stellar_base/operations/
create_passive_sell_offer.rs1use 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 pub fn source_account(&self) -> &Option<MuxedAccount> {
30 &self.source_account
31 }
32
33 pub fn source_account_mut(&mut self) -> &mut Option<MuxedAccount> {
35 &mut self.source_account
36 }
37
38 pub fn selling(&self) -> &Asset {
40 &self.selling
41 }
42
43 pub fn selling_mut(&mut self) -> &mut Asset {
45 &mut self.selling
46 }
47
48 pub fn buying(&self) -> &Asset {
50 &self.buying
51 }
52
53 pub fn buying_mut(&mut self) -> &mut Asset {
55 &mut self.buying
56 }
57
58 pub fn amount(&self) -> &Stroops {
60 &self.amount
61 }
62
63 pub fn amount_mut(&mut self) -> &mut Stroops {
65 &mut self.amount
66 }
67
68 pub fn price(&self) -> &Price {
70 &self.price
71 }
72
73 pub fn price_(&mut self) -> &mut Price {
75 &mut self.price
76 }
77
78 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 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}