waves_rust/util/
binary_serializer.rs

1use prost::Message;
2
3use TransactionData::{
4    Burn, CreateAlias, Ethereum, Genesis, Lease, LeaseCancel, MassTransfer, Payment, Reissue,
5    SetAssetScript, SetScript, SponsorFee, UpdateAssetInfo,
6};
7
8use crate::error::Error::UnsupportedOperation;
9use crate::error::Result;
10use crate::model::TransactionData::{Data, Exchange, InvokeScript, Issue, Transfer};
11use crate::model::{ByteString, Order, OrderType, Transaction, TransactionData};
12use crate::waves_proto::transaction::Data as ProtoData;
13use crate::waves_proto::{
14    Amount as ProtoAmount, Order as ProtoOrder, Transaction as ProtoTransaction,
15};
16
17use super::ByteWriter;
18
19pub struct BinarySerializer;
20
21impl BinarySerializer {
22    pub fn tx_body_bytes(transaction: &Transaction) -> Result<Vec<u8>> {
23        let proto_data = match transaction.data() {
24            Genesis(tx) => ProtoData::Genesis(tx.try_into()?),
25            Payment(tx) => ProtoData::Payment(tx.try_into()?),
26            Transfer(tx) => ProtoData::Transfer(tx.try_into()?),
27            Data(tx) => ProtoData::DataTransaction(tx.try_into()?),
28            Issue(tx) => ProtoData::Issue(tx.try_into()?),
29            InvokeScript(tx) => ProtoData::InvokeScript(tx.try_into()?),
30            Exchange(tx) => ProtoData::Exchange(tx.try_into()?),
31            Reissue(tx) => ProtoData::Reissue(tx.try_into()?),
32            Burn(tx) => ProtoData::Burn(tx.try_into()?),
33            Lease(tx) => ProtoData::Lease(tx.try_into()?),
34            LeaseCancel(tx) => ProtoData::LeaseCancel(tx.try_into()?),
35            CreateAlias(tx) => ProtoData::CreateAlias(tx.try_into()?),
36            MassTransfer(tx) => ProtoData::MassTransfer(tx.try_into()?),
37            SetScript(tx) => ProtoData::SetScript(tx.try_into()?),
38            SetAssetScript(tx) => ProtoData::SetAssetScript(tx.try_into()?),
39            SponsorFee(tx) => ProtoData::SponsorFee(tx.try_into()?),
40            UpdateAssetInfo(tx) => ProtoData::UpdateAssetInfo(tx.try_into()?),
41            Ethereum(_) => Err(UnsupportedOperation("ethereum transaction".to_owned()))?,
42        };
43
44        let fee_asset_id = match transaction.fee().asset_id() {
45            None => vec![],
46            Some(asset_id) => asset_id.bytes(),
47        };
48
49        let amount = ProtoAmount {
50            amount: transaction.fee().value() as i64,
51            asset_id: fee_asset_id,
52        };
53
54        let proto_tx = ProtoTransaction {
55            chain_id: transaction.chain_id() as i32,
56            data: Some(proto_data),
57            fee: Some(amount),
58            sender_public_key: transaction.public_key().bytes(),
59            timestamp: transaction.timestamp() as i64,
60            version: transaction.version() as i32,
61        };
62
63        let buf = Message::encode_to_vec(&proto_tx);
64        Ok(buf)
65    }
66
67    pub fn order_body_bytes(order: &Order) -> Result<Vec<u8>> {
68        match order {
69            Order::V3(order) => {
70                let mut bw = ByteWriter::new();
71
72                // https://docs.waves.tech/en/blockchain/binary-format/order-binary-format#version-3
73                bw.push_byte(3);
74                bw.push_bytes(&mut order.sender().bytes());
75                bw.push_bytes(&mut order.matcher().bytes());
76                match order.amount().asset_id() {
77                    Some(asset_id) => {
78                        bw.push_byte(1);
79                        bw.push_bytes(&mut asset_id.bytes());
80                    }
81                    None => {
82                        bw.push_byte(0);
83                    }
84                }
85                match order.price().asset_id() {
86                    Some(asset_id) => {
87                        bw.push_byte(1);
88                        bw.push_bytes(&mut asset_id.bytes());
89                    }
90                    None => {
91                        bw.push_byte(0);
92                    }
93                }
94                match order.order_type() {
95                    OrderType::Buy => {
96                        bw.push_byte(0);
97                    }
98                    OrderType::Sell => {
99                        bw.push_byte(1);
100                    }
101                }
102                bw.push_bytes(&mut order.price().value().to_be_bytes().to_vec());
103                bw.push_bytes(&mut order.amount().value().to_be_bytes().to_vec());
104                bw.push_bytes(&mut order.timestamp().to_be_bytes().to_vec());
105                bw.push_bytes(&mut order.expiration().to_be_bytes().to_vec());
106                bw.push_bytes(&mut order.fee().value().to_be_bytes().to_vec());
107                match order.fee().asset_id() {
108                    Some(asset_id) => {
109                        bw.push_byte(1);
110                        bw.push_bytes(&mut asset_id.bytes());
111                    }
112                    None => {
113                        bw.push_byte(0);
114                    }
115                }
116
117                Ok(bw.bytes())
118            }
119            Order::V4(_) => {
120                let proto_order: ProtoOrder = order.try_into()?;
121                let buf = Message::encode_to_vec(&proto_order);
122                Ok(buf)
123            }
124        }
125    }
126}