stellar_base/operations/
manage_buy_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 ManageBuyOfferOperation {
11 source_account: Option<MuxedAccount>,
12 selling: Asset,
13 buying: Asset,
14 buy_amount: Stroops,
15 price: Price,
16 offer_id: Option<i64>,
17}
18
19#[derive(Debug, Default)]
20pub struct ManageBuyOfferOperationBuilder {
21 source_account: Option<MuxedAccount>,
22 selling: Option<Asset>,
23 buying: Option<Asset>,
24 buy_amount: Option<Stroops>,
25 price: Option<Price>,
26 offer_id: Option<i64>,
27}
28
29impl ManageBuyOfferOperation {
30 pub fn source_account(&self) -> &Option<MuxedAccount> {
32 &self.source_account
33 }
34
35 pub fn source_account_mut(&mut self) -> &mut Option<MuxedAccount> {
37 &mut self.source_account
38 }
39
40 pub fn selling(&self) -> &Asset {
42 &self.selling
43 }
44
45 pub fn selling_mut(&mut self) -> &mut Asset {
47 &mut self.selling
48 }
49
50 pub fn buying(&self) -> &Asset {
52 &self.buying
53 }
54
55 pub fn buying_mut(&mut self) -> &mut Asset {
57 &mut self.buying
58 }
59
60 pub fn buy_amount(&self) -> &Stroops {
62 &self.buy_amount
63 }
64
65 pub fn buy_amount_mut(&mut self) -> &mut Stroops {
67 &mut self.buy_amount
68 }
69
70 pub fn price(&self) -> &Price {
72 &self.price
73 }
74
75 pub fn price_mut(&mut self) -> &mut Price {
77 &mut self.price
78 }
79
80 pub fn offer_id(&self) -> &Option<i64> {
82 &self.offer_id
83 }
84
85 pub fn offer_id_mut(&mut self) -> &mut Option<i64> {
87 &mut self.offer_id
88 }
89
90 pub fn to_xdr_operation_body(&self) -> Result<xdr::OperationBody> {
92 let selling = self.selling.to_xdr()?;
93 let buying = self.buying.to_xdr()?;
94 let buy_amount = self.buy_amount.to_xdr_int64()?;
95 let price = self.price.to_xdr()?;
96 let offer_id = match &self.offer_id {
97 None => 0,
98 Some(id) => *id,
99 };
100 let inner = xdr::ManageBuyOfferOp {
101 selling,
102 buying,
103 buy_amount,
104 price,
105 offer_id,
106 };
107 Ok(xdr::OperationBody::ManageBuyOffer(inner))
108 }
109
110 pub fn from_xdr_operation_body(
112 source_account: Option<MuxedAccount>,
113 x: &xdr::ManageBuyOfferOp,
114 ) -> Result<ManageBuyOfferOperation> {
115 let selling = Asset::from_xdr(&x.selling)?;
116 let buying = Asset::from_xdr(&x.buying)?;
117 let buy_amount = Stroops::from_xdr_int64(x.buy_amount)?;
118 let price = Price::from_xdr(&x.price)?;
119 let offer_id = match &x.offer_id {
122 0 => None,
123 n => Some(*n),
124 };
125 Ok(ManageBuyOfferOperation {
126 source_account,
127 selling,
128 buying,
129 buy_amount,
130 price,
131 offer_id,
132 })
133 }
134}
135
136impl ManageBuyOfferOperationBuilder {
137 pub fn new() -> ManageBuyOfferOperationBuilder {
138 Default::default()
139 }
140
141 pub fn with_source_account<S>(mut self, source: S) -> ManageBuyOfferOperationBuilder
142 where
143 S: Into<MuxedAccount>,
144 {
145 self.source_account = Some(source.into());
146 self
147 }
148
149 pub fn with_selling_asset(mut self, asset: Asset) -> ManageBuyOfferOperationBuilder {
150 self.selling = Some(asset);
151 self
152 }
153
154 pub fn with_buying_asset(mut self, asset: Asset) -> ManageBuyOfferOperationBuilder {
155 self.buying = Some(asset);
156 self
157 }
158
159 pub fn with_buy_amount<A>(mut self, amount: A) -> Result<ManageBuyOfferOperationBuilder>
160 where
161 A: TryInto<Stroops, Error = Error>,
162 {
163 self.buy_amount = Some(amount.try_into()?);
164 Ok(self)
165 }
166
167 pub fn with_price(mut self, price: Price) -> ManageBuyOfferOperationBuilder {
168 self.price = Some(price);
169 self
170 }
171
172 pub fn with_offer_id(mut self, offer_id: Option<i64>) -> ManageBuyOfferOperationBuilder {
173 self.offer_id = offer_id;
174 self
175 }
176
177 pub fn build(self) -> Result<Operation> {
178 let selling = self.selling.ok_or_else(|| {
179 Error::InvalidOperation("missing manage buy offer selling asset".to_string())
180 })?;
181
182 let buying = self.buying.ok_or_else(|| {
183 Error::InvalidOperation("missing manage buy offer buying asset".to_string())
184 })?;
185
186 let buy_amount = self.buy_amount.ok_or_else(|| {
187 Error::InvalidOperation("missing manage buy offer amount".to_string())
188 })?;
189
190 let price = self
191 .price
192 .ok_or_else(|| Error::InvalidOperation("missing manage buy offer price".to_string()))?;
193
194 if let Some(offer_id) = self.offer_id {
195 if offer_id <= 0 {
196 return Err(Error::InvalidOperation(
197 "manage buy offer offer_id must be positive".to_string(),
198 ));
199 }
200 }
201
202 Ok(Operation::ManageBuyOffer(ManageBuyOfferOperation {
203 source_account: self.source_account,
204 selling,
205 buying,
206 buy_amount,
207 price,
208 offer_id: self.offer_id,
209 }))
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use crate::amount::{Amount, Price};
216 use crate::asset::Asset;
217
218 use crate::network::Network;
219 use crate::operations::tests::*;
220 use crate::operations::Operation;
221 use crate::transaction::{Transaction, TransactionEnvelope, MIN_BASE_FEE};
222 use crate::xdr::{XDRDeserialize, XDRSerialize};
223 use std::str::FromStr;
224
225 #[test]
226 fn test_manage_buy_offer() {
227 let kp = keypair0();
228 let kp1 = keypair1();
229
230 let amount = Amount::from_str("100.0").unwrap();
231 let buying = Asset::new_credit("ABCDEFGH", kp1.public_key()).unwrap();
232 let price = Price::from_str("12.35").unwrap();
233
234 let op = Operation::new_manage_buy_offer()
235 .with_selling_asset(Asset::new_native())
236 .with_buying_asset(buying)
237 .with_buy_amount(amount)
238 .unwrap()
239 .with_price(price)
240 .build()
241 .unwrap();
242 let mut tx = Transaction::builder(kp.public_key(), 3556091187167235, MIN_BASE_FEE)
243 .add_operation(op)
244 .into_transaction()
245 .unwrap();
246 tx.sign(kp.as_ref(), &Network::new_test()).unwrap();
247 let envelope = tx.to_envelope();
248 let xdr = envelope.xdr_base64().unwrap();
249 let expected = "AAAAAgAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAGQADKI/AAAAAwAAAAAAAAAAAAAAAQAAAAAAAAAMAAAAAAAAAAJBQkNERUZHSAAAAAAAAAAAJcrx2g/Hbs/ohF5CVFG7B5JJSJR+OqDKzDGK7dKHZH4AAAAAO5rKAAAAAPcAAAAUAAAAAAAAAAAAAAAAAAAAAeoucsUAAABAwJNdoP6KJlGw9S5BglgiBsWQPPKuPZQVqsFr0b9x3xSXUn+HOagzv210kzga37vSEFGIQ3GyoAgWLbxbYVcKDg==";
250 assert_eq!(expected, xdr);
251 let back = TransactionEnvelope::from_xdr_base64(&xdr).unwrap();
252 assert_eq!(envelope, back);
253 }
254
255 #[test]
256 fn test_manage_buy_offer_with_offer_id() {
257 let kp = keypair0();
258 let kp1 = keypair1();
259
260 let amount = Amount::from_str("100.0").unwrap();
261 let buying = Asset::new_credit("AB", kp1.public_key()).unwrap();
262 let price = Price::from_str("12.35").unwrap();
263
264 let op = Operation::new_manage_buy_offer()
265 .with_selling_asset(Asset::new_native())
266 .with_buying_asset(buying)
267 .with_buy_amount(amount)
268 .unwrap()
269 .with_price(price)
270 .with_offer_id(Some(888))
271 .build()
272 .unwrap();
273 let mut tx = Transaction::builder(kp.public_key(), 3556091187167235, MIN_BASE_FEE)
274 .add_operation(op)
275 .into_transaction()
276 .unwrap();
277 tx.sign(kp.as_ref(), &Network::new_test()).unwrap();
278 let envelope = tx.to_envelope();
279 let xdr = envelope.xdr_base64().unwrap();
280 let expected = "AAAAAgAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAGQADKI/AAAAAwAAAAAAAAAAAAAAAQAAAAAAAAAMAAAAAAAAAAFBQgAAAAAAACXK8doPx27P6IReQlRRuweSSUiUfjqgyswxiu3Sh2R+AAAAADuaygAAAAD3AAAAFAAAAAAAAAN4AAAAAAAAAAHqLnLFAAAAQJiREkdqaD2QzbsQWcuaUdr5mhJmbatEzAEqChBjtlUQ44C7nFbashDHyTN/Q6YkYOGr2xwL7yWIK9SCJKfeSQU=";
281 assert_eq!(expected, xdr);
282 let back = TransactionEnvelope::from_xdr_base64(&xdr).unwrap();
283 assert_eq!(envelope, back);
284 }
285
286 #[test]
287 fn test_manage_buy_offer_with_source_account() {
288 let kp = keypair0();
289 let kp1 = keypair1();
290 let kp2 = keypair2();
291
292 let amount = Amount::from_str("100.0").unwrap();
293 let buying = Asset::new_credit("AB", kp1.public_key()).unwrap();
294 let price = Price::from_str("12.35").unwrap();
295
296 let op = Operation::new_manage_buy_offer()
297 .with_source_account(kp2.public_key())
298 .with_selling_asset(Asset::new_native())
299 .with_buying_asset(buying)
300 .with_buy_amount(amount)
301 .unwrap()
302 .with_price(price)
303 .build()
304 .unwrap();
305 let mut tx = Transaction::builder(kp.public_key(), 3556091187167235, MIN_BASE_FEE)
306 .add_operation(op)
307 .into_transaction()
308 .unwrap();
309 tx.sign(kp.as_ref(), &Network::new_test()).unwrap();
310 let envelope = tx.to_envelope();
311 let xdr = envelope.xdr_base64().unwrap();
312 let expected = "AAAAAgAAAADg3G3hclysZlFitS+s5zWyiiJD5B0STWy5LXCj6i5yxQAAAGQADKI/AAAAAwAAAAAAAAAAAAAAAQAAAAEAAAAAfhHLNNY19eGrAtSgLD3VpaRm2AjNjxIBWQg9zS4VWZgAAAAMAAAAAAAAAAFBQgAAAAAAACXK8doPx27P6IReQlRRuweSSUiUfjqgyswxiu3Sh2R+AAAAADuaygAAAAD3AAAAFAAAAAAAAAAAAAAAAAAAAAHqLnLFAAAAQLZdtLQcZZgoBIbkkHsnZ0Afhm5M+szpVmwulAYpde9aZx8FpN8ZRRHxW0qoLgr9Y1K7W/8jOyuEItqMd+PDewA=";
313 assert_eq!(expected, xdr);
314 let back = TransactionEnvelope::from_xdr_base64(&xdr).unwrap();
315 assert_eq!(envelope, back);
316 }
317}