xavax_avalanche/evm_atomic/
tx_format_impl.rs

1use std::borrow::Borrow;
2
3use super::tx_format::*;
4use crate::avm::tx_format::{Credential, TransferableInput, TransferableOutput};
5use crate::encoding::cb58::encode_cb58;
6use crate::parser::parser_traits::Parser;
7use crate::parser::byte_conversion::*;
8
9
10/* ----\\\0111100001100001011101100110000101111000_we_are_one\\\ --- NON-IMPORTANT-NOTE:
11    Working really hard but this stuff is a lot, no docs for this yet! Sowwy (╥﹏╥)
12*/
13
14
15impl Parser for EVMOutput {
16    fn from_bytes(&mut self, raw_payload: &[u8], offset: Option<&mut usize>) {
17        let mut offset: usize = 0;
18        self.address.address_bytes = raw_payload[offset..=(offset + 19)].try_into().expect("Slice with incorrect length! diinki pls fix");
19        offset += 20;
20        self.amount = extract_u64(raw_payload[offset..=(offset + 7)].borrow());
21        offset += 8;
22        self.asset_id = raw_payload[offset..=(offset + 31)].try_into().expect("Slice with incorrect length! diinki pls fix");
23    }
24
25    fn to_bytes(&self) -> Vec<u8> {
26        let mut result: Vec<u8> = Vec::new();
27        result.extend_from_slice(&self.address.address_bytes);
28        result.extend_from_slice(&self.amount.to_be_bytes());
29        result.extend_from_slice(&self.asset_id);
30        result
31    }
32
33    fn to_cb58(&self) -> String {
34        encode_cb58(&self.to_bytes()[..])
35    }
36}
37impl Parser for EVMInput {
38    fn from_bytes(&mut self, raw_payload: &[u8], offset: Option<&mut usize>) {
39        let mut offset: usize = 0;
40        self.address.address_bytes = raw_payload[offset..=(offset + 19)].try_into().expect("Slice with incorrect length! diinki pls fix");
41        offset += 20;
42        self.amount = extract_u64(raw_payload[offset..=(offset + 7)].borrow());
43        offset += 8;
44        self.asset_id = raw_payload[offset..=(offset + 31)].try_into().expect("Slice with incorrect length! diinki pls fix");
45        offset += 32;
46        self.nonce = extract_u64(raw_payload[offset..=(offset + 7)].borrow());
47    }
48
49    fn to_bytes(&self) -> Vec<u8> {
50        let mut result: Vec<u8> = Vec::new();
51        result.extend_from_slice(&self.address.address_bytes);
52        result.extend_from_slice(&self.amount.to_be_bytes());
53        result.extend_from_slice(&self.asset_id);
54        result.extend_from_slice(&self.nonce.to_be_bytes());
55        result
56    }
57
58    fn to_cb58(&self) -> String {
59        encode_cb58(&self.to_bytes()[..])
60    }
61}
62
63impl Parser for ExportTx {
64    fn from_bytes(&mut self, raw_payload: &[u8], offset: Option<&mut usize>) {
65        let mut offset: usize = 0;
66        self.type_id = extract_u32(raw_payload[offset..=(offset + 3)].borrow());
67        offset += 4;
68        self.network_id = extract_u32(raw_payload[offset..=(offset + 3)].borrow());
69        offset += 4;
70        self.blockchain_id = raw_payload[offset..=(offset + 31)].try_into().expect("Incorrect slice length!");
71        offset += 32;
72        self.destination_chain = raw_payload[offset..=(offset + 31)].try_into().expect("Incorrect slice length!");
73        offset += 32;
74
75        let inputs_len: u32 = extract_u32(raw_payload[offset..=(offset + 3)].borrow());
76        offset += 4;
77
78        let mut index: usize = 0;
79        while index < inputs_len as usize {
80            let mut input: EVMInput = EVMInput::default();
81            input.from_bytes(&raw_payload[offset..], None);
82            self.inputs.push(input.clone());
83            offset += input.to_bytes().len();
84            index += 1;
85        }
86
87        let output_len: u32 = extract_u32(raw_payload[offset..=(offset + 3)].borrow());
88        offset += 4;
89
90        let mut index: usize = 0;
91        while index < output_len as usize {
92            let mut output: TransferableOutput = TransferableOutput::default();
93            output.from_bytes(&raw_payload[offset..], None);
94            self.exported_outputs.push(output.clone());
95            offset += output.to_bytes().len();
96            index += 1;
97        }
98    }
99
100    fn to_bytes(&self) -> Vec<u8> {
101        let mut result: Vec<u8> = Vec::new();
102        result.extend_from_slice(&self.type_id.to_be_bytes());
103        result.extend_from_slice(&self.network_id.to_be_bytes());
104        result.extend_from_slice(&self.blockchain_id);
105        result.extend_from_slice(&self.destination_chain);
106        
107        result.extend_from_slice(&(self.inputs.len() as u32).to_be_bytes());
108        for i in &self.inputs {
109            result.extend_from_slice(&i.to_bytes()[..]);
110        }
111
112        result.extend_from_slice(&(self.exported_outputs.len() as u32).to_be_bytes());
113        for t_o in &self.exported_outputs {
114            result.extend_from_slice(&t_o.to_bytes()[..]);
115        }
116        result
117    }
118
119    fn to_cb58(&self) -> String {
120        encode_cb58(&self.to_bytes()[..])
121    }
122}
123
124impl Parser for ImportTx {
125    fn from_bytes(&mut self, raw_payload: &[u8], offset: Option<&mut usize>) {
126        let mut offset: usize = 0;
127        self.type_id = extract_u32(raw_payload[offset..=(offset + 3)].borrow());
128        offset += 4;
129        self.network_id = extract_u32(raw_payload[offset..=(offset + 3)].borrow());
130        offset += 4;
131        self.blockchain_id = raw_payload[offset..=(offset + 31)].try_into().expect("Incorrect slice length!");
132        offset += 32;
133        self.source_chain = raw_payload[offset..=(offset + 31)].try_into().expect("Incorrect slice length!");
134        offset += 32;
135
136        let input_len: u32 = extract_u32(raw_payload[offset..=(offset + 3)].borrow());
137        offset += 4;
138
139        let mut index: usize = 0;
140        while index < input_len as usize {
141            let mut input: TransferableInput = TransferableInput::default();
142            input.from_bytes(&raw_payload[offset..], None);
143            self.imported_inputs.push(input.clone());
144            offset += input.to_bytes().len();
145            index += 1;
146        }
147
148        let imported_inputs_len: u32 = extract_u32(raw_payload[offset..=(offset + 3)].borrow());
149        offset += 4;
150
151        let mut index: usize = 0;
152        while index < imported_inputs_len as usize {
153            let mut output: EVMOutput = EVMOutput::default();
154            output.from_bytes(&raw_payload[offset..], None);
155            self.outputs.push(output.clone());
156            offset += output.to_bytes().len();
157            index += 1;
158        }
159    }
160
161    fn to_bytes(&self) -> Vec<u8> {
162        let mut result: Vec<u8> = Vec::new();
163        result.extend_from_slice(&self.type_id.to_be_bytes());
164        result.extend_from_slice(&self.network_id.to_be_bytes());
165        result.extend_from_slice(&self.blockchain_id);
166        result.extend_from_slice(&self.source_chain);
167        
168        result.extend_from_slice(&(self.imported_inputs.len() as u32).to_be_bytes());
169        for i in &self.imported_inputs {
170            result.extend_from_slice(&i.to_bytes()[..]);
171        }
172
173        result.extend_from_slice(&(self.outputs.len() as u32).to_be_bytes());
174        for o in &self.outputs {
175            result.extend_from_slice(&o.to_bytes()[..]);
176        }
177        result
178    }
179
180    fn to_cb58(&self) -> String {
181        encode_cb58(&self.to_bytes()[..])
182    }
183}
184
185
186impl Parser for SignedTransaction {
187    fn from_bytes(&mut self, raw_payload: &[u8], offset: Option<&mut usize>) {
188        let mut offset: usize = 0;
189        self.codec_id = extract_u16(raw_payload[offset..=(offset + 1)].borrow());
190        offset += 2;
191
192        let tx_type_id: u32 = extract_u32(raw_payload[offset..=(offset + 3)].borrow());
193        match tx_type_id {
194            0 => {
195                let mut tx: ImportTx = ImportTx::default();
196                tx.from_bytes(&raw_payload[offset..], None);
197                self.atomic_tx = AtomicTx::ImportTx(tx.clone());
198                offset += tx.to_bytes().len();
199            }
200            1 => {
201                let mut tx: ExportTx = ExportTx::default();
202                tx.from_bytes(&raw_payload[offset..], None);
203                self.atomic_tx = AtomicTx::ExportTx(tx.clone());
204                offset += tx.to_bytes().len();
205            }
206            _=> {
207                panic!("Incorrect tx_id!")
208            }
209        }
210        let cred_len: u32 = extract_u32(raw_payload[offset..=(offset + 3)].borrow());
211        offset += 4;
212
213        let mut index: u32 = 0;
214        while index < cred_len {
215            let mut c = Credential::default();
216            c.from_bytes(&raw_payload[offset..], None);
217            self.credentials.push(c.clone());
218            offset += c.to_bytes().len();
219            
220            index += 1;
221        }
222        
223    }
224    fn to_bytes(&self) -> Vec<u8> {
225        let mut result: Vec<u8> = Vec::new();
226
227        result.extend_from_slice(&self.codec_id.to_be_bytes());
228        match &self.atomic_tx {
229            AtomicTx::ImportTx(tx) => {
230                result.extend_from_slice(&tx.to_bytes()[..]);
231            },
232            AtomicTx::ExportTx(tx) => {
233                result.extend_from_slice(&tx.to_bytes()[..]);
234            },
235        }
236
237        result.extend_from_slice(&(self.credentials.len() as u32).to_be_bytes());
238        for i in &self.credentials {
239            result.extend_from_slice(&i.to_bytes());
240        }
241        result
242    }
243    fn to_cb58(&self) -> String {
244        encode_cb58(&self.to_bytes()[..])
245    }
246}
247
248
249#[cfg(test)]
250mod tests {
251    use crate::encoding::cb58::decode_cb58;
252    use crate::evm_atomic::tx_format::*;
253    use crate::parser::parser_traits::Parser;
254
255
256    /* damn the test worked firs try, I didn't expect it but I did really need it  (ಥ﹏ಥ)*/
257
258    //ps: the cb_58_encoded_tx is a transaction generated by the default avalanche web wallet that I packed-sniffed and got,
259    //used it here as a bench-mark.
260    #[test]
261    fn test_signed_transactions() {
262
263        //Cross chain X-chain ---> C-Chain
264        let cb_58_encoded_tx = "111111111879MAjcAYPQY7BPt8JDK9oJrKf88WfnUdX7dPpKTZRb9MxnwzRmG9MiCPndDfJMKpU3xjSLoboA15Y1no9J3vdc9YV3WAVmamjDMGYxffQ3jBsEB2yUEa5mvhwkAHpZMtnWRvnU3EimZY377FCCFfvAc3RVesPJoe5cuZTjAk1MH3hz23xXeURUYSEBWHsNd4ByxLFNejRtRyV9AN3bmWTrWN4F6fXvKwd1uicCw5FSjJUfQDZpBD84htGu4q7KUCXHBT4ze3caembBiJ1BMHRgG4Wa4kvfaWwrBpBMvv3eKxWoHgja4pJ8jckq64N8wCEt3bS5xBZrBbrsg7xCmr6vHG7P95ahepcQDGwu9ANCWfyxeoBCHTeXiHDzR9PAXk4fzuRZ4J196k1i6NDrZxHm9ohRa".to_string();
265        let temp = decode_cb58(cb_58_encoded_tx.clone());
266
267        let mut tx: SignedTransaction = SignedTransaction::default();
268        tx.from_bytes(&temp, None);
269
270        assert_eq!(tx.to_cb58(), cb_58_encoded_tx);
271
272        //Cross chain C-chain ---> X-Chain
273        let cb_58_encoded_tx = "111119TRcmX2yWov6MZAQjGpUwLsrQkofTZg9FjNiX2vryYzsKbvwVu8EVobeZ9NqJo9AcYDrLiB8u1QQduF7Gpu6ktiij117A5PNjRinDMMm77VDaT7ZG8CFEjNSQT3TiQ28eyBZ5rWKsTd74phC6zS7TRZtqXecsie5sgUxF5hSZfPNMcZpTpRPtvauuFx6F85bpV8HPBfEXzZYafczqGn1S8SzCKa5QodPsR9y5KX25rYb2xbBVLDeRA8fV2NPyxHwA6kKbJ7vNdyV9w4Gv1NAT5HRRVrPoDC2SE3SPAzytVmSUPgjwLaq3zUQ1iD6z8hER9E9idGT2dbvdyWx2YiC46YFH1R4wkx6kEWZURSKc54vqv9y13pe5tyYJFRuZ3wqWiPV7qcpq1M1GfyZUubjY8323TcATRjNJ".to_string();
274        let temp = decode_cb58(cb_58_encoded_tx.clone());
275
276        let mut tx: SignedTransaction = SignedTransaction::default();
277        tx.from_bytes(&temp, None);
278
279        assert_eq!(tx.to_cb58(), cb_58_encoded_tx);
280    }
281}