stellar_base/
claim.rs

1//! Represent an account claim.
2use std::io::{Read, Write};
3
4use crate::crypto::PublicKey;
5use crate::error::{Error, Result};
6use crate::xdr;
7use chrono::{DateTime, Duration, TimeZone, Utc};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct ClaimableBalanceId(Vec<u8>);
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct Claimant {
14    destination: PublicKey,
15    predicate: ClaimPredicate,
16}
17
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub enum ClaimPredicate {
20    Unconditional,
21    And(Box<ClaimPredicate>, Box<ClaimPredicate>),
22    Or(Box<ClaimPredicate>, Box<ClaimPredicate>),
23    Not(Box<ClaimPredicate>),
24    BeforeAbsoluteTime(DateTime<Utc>),
25    BeforeRelativeTime(Duration),
26}
27
28impl ClaimableBalanceId {
29    /// Returns a new claimable balance id, or Error if the hash length is not 32 bytes.
30    pub fn new(hash: Vec<u8>) -> Result<ClaimableBalanceId> {
31        if hash.len() != 32 {
32            Err(Error::InvalidClaimableBalanceIdLength)
33        } else {
34            Ok(ClaimableBalanceId(hash))
35        }
36    }
37
38    /// Retrieves the claimable balance id bytes.
39    pub fn as_bytes(&self) -> &[u8] {
40        &self.0
41    }
42
43    /// Returns the xdr object.
44    pub fn to_xdr(&self) -> xdr::ClaimableBalanceId {
45        let hash = xdr::Hash(self.0.as_slice().try_into().unwrap());
46        xdr::ClaimableBalanceId::ClaimableBalanceIdTypeV0(hash)
47    }
48
49    /// Creates from the xdr object.
50    pub fn from_xdr(x: &xdr::ClaimableBalanceId) -> Result<ClaimableBalanceId> {
51        match x {
52            xdr::ClaimableBalanceId::ClaimableBalanceIdTypeV0(hash) => {
53                ClaimableBalanceId::new(hash.0.to_vec())
54            }
55        }
56    }
57}
58
59impl Claimant {
60    /// Returns a new claimant with the given `destination` and `predicate`.
61    pub fn new(destination: PublicKey, predicate: ClaimPredicate) -> Claimant {
62        Claimant {
63            destination,
64            predicate,
65        }
66    }
67
68    /// Returns the xdr object.
69    pub fn to_xdr(&self) -> Result<xdr::Claimant> {
70        let destination = self.destination.to_xdr_account_id()?;
71        let predicate = self.predicate.to_xdr()?;
72        let inner = xdr::ClaimantV0 {
73            destination,
74            predicate,
75        };
76        Ok(xdr::Claimant::ClaimantTypeV0(inner))
77    }
78
79    /// Creates from the xdr object.
80    pub fn from_xdr(x: &xdr::Claimant) -> Result<Claimant> {
81        match x {
82            xdr::Claimant::ClaimantTypeV0(inner) => {
83                let destination = PublicKey::from_xdr_account_id(&inner.destination)?;
84                let predicate = ClaimPredicate::from_xdr(&inner.predicate)?;
85                Ok(Claimant::new(destination, predicate))
86            }
87        }
88    }
89}
90
91impl ClaimPredicate {
92    /// Returns an unconditional predicate.
93    pub fn new_unconditional() -> ClaimPredicate {
94        ClaimPredicate::Unconditional
95    }
96
97    /// Returns a predicate that is true if `p1` and `p2` are both true.
98    pub fn new_and(p1: ClaimPredicate, p2: ClaimPredicate) -> ClaimPredicate {
99        ClaimPredicate::And(Box::new(p1), Box::new(p2))
100    }
101
102    /// Returns a predicate that is true if at least one of `p1` or `p2` is true.
103    pub fn new_or(p1: ClaimPredicate, p2: ClaimPredicate) -> ClaimPredicate {
104        ClaimPredicate::Or(Box::new(p1), Box::new(p2))
105    }
106
107    /// Returns a predicate that is true if `predicate` is false.
108    pub fn new_not(predicate: ClaimPredicate) -> ClaimPredicate {
109        ClaimPredicate::Not(Box::new(predicate))
110    }
111
112    /// Returns a predicate that is true the ledger close time is before `datetime`.
113    pub fn new_before_absolute_time(datetime: DateTime<Utc>) -> ClaimPredicate {
114        ClaimPredicate::BeforeAbsoluteTime(datetime)
115    }
116
117    /// Returns a predicate that is true the ledger close time is
118    /// within `duration` of the current ledger close time.
119    pub fn new_before_relative_time(duration: Duration) -> ClaimPredicate {
120        ClaimPredicate::BeforeRelativeTime(duration)
121    }
122
123    /// Returns the xdr object.
124    pub fn to_xdr(&self) -> Result<xdr::ClaimPredicate> {
125        match self {
126            ClaimPredicate::Unconditional => Ok(xdr::ClaimPredicate::Unconditional),
127            ClaimPredicate::And(p1, p2) => {
128                let p1_xdr = p1.to_xdr()?;
129                let p2_xdr = p2.to_xdr()?;
130                let predicates = vec![p1_xdr, p2_xdr];
131                Ok(xdr::ClaimPredicate::And(predicates.try_into().unwrap()))
132            }
133            ClaimPredicate::Or(p1, p2) => {
134                let p1_xdr = p1.to_xdr()?;
135                let p2_xdr = p2.to_xdr()?;
136                let predicates = vec![p1_xdr, p2_xdr];
137                Ok(xdr::ClaimPredicate::Or(predicates.try_into().unwrap()))
138            }
139            ClaimPredicate::Not(p) => {
140                let p_xdr = p.to_xdr()?;
141                let predicate = Some(Box::new(p_xdr));
142                Ok(xdr::ClaimPredicate::Not(predicate))
143            }
144            ClaimPredicate::BeforeAbsoluteTime(datetime) => {
145                let time = datetime.timestamp();
146                Ok(xdr::ClaimPredicate::BeforeAbsoluteTime(time))
147            }
148            ClaimPredicate::BeforeRelativeTime(duration) => {
149                let time = duration.num_seconds();
150                Ok(xdr::ClaimPredicate::BeforeRelativeTime(time))
151            }
152        }
153    }
154
155    /// Creates from the xdr object.
156    pub fn from_xdr(x: &xdr::ClaimPredicate) -> Result<ClaimPredicate> {
157        // The challenge here is that the XDR definition allows and/or/not
158        // predicates to have the wrong number of arguments (because xdrc
159        // does not support recursive data structures).
160        // We perform a check and return an error if the XDR is valid
161        // but the claim predicate is not.
162        match x {
163            xdr::ClaimPredicate::Unconditional => Ok(ClaimPredicate::new_unconditional()),
164            xdr::ClaimPredicate::And(predicates) => {
165                let mut p = predicates.iter();
166                match (p.next(), p.next()) {
167                    (Some(p1), Some(p2)) => {
168                        let p1 = ClaimPredicate::from_xdr(p1)?;
169                        let p2 = ClaimPredicate::from_xdr(p2)?;
170                        Ok(ClaimPredicate::new_and(p1, p2))
171                    }
172                    _ => Err(Error::XdrClaimPredicateError),
173                }
174            }
175            xdr::ClaimPredicate::Or(predicates) => {
176                let mut p = predicates.iter();
177                match (p.next(), p.next()) {
178                    (Some(p1), Some(p2)) => {
179                        let p1 = ClaimPredicate::from_xdr(p1)?;
180                        let p2 = ClaimPredicate::from_xdr(p2)?;
181                        Ok(ClaimPredicate::new_or(p1, p2))
182                    }
183                    _ => Err(Error::XdrClaimPredicateError),
184                }
185            }
186            xdr::ClaimPredicate::Not(predicate) => {
187                if let Some(predicate) = predicate {
188                    let p = ClaimPredicate::from_xdr(predicate)?;
189                    Ok(ClaimPredicate::new_not(p))
190                } else {
191                    Err(Error::XdrClaimPredicateError)
192                }
193            }
194            xdr::ClaimPredicate::BeforeAbsoluteTime(time) => {
195                let datetime = Utc.timestamp_opt(*time, 0).single();
196                datetime
197                    .map(ClaimPredicate::new_before_absolute_time)
198                    .ok_or(Error::XdrClaimPredicateError)
199            }
200            xdr::ClaimPredicate::BeforeRelativeTime(time) => {
201                let duration = Duration::seconds(*time);
202                Ok(ClaimPredicate::new_before_relative_time(duration))
203            }
204        }
205    }
206}
207
208impl xdr::WriteXdr for Claimant {
209    fn write_xdr<W: Write>(&self, w: &mut xdr::Limited<W>) -> xdr::Result<()> {
210        let xdr = self.to_xdr().map_err(|_| xdr::Error::Invalid)?;
211        xdr.write_xdr(w)
212    }
213}
214
215impl xdr::ReadXdr for Claimant {
216    fn read_xdr<R: Read>(r: &mut xdr::Limited<R>) -> xdr::Result<Self> {
217        let xdr_result = xdr::Claimant::read_xdr(r)?;
218        Self::from_xdr(&xdr_result).map_err(|_| xdr::Error::Invalid)
219    }
220}
221
222impl xdr::WriteXdr for ClaimPredicate {
223    fn write_xdr<W: Write>(&self, w: &mut xdr::Limited<W>) -> xdr::Result<()> {
224        let xdr = self.to_xdr().map_err(|_| xdr::Error::Invalid)?;
225        xdr.write_xdr(w)
226    }
227}
228
229impl xdr::ReadXdr for ClaimPredicate {
230    fn read_xdr<R: Read>(r: &mut xdr::Limited<R>) -> xdr::Result<Self> {
231        let xdr_result = xdr::ClaimPredicate::read_xdr(r)?;
232        Self::from_xdr(&xdr_result).map_err(|_| xdr::Error::Invalid)
233    }
234}