stellar_base/operations/
create_passive_sell_offer.rs

1use crate::amount::{Price, Stroops};
2use crate::asset::Asset;
3use crate::crypto::MuxedAccount;
4use crate::error::{Error, Result};
5use crate::operations::Operation;
6use crate::xdr;
7use std::convert::TryInto;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct CreatePassiveSellOfferOperation {
11    source_account: Option<MuxedAccount>,
12    selling: Asset,
13    buying: Asset,
14    amount: Stroops,
15    price: Price,
16}
17
18#[derive(Debug, Default)]
19pub struct CreatePassiveSellOfferOperationBuilder {
20    source_account: Option<MuxedAccount>,
21    selling: Option<Asset>,
22    buying: Option<Asset>,
23    amount: Option<Stroops>,
24    price: Option<Price>,
25}
26
27impl CreatePassiveSellOfferOperation {
28    /// Retrieves the operation source account.
29    pub fn source_account(&self) -> &Option<MuxedAccount> {
30        &self.source_account
31    }
32
33    /// Retrieves a reference to the operation source account.
34    pub fn source_account_mut(&mut self) -> &mut Option<MuxedAccount> {
35        &mut self.source_account
36    }
37
38    /// Retrieves the operation seling asset.
39    pub fn selling(&self) -> &Asset {
40        &self.selling
41    }
42
43    /// Retrieves a mutable reference to the operation seling asset.
44    pub fn selling_mut(&mut self) -> &mut Asset {
45        &mut self.selling
46    }
47
48    /// Retrieves the operation buying asset.
49    pub fn buying(&self) -> &Asset {
50        &self.buying
51    }
52
53    /// Retrieves a mutable reference to the operation buying asset.
54    pub fn buying_mut(&mut self) -> &mut Asset {
55        &mut self.buying
56    }
57
58    /// Retrieves the operation amout.
59    pub fn amount(&self) -> &Stroops {
60        &self.amount
61    }
62
63    /// Retrieves a mutable reference to the operation amout.
64    pub fn amount_mut(&mut self) -> &mut Stroops {
65        &mut self.amount
66    }
67
68    /// Retrieves the operation price.
69    pub fn price(&self) -> &Price {
70        &self.price
71    }
72
73    /// Retrieves a mutable reference to the operation price.
74    pub fn price_(&mut self) -> &mut Price {
75        &mut self.price
76    }
77
78    /// Returns the xdr operation body.
79    pub fn to_xdr_operation_body(&self) -> Result<xdr::OperationBody> {
80        let selling = self.selling.to_xdr()?;
81        let buying = self.buying.to_xdr()?;
82        let amount = self.amount.to_xdr_int64()?;
83        let price = self.price.to_xdr()?;
84        let inner = xdr::CreatePassiveSellOfferOp {
85            selling,
86            buying,
87            amount,
88            price,
89        };
90        Ok(xdr::OperationBody::CreatePassiveSellOffer(inner))
91    }
92
93    /// Creates from the xdr operation body.
94    pub fn from_xdr_operation_body(
95        source_account: Option<MuxedAccount>,
96        x: &xdr::CreatePassiveSellOfferOp,
97    ) -> Result<CreatePassiveSellOfferOperation> {
98        let selling = Asset::from_xdr(&x.selling)?;
99        let buying = Asset::from_xdr(&x.buying)?;
100        let amount = Stroops::from_xdr_int64(x.amount)?;
101        let price = Price::from_xdr(&x.price)?;
102        Ok(CreatePassiveSellOfferOperation {
103            source_account,
104            selling,
105            buying,
106            amount,
107            price,
108        })
109    }
110}
111
112impl CreatePassiveSellOfferOperationBuilder {
113    pub fn new() -> CreatePassiveSellOfferOperationBuilder {
114        Default::default()
115    }
116
117    pub fn with_source_account<S>(mut self, source: S) -> CreatePassiveSellOfferOperationBuilder
118    where
119        S: Into<MuxedAccount>,
120    {
121        self.source_account = Some(source.into());
122        self
123    }
124
125    pub fn with_selling_asset(mut self, asset: Asset) -> CreatePassiveSellOfferOperationBuilder {
126        self.selling = Some(asset);
127        self
128    }
129
130    pub fn with_buying_asset(mut self, asset: Asset) -> CreatePassiveSellOfferOperationBuilder {
131        self.buying = Some(asset);
132        self
133    }
134
135    pub fn with_amount<A>(mut self, amount: A) -> Result<CreatePassiveSellOfferOperationBuilder>
136    where
137        A: TryInto<Stroops>,
138    {
139        self.amount = Some(amount.try_into().map_err(|_| Error::InvalidStroopsAmount)?);
140        Ok(self)
141    }
142
143    pub fn with_price(mut self, price: Price) -> CreatePassiveSellOfferOperationBuilder {
144        self.price = Some(price);
145        self
146    }
147
148    pub fn build(self) -> Result<Operation> {
149        let selling = self.selling.ok_or_else(|| {
150            Error::InvalidOperation("missing create passive sell offer selling asset".to_string())
151        })?;
152
153        let buying = self.buying.ok_or_else(|| {
154            Error::InvalidOperation("missing create passive sell offer buying asset".to_string())
155        })?;
156
157        let amount = self.amount.ok_or_else(|| {
158            Error::InvalidOperation("missing create passive sell offer amount".to_string())
159        })?;
160
161        let price = self.price.ok_or_else(|| {
162            Error::InvalidOperation("missing create passive sell offer price".to_string())
163        })?;
164
165        Ok(Operation::CreatePassiveSellOffer(
166            CreatePassiveSellOfferOperation {
167                source_account: self.source_account,
168                selling,
169                buying,
170                amount,
171                price,
172            },
173        ))
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use crate::amount::{Amount, Price};
180    use crate::asset::Asset;
181
182    use crate::network::Network;
183    use crate::operations::tests::*;
184    use crate::operations::Operation;
185    use crate::transaction::{Transaction, TransactionEnvelope, MIN_BASE_FEE};
186    use crate::xdr::{XDRDeserialize, XDRSerialize};
187    use std::str::FromStr;
188
189    #[test]
190    fn test_create_passive_sell_offer() {
191        let kp = keypair0();
192        let kp1 = keypair1();
193
194        let amount = Amount::from_str("100.0").unwrap();
195        let buying = Asset::new_credit("AB", kp1.public_key()).unwrap();
196        let price = Price::from_str("12.35").unwrap();
197
198        let op = Operation::new_create_passive_sell_offer()
199            .with_selling_asset(Asset::new_native())
200            .with_buying_asset(buying)
201            .with_amount(amount)
202            .unwrap()
203            .with_price(price)
204            .build()
205            .unwrap();
206        let mut tx = Transaction::builder(kp.public_key(), 3556091187167235, MIN_BASE_FEE)
207            .add_operation(op)
208            .into_transaction()
209            .unwrap();
210        tx.sign(kp.as_ref(), &Network::new_test()).unwrap();
211        let envelope = tx.to_envelope();
212        let xdr = envelope.xdr_base64().unwrap();
213        let expected = "AAAAAgAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAGQADKI/AAAAAwAAAAAAAAAAAAAAAQAAAAAAAAAEAAAAAAAAAAFBQgAAAAAAACXK8doPx27P6IReQlRRuweSSUiUfjqgyswxiu3Sh2R+AAAAADuaygAAAAD3AAAAFAAAAAAAAAAB6i5yxQAAAECG2/IOsqY2pTugmUnhX9Iafmy5JuCQjPxlA0kxdYHe2EKIbZVClMbgckEwvjJq+B0G2SzRUqiK1sfAOIZpAB4D";
214        assert_eq!(expected, xdr);
215        let back = TransactionEnvelope::from_xdr_base64(&xdr).unwrap();
216        assert_eq!(envelope, back);
217    }
218
219    #[test]
220    fn test_create_passive_sell_offer_with_source_account() {
221        let kp = keypair0();
222        let kp1 = keypair1();
223        let kp2 = keypair2();
224
225        let amount = Amount::from_str("100.0").unwrap();
226        let buying = Asset::new_credit("AB", kp1.public_key()).unwrap();
227        let price = Price::from_str("12.35").unwrap();
228
229        let op = Operation::new_create_passive_sell_offer()
230            .with_source_account(kp2.public_key())
231            .with_selling_asset(Asset::new_native())
232            .with_buying_asset(buying)
233            .with_amount(amount)
234            .unwrap()
235            .with_price(price)
236            .build()
237            .unwrap();
238        let mut tx = Transaction::builder(kp.public_key(), 3556091187167235, MIN_BASE_FEE)
239            .add_operation(op)
240            .into_transaction()
241            .unwrap();
242        tx.sign(kp.as_ref(), &Network::new_test()).unwrap();
243        let envelope = tx.to_envelope();
244        let xdr = envelope.xdr_base64().unwrap();
245        let expected = "AAAAAgAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAGQADKI/AAAAAwAAAAAAAAAAAAAAAQAAAAEAAAAAfhHLNNY19eGrAtSgLD3VpaRm2AjNjxIBWQg9zS4VWZgAAAAEAAAAAAAAAAFBQgAAAAAAACXK8doPx27P6IReQlRRuweSSUiUfjqgyswxiu3Sh2R+AAAAADuaygAAAAD3AAAAFAAAAAAAAAAB6i5yxQAAAECffRDt4ilFKVEfldEY/Ys2VJm4g7iu6eiqJvPGqDGALTPnEMncqaMGoFbtNgMvZWv3rXi65351/VQv1o8MrtML";
246        assert_eq!(expected, xdr);
247        let back = TransactionEnvelope::from_xdr_base64(&xdr).unwrap();
248        assert_eq!(envelope, back);
249    }
250}