1pub mod v3;
2pub mod v4;
3
4use crate::error::Error::UnsupportedOperation;
5use crate::error::{Error, Result};
6use crate::model::{Address, Amount, AssetId, ByteString, Id, Proof, PublicKey};
7use crate::util::{Base58, BinarySerializer, Hash, JsonDeserializer, JsonSerializer};
8use crate::waves_proto::order::Sender::SenderPublicKey;
9use crate::waves_proto::{Amount as ProtoAmount, AssetPair, Order as ProtoOrder};
10use serde_json::{Map, Value};
11
12use self::v3::{OrderInfoV3, OrderV3};
13use self::v4::{OrderInfoV4, OrderV4};
14
15use super::PrivateKey;
16
17#[derive(Eq, PartialEq, Clone, Debug)]
18pub enum OrderInfo {
19 V3(v3::OrderInfoV3),
20 V4(v4::OrderInfoV4),
21}
22
23impl OrderInfo {
25 pub fn id(&self) -> Id {
26 match self {
27 Self::V3(order) => order.id(),
28 Self::V4(order) => order.id(),
29 }
30 }
31
32 pub fn chain_id(&self) -> u8 {
33 match self {
34 Self::V3(order) => order.chain_id(),
35 Self::V4(order) => order.chain_id(),
36 }
37 }
38
39 pub fn order_type(&self) -> OrderType {
40 match self {
41 Self::V3(order) => order.order_type(),
42 Self::V4(order) => order.order_type(),
43 }
44 }
45
46 pub fn version(&self) -> u8 {
47 match self {
48 Self::V3(order) => order.version(),
49 Self::V4(order) => order.version(),
50 }
51 }
52
53 pub fn sender(&self) -> PublicKey {
54 match self {
55 Self::V3(order) => order.sender(),
56 Self::V4(order) => order.sender(),
57 }
58 }
59
60 pub fn amount(&self) -> Amount {
61 match self {
62 Self::V3(order) => order.amount(),
63 Self::V4(order) => order.amount(),
64 }
65 }
66
67 pub fn price(&self) -> Amount {
68 match self {
69 Self::V3(order) => order.price(),
70 Self::V4(order) => order.price(),
71 }
72 }
73
74 pub fn fee(&self) -> Amount {
75 match self {
76 Self::V3(order) => order.fee(),
77 Self::V4(order) => order.fee(),
78 }
79 }
80
81 pub fn matcher(&self) -> PublicKey {
82 match self {
83 Self::V3(order) => order.matcher(),
84 Self::V4(order) => order.matcher(),
85 }
86 }
87
88 pub fn timestamp(&self) -> u64 {
89 match self {
90 Self::V3(order) => order.timestamp(),
91 Self::V4(order) => order.timestamp(),
92 }
93 }
94
95 pub fn expiration(&self) -> u64 {
96 match self {
97 Self::V3(order) => order.expiration(),
98 Self::V4(order) => order.expiration(),
99 }
100 }
101
102 pub fn price_mode(&self) -> PriceMode {
103 match self {
104 Self::V3(_) => PriceMode::AssetDecimals,
105 Self::V4(order) => order.price_mode(),
106 }
107 }
108
109 pub fn proofs(&self) -> Vec<Proof> {
110 match self {
111 Self::V3(order) => order.proofs(),
112 Self::V4(order) => order.proofs(),
113 }
114 }
115}
116
117impl TryFrom<&Value> for OrderInfo {
118 type Error = Error;
119
120 fn try_from(order_json: &Value) -> Result<Self> {
121 let signed_order: SignedOrder = order_json.try_into()?;
122 signed_order.try_into()
123 }
124}
125
126#[derive(Eq, PartialEq, Clone, Debug)]
127pub struct SignedOrder {
128 order: Order,
129 proofs: Vec<Proof>,
130}
131
132impl SignedOrder {
133 pub fn new(order: Order, proofs: Vec<Proof>) -> SignedOrder {
134 SignedOrder { order, proofs }
135 }
136
137 pub fn order(&self) -> Order {
138 self.order.clone()
139 }
140
141 pub fn proofs(&self) -> Vec<Proof> {
142 self.proofs.clone()
143 }
144
145 pub fn id(&self) -> Result<Id> {
146 Ok(Id::from_bytes(&Hash::blake(&self.bytes()?)?))
147 }
148
149 pub fn bytes(&self) -> Result<Vec<u8>> {
150 BinarySerializer::order_body_bytes(&self.order())
151 }
152
153 pub fn to_json(&self) -> Result<Value> {
154 JsonSerializer::serialize_signed_order(self)
155 }
156}
157
158impl TryFrom<&Value> for SignedOrder {
159 type Error = Error;
160
161 fn try_from(signed_order_json: &Value) -> Result<Self> {
162 let order: Order = signed_order_json.try_into()?;
163
164 let signature = Proof::new(Base58::decode(
165 &JsonDeserializer::safe_to_string_from_field(signed_order_json, "signature")?,
166 )?);
167
168 Ok(SignedOrder::new(order, vec![signature]))
169 }
170}
171
172impl TryFrom<&SignedOrder> for Value {
173 type Error = Error;
174
175 fn try_from(signed_order: &SignedOrder) -> Result<Self> {
176 let order = signed_order.order();
177 let order_type = match order.order_type() {
178 OrderType::Buy => "buy",
179 OrderType::Sell => "sell",
180 };
181 let mut order_json = Map::new();
182 order_json.insert("orderType".to_owned(), order_type.into());
183 order_json.insert("version".to_owned(), order.version().into());
184 order_json.insert(
185 "senderPublicKey".to_owned(),
186 order.sender().encoded().into(),
187 );
188 order_json.insert(
189 "sender".to_owned(),
190 order.sender().address(order.chain_id())?.encoded().into(),
191 );
192 let mut asset_pair_json = Map::new();
193 asset_pair_json.insert(
194 "amountAsset".to_owned(),
195 order
196 .amount()
197 .asset_id()
198 .map(|asset| asset.encoded().into())
199 .unwrap_or(Value::Null),
200 );
201 asset_pair_json.insert(
202 "priceAsset".to_owned(),
203 order
204 .price()
205 .asset_id()
206 .map(|asset| asset.encoded().into())
207 .unwrap_or(Value::Null),
208 );
209
210 order_json.insert("assetPair".to_owned(), asset_pair_json.into());
211 order_json.insert("amount".to_owned(), order.amount().value().into());
212 order_json.insert("price".to_owned(), order.price().value().into());
213 order_json.insert("matcherFee".to_owned(), order.fee().value().into());
214 order_json.insert(
215 "matcherPublicKey".to_owned(),
216 order.matcher().encoded().into(),
217 );
218 order_json.insert(
219 "matcherFeeAssetId".to_owned(),
220 order
221 .fee()
222 .asset_id()
223 .map(|asset| asset.encoded().into())
224 .unwrap_or(Value::Null),
225 );
226 order_json.insert("timestamp".to_owned(), order.timestamp().into());
227 order_json.insert("expiration".to_owned(), order.expiration().into());
228 let signature = signed_order.proofs[0].encoded();
229 order_json.insert("signature".to_owned(), signature.clone().into());
230 order_json.insert("proofs".to_owned(), vec![Value::String(signature)].into());
231
232 match order {
233 Order::V3(_) => {}
234 Order::V4(order_v4) => {
235 let price_mode = match order_v4.price_mode() {
236 PriceMode::Default => "default",
237 PriceMode::FixedDecimals => "fixedDecimals",
238 PriceMode::AssetDecimals => "assetDecimals",
239 };
240 order_json.insert("priceMode".to_owned(), price_mode.into());
241 }
242 }
243
244 Ok(order_json.into())
245 }
246}
247
248impl TryFrom<&SignedOrder> for ProtoOrder {
249 type Error = Error;
250
251 fn try_from(signed_order: &SignedOrder) -> Result<Self> {
252 let order = signed_order.order();
253
254 match order {
255 Order::V3(_) => Err(UnsupportedOperation(
256 "Order version 3 can't be transformed into protobuf message".to_owned(),
257 )),
258 Order::V4(order) => Ok(ProtoOrder {
259 chain_id: order.chain_id() as i32,
260 matcher_public_key: order.matcher().bytes(),
261 asset_pair: map_asset_pair(&order),
262 order_side: map_order_side(&order),
263 amount: order.amount().value() as i64,
264 price: order.price().value() as i64,
265 timestamp: order.timestamp() as i64,
266 expiration: order.expiration() as i64,
267 matcher_fee: map_matcher_fee(&order),
268 version: order.version() as i32,
269 proofs: signed_order
270 .proofs()
271 .iter()
272 .map(|proof| proof.bytes())
273 .collect(),
274 price_mode: map_price_mode(&order),
275 sender: Some(SenderPublicKey(order.sender().bytes())),
276 }),
277 }
278 }
279}
280
281impl TryFrom<SignedOrder> for OrderInfo {
282 type Error = Error;
283
284 fn try_from(signed_order: SignedOrder) -> Result<Self> {
285 match signed_order.order() {
286 Order::V3(order) => signed_order.id().map(|id| {
287 OrderInfo::V3(OrderInfoV3::new(
288 id,
289 order.chain_id(),
290 order.timestamp(),
291 order.sender(),
292 order.fee(),
293 order.order_type(),
294 order.amount(),
295 order.price(),
296 order.matcher(),
297 order.expiration(),
298 signed_order.proofs(),
299 ))
300 }),
301 Order::V4(order) => signed_order.id().map(|id| {
302 OrderInfo::V4(OrderInfoV4::new(
303 id,
304 order.chain_id(),
305 order.timestamp(),
306 order.sender(),
307 order.fee(),
308 order.order_type(),
309 order.amount(),
310 order.price(),
311 order.matcher(),
312 order.expiration(),
313 signed_order.proofs(),
314 order.price_mode(),
315 ))
316 }),
317 }
318 }
319}
320
321#[derive(Eq, PartialEq, Clone, Debug)]
322pub enum Order {
323 V3(v3::OrderV3),
324 V4(v4::OrderV4),
325}
326
327impl Order {
329 #[allow(clippy::too_many_arguments)]
330 pub fn v3(
331 chain_id: u8,
332 timestamp: u64,
333 sender: PublicKey,
334 fee: Amount,
335 order_type: OrderType,
336 amount: Amount,
337 price: Amount,
338 matcher: PublicKey,
339 expiration: u64,
340 ) -> Self {
341 Self::V3(OrderV3::new(
342 chain_id, timestamp, sender, fee, order_type, amount, price, matcher, expiration,
343 ))
344 }
345
346 #[allow(clippy::too_many_arguments)]
347 pub fn v4(
348 chain_id: u8,
349 timestamp: u64,
350 sender: PublicKey,
351 fee: Amount,
352 order_type: OrderType,
353 amount: Amount,
354 price: Amount,
355 matcher: PublicKey,
356 expiration: u64,
357 price_mode: PriceMode,
358 ) -> Self {
359 Self::V4(OrderV4::new(
360 chain_id, timestamp, sender, fee, order_type, amount, price, matcher, expiration,
361 price_mode,
362 ))
363 }
364
365 pub fn id(&self) -> Result<Id> {
366 match self {
367 Self::V3(order) => order.id(),
368 Self::V4(order) => order.id(),
369 }
370 }
371
372 pub fn chain_id(&self) -> u8 {
373 match self {
374 Self::V3(order) => order.chain_id(),
375 Self::V4(order) => order.chain_id(),
376 }
377 }
378
379 pub fn order_type(&self) -> OrderType {
380 match self {
381 Self::V3(order) => order.order_type(),
382 Self::V4(order) => order.order_type(),
383 }
384 }
385
386 pub fn version(&self) -> u8 {
387 match self {
388 Self::V3(order) => order.version(),
389 Self::V4(order) => order.version(),
390 }
391 }
392
393 pub fn sender(&self) -> PublicKey {
394 match self {
395 Self::V3(order) => order.sender(),
396 Self::V4(order) => order.sender(),
397 }
398 }
399
400 pub fn amount(&self) -> Amount {
401 match self {
402 Self::V3(order) => order.amount(),
403 Self::V4(order) => order.amount(),
404 }
405 }
406
407 pub fn price(&self) -> Amount {
408 match self {
409 Self::V3(order) => order.price(),
410 Self::V4(order) => order.price(),
411 }
412 }
413
414 pub fn fee(&self) -> Amount {
415 match self {
416 Self::V3(order) => order.fee(),
417 Self::V4(order) => order.fee(),
418 }
419 }
420
421 pub fn matcher(&self) -> PublicKey {
422 match self {
423 Self::V3(order) => order.matcher(),
424 Self::V4(order) => order.matcher(),
425 }
426 }
427
428 pub fn timestamp(&self) -> u64 {
429 match self {
430 Self::V3(order) => order.timestamp(),
431 Self::V4(order) => order.timestamp(),
432 }
433 }
434
435 pub fn expiration(&self) -> u64 {
436 match self {
437 Self::V3(order) => order.expiration(),
438 Self::V4(order) => order.expiration(),
439 }
440 }
441
442 pub fn sign(&self, private_key: &PrivateKey) -> Result<SignedOrder> {
443 match self {
444 Self::V3(order) => order.sign(private_key),
445 Self::V4(order) => order.sign(private_key),
446 }
447 }
448
449 pub fn default_expiration(current_time: u64) -> u64 {
450 current_time + (30 * 24 * 60 * 60 * 1000)
451 }
452}
453
454#[derive(Eq, PartialEq, Clone, Debug)]
455pub enum OrderType {
456 Buy,
457 Sell,
458}
459
460#[derive(Eq, PartialEq, Clone, Debug)]
461pub enum PriceMode {
462 Default,
463 FixedDecimals,
464 AssetDecimals,
465}
466
467impl TryFrom<&Order> for ProtoOrder {
468 type Error = Error;
469
470 fn try_from(order: &Order) -> Result<Self> {
471 match order {
472 Order::V3(_) => Err(UnsupportedOperation(
473 "Order version 3 can't be transformed into protobuf message".to_owned(),
474 )),
475 Order::V4(order) => Ok(ProtoOrder {
476 chain_id: order.chain_id() as i32,
477 matcher_public_key: order.matcher().bytes(),
478 asset_pair: map_asset_pair(order),
479 order_side: map_order_side(order),
480 amount: order.amount().value() as i64,
481 price: order.price().value() as i64,
482 timestamp: order.timestamp() as i64,
483 expiration: order.expiration() as i64,
484 matcher_fee: map_matcher_fee(order),
485 version: order.version() as i32,
486 proofs: vec![],
487 price_mode: map_price_mode(order),
488 sender: Some(SenderPublicKey(order.sender().bytes())),
489 }),
490 }
491 }
492}
493
494impl TryFrom<&Value> for Order {
495 type Error = Error;
496
497 fn try_from(order_json: &Value) -> Result<Self> {
498 let order_type =
499 match JsonDeserializer::safe_to_string_from_field(order_json, "orderType")?.as_str() {
500 "buy" => OrderType::Buy,
501 "sell" => OrderType::Sell,
502 _ => return Err(UnsupportedOperation("unknown order type".to_owned())),
503 };
504 let version = JsonDeserializer::safe_to_int_from_field(order_json, "version")? as u8;
505 let timestamp = JsonDeserializer::safe_to_int_from_field(order_json, "timestamp")?;
506 let sender_public_key = PublicKey::from_string(
507 &JsonDeserializer::safe_to_string_from_field(order_json, "senderPublicKey")?,
508 )?;
509
510 let sender = Address::from_string(&JsonDeserializer::safe_to_string_from_field(
511 order_json, "sender",
512 )?)?;
513
514 let matcher_fee = JsonDeserializer::safe_to_int_from_field(order_json, "matcherFee")?;
515 let matcher_fee_asset_id = match order_json["matcherFeeAssetId"].as_str() {
516 Some(asset) => Some(AssetId::from_string(asset)?),
517 None => None,
518 };
519
520 let amount_asset = match order_json["assetPair"]["amountAsset"].as_str() {
521 Some(asset) => Some(AssetId::from_string(asset)?),
522 None => None,
523 };
524 let amount = JsonDeserializer::safe_to_int_from_field(order_json, "amount")?;
525
526 let price_asset = match order_json["assetPair"]["priceAsset"].as_str() {
527 Some(asset) => Some(AssetId::from_string(asset)?),
528 None => None,
529 };
530
531 let price = JsonDeserializer::safe_to_int_from_field(order_json, "price")?;
532
533 let matcher_public_key = PublicKey::from_string(
534 &JsonDeserializer::safe_to_string_from_field(order_json, "matcherPublicKey")?,
535 )?;
536
537 let expiration = JsonDeserializer::safe_to_int_from_field(order_json, "expiration")?;
538
539 let price_mode = match order_json["priceMode"].as_str() {
540 Some(price_mode) => match price_mode {
541 "default" => PriceMode::Default,
542 "fixedDecimals" => PriceMode::FixedDecimals,
543 "assetDecimals" => PriceMode::AssetDecimals,
544 _ => return Err(UnsupportedOperation("unknown price mode".to_owned())),
545 },
546 None => PriceMode::Default,
548 };
549
550 match version {
551 3 => Ok(Order::V3(v3::OrderV3::new(
552 sender.chain_id(),
553 timestamp as u64,
554 sender_public_key,
555 Amount::new(matcher_fee as u64, matcher_fee_asset_id),
556 order_type,
557 Amount::new(amount as u64, amount_asset),
558 Amount::new(price as u64, price_asset),
559 matcher_public_key,
560 expiration as u64,
561 ))),
562 4 => Ok(Order::V4(v4::OrderV4::new(
563 sender.chain_id(),
564 timestamp as u64,
565 sender_public_key,
566 Amount::new(matcher_fee as u64, matcher_fee_asset_id),
567 order_type,
568 Amount::new(amount as u64, amount_asset),
569 Amount::new(price as u64, price_asset),
570 matcher_public_key,
571 expiration as u64,
572 price_mode,
573 ))),
574 _ => Err(Error::UnsupportedOrderVersion),
575 }
576 }
577}
578
579fn map_asset_pair(order: &OrderV4) -> Option<AssetPair> {
580 Some(AssetPair {
581 amount_asset_id: order
582 .amount()
583 .asset_id()
584 .map(|asset| asset.bytes())
585 .unwrap_or_default(),
586 price_asset_id: order
587 .price()
588 .asset_id()
589 .map(|asset| asset.bytes())
590 .unwrap_or_default(),
591 })
592}
593
594fn map_order_side(order: &OrderV4) -> i32 {
595 match order.order_type() {
596 OrderType::Buy => 0,
597 OrderType::Sell => 1,
598 }
599}
600
601fn map_matcher_fee(order: &OrderV4) -> Option<ProtoAmount> {
602 Some(ProtoAmount {
603 asset_id: order
604 .fee()
605 .asset_id()
606 .map(|asset| asset.bytes())
607 .unwrap_or_default(),
608 amount: order.fee().value() as i64,
609 })
610}
611
612fn map_price_mode(order: &OrderV4) -> i32 {
613 match order.price_mode() {
614 PriceMode::Default => 0,
615 PriceMode::FixedDecimals => 1,
616 PriceMode::AssetDecimals => 2,
617 }
618}