Skip to main content

avalanche_rs/avm/parser/
output_parser.rs

1use rust_base58::ToBase58;
2use tracing::{error, instrument, trace};
3
4use std::borrow::Borrow;
5
6use bech32::ToBase32;
7use std::error::Error;
8
9use crate::avm::parser::Context;
10use crate::utils::conversion::{pop_i32, pop_i64, pop_u32};
11
12#[derive(Serialize, Deserialize, Debug)]
13pub struct Output {
14    pub type_id: i32,
15    pub amount: Option<i64>,
16    pub group_id: Option<i32>,
17    pub payload: Option<Vec<u8>>,
18    pub locktime: i64,
19    pub threshold: i32,
20    pub addresses: Vec<String>,
21}
22
23#[instrument(skip(_raw_msg), fields(tx_id = %_context.tx_id))]
24pub fn output_parser(_raw_msg: &[u8], _context: &mut Context) -> Result<Output, Box<dyn Error>> {
25    // Type Id
26    let type_id = pop_i32(_raw_msg[*_context.offset..=(*_context.offset + 3)].borrow());
27
28    *_context.offset += 4;
29
30    let output;
31
32    match type_id {
33        6 => output = secp256k1_mint_output_parser(_raw_msg, _context)?,
34        7 => output = secp256k1_transfer_output_parser(_raw_msg, _context)?,
35        10 => output = nft_mint_output_parser(_raw_msg, _context)?,
36        11 => output = nft_transfer_output_parser(_raw_msg, _context)?,
37        _ => {
38            error!(
39                "{} \n This type id {} for this output is not expected \n Dump of the tx bytes : {:?} \n +++++++",
40
41                _context.tx_id,
42                type_id,
43                _raw_msg
44            );
45            panic!("Unsupported")
46        }
47    }
48
49    Ok(output)
50}
51
52#[instrument(skip(_raw_msg), fields(tx_id = %_context.tx_id))]
53pub fn secp256k1_mint_output_parser(
54    _raw_msg: &[u8],
55    _context: &mut Context,
56) -> Result<Output, Box<dyn Error>> {
57    // Locktime
58    let locktime = pop_i64(_raw_msg[*_context.offset..=(*_context.offset + 7)].borrow());
59    trace!(
60        "{} \n Output -- SECP256K1MintOutput -- Locktime : {:?}",
61        _context.tx_id,
62        locktime
63    );
64    *_context.offset += 8;
65
66    // Threshold
67    let threshold = pop_i32(_raw_msg[*_context.offset..=(*_context.offset + 3)].borrow());
68    trace!(
69        "{} \n Output -- SECP256K1MintOutput -- Threshold : {:?}",
70        _context.tx_id,
71        threshold
72    );
73    *_context.offset += 4;
74
75    // Number of addresses
76    let number_of_address = pop_i32(_raw_msg[*_context.offset..=(*_context.offset + 3)].borrow());
77    trace!(
78        "{} \n Output -- SECP256K1MintOutput -- Number of addresses : {:?}",
79        _context.tx_id,
80        number_of_address
81    );
82    *_context.offset += 4;
83
84    // Addresses
85    let mut index = 0;
86    let mut addresses = Vec::new();
87
88    while index < number_of_address {
89        let address = format!(
90            "X-{}",
91            bech32::encode(
92                _context.network_name.as_str(),
93                _raw_msg[*_context.offset..=(*_context.offset + 19)]
94                    .to_vec()
95                    .to_base32()
96            )?
97        );
98        trace!(
99            "{} \n Output -- SECP256K1MintOutput -- Addresses number {} {:?}",
100            _context.tx_id,
101            index,
102            address
103        );
104        addresses.push(address);
105        *_context.offset += 20;
106        index += 1;
107    }
108
109    Ok(Output {
110        type_id: 6,
111        amount: None,
112        group_id: None,
113        payload: None,
114        locktime,
115        threshold,
116        addresses,
117    })
118}
119
120#[instrument(skip(_raw_msg), fields(tx_id = %_context.tx_id))]
121pub fn secp256k1_transfer_output_parser(
122    _raw_msg: &[u8],
123    _context: &mut Context,
124) -> Result<Output, Box<dyn Error>> {
125    // Amount
126    let amount = pop_i64(_raw_msg[*_context.offset..=(*_context.offset + 7)].borrow());
127    trace!(
128        "{} \n Output -- SECP256K1TransferOutput -- Parser -- Amount : {:?}",
129        _context.tx_id,
130        amount
131    );
132    *_context.offset += 8;
133
134    // Locktime
135    let locktime = pop_i64(_raw_msg[*_context.offset..=(*_context.offset + 7)].borrow());
136    trace!(
137        "{} \n Output -- SECP256K1TransferOutput -- Parser -- Locktime : {:?}",
138        _context.tx_id,
139        locktime
140    );
141    *_context.offset += 8;
142
143    // Threshold
144    let threshold = pop_i32(_raw_msg[*_context.offset..=(*_context.offset + 3)].borrow());
145    trace!(
146        "{} \n Output -- SECP256K1TransferOutput -- Parser -- Threshold : {:?}",
147        _context.tx_id,
148        threshold
149    );
150    *_context.offset += 4;
151
152    // Number of addresses
153    let number_of_address = pop_i32(_raw_msg[*_context.offset..=(*_context.offset + 3)].borrow());
154    trace!(
155        "{} \n Output -- SECP256K1TransferOutput -- Parser -- Number of addresses : {:?}",
156        _context.tx_id,
157        number_of_address
158    );
159    *_context.offset += 4;
160
161    // Addresses
162    let mut index = 0;
163    let mut addresses = Vec::new();
164
165    while index < number_of_address {
166        let address = format!(
167            "X-{}",
168            bech32::encode(
169                _context.network_name.as_str(),
170                _raw_msg[*_context.offset..=(*_context.offset + 19)]
171                    .to_vec()
172                    .to_base32()
173            )?
174        );
175        trace!(
176            "{} \n Output -- SECP256K1TransferOutput -- Parser Addresses number {} {:?}",
177            _context.tx_id,
178            index,
179            address
180        );
181        addresses.push(address);
182        *_context.offset += 20;
183        index += 1;
184    }
185
186    Ok(Output {
187        type_id: 7,
188        amount: Some(amount),
189        group_id: None,
190        payload: None,
191        locktime,
192        threshold,
193        addresses,
194    })
195}
196
197#[instrument(skip(_raw_msg), fields(tx_id = %_context.tx_id))]
198pub fn nft_mint_output_parser(
199    _raw_msg: &[u8],
200    _context: &mut Context,
201) -> Result<Output, Box<dyn Error>> {
202    // Group Id
203    let group_id = pop_i32(_raw_msg[*_context.offset..=(*_context.offset + 3)].borrow());
204    trace!(
205        "{} \n Output -- SECP256K1MintOutput -- Group Id : {:?}",
206        _context.tx_id,
207        group_id
208    );
209    *_context.offset += 4;
210
211    // Locktime
212    let locktime = pop_i64(_raw_msg[*_context.offset..=(*_context.offset + 7)].borrow());
213    trace!(
214        "{} \n Output -- SECP256K1MintOutput Parser -- Locktime : {:?}",
215        _context.tx_id,
216        locktime
217    );
218    *_context.offset += 8;
219
220    // Threshold
221    let threshold = pop_i32(_raw_msg[*_context.offset..=(*_context.offset + 3)].borrow());
222    trace!(
223        "{} \n Output -- SECP256K1MintOutput Parser -- Threshold : {:?}",
224        _context.tx_id,
225        threshold
226    );
227    *_context.offset += 4;
228
229    // Number of addresses
230    let number_of_address = pop_i32(_raw_msg[*_context.offset..=(*_context.offset + 3)].borrow());
231    trace!(
232        "{} \n Output -- SECP256K1MintOutput Parser -- Number of addresses : {:?}",
233        _context.tx_id,
234        number_of_address
235    );
236    *_context.offset += 4;
237
238    // Addresses
239    let mut index = 0;
240    let mut addresses = Vec::new();
241
242    while index < number_of_address {
243        let address = format!(
244            "X-{}",
245            bech32::encode(
246                _context.network_name.as_str(),
247                _raw_msg[*_context.offset..=(*_context.offset + 19)]
248                    .to_vec()
249                    .to_base32()
250            )?
251        );
252        trace!(
253            "{} \n Output -- SECP256K1MintOutput Parser -- Addresses number {} {:?}",
254            _context.tx_id,
255            index,
256            address
257        );
258        addresses.push(address);
259        *_context.offset += 20;
260        index += 1;
261    }
262
263    Ok(Output {
264        type_id: 10,
265        amount: None,
266        group_id: Some(group_id),
267        payload: None,
268        locktime,
269        threshold,
270        addresses,
271    })
272}
273
274#[instrument(skip(_raw_msg), fields(tx_id = %_context.tx_id))]
275pub fn nft_transfer_output_parser(
276    _raw_msg: &[u8],
277    _context: &mut Context,
278) -> Result<Output, Box<dyn Error>> {
279    // Group Id
280    let group_id = pop_i32(_raw_msg[*_context.offset..=(*_context.offset + 3)].borrow());
281    trace!(
282        "{} \n Output -- NftTransferOutput Parser -- Group Id : {:?}",
283        _context.tx_id,
284        group_id
285    );
286    *_context.offset += 4;
287
288    // Payload
289    let payload_size = pop_u32(&_raw_msg[*_context.offset..=(*_context.offset + 3)]) as usize;
290    trace!(
291        "{} \n Output -- NftTransferOutput Parser -- Payload size: {:?}",
292        _context.tx_id,
293        payload_size
294    );
295    *_context.offset += 4;
296
297    // Payload
298    let mut payload = Vec::new();
299    if payload_size == 0 {
300        trace!(
301            "{} \n Output -- NftTransferOutput Parser -- payload_size is empty ",
302            _context.tx_id
303        );
304    } else {
305        trace!(
306            "{} \n Output -- NftTransferOutput Parser -- payload content : {:?}",
307            _context.tx_id,
308            &_raw_msg[*_context.offset..=(*_context.offset + payload_size)].to_base58()
309        );
310        payload = _raw_msg[*_context.offset..=(*_context.offset + payload_size)].to_vec();
311        *_context.offset += payload_size;
312    }
313
314    // Locktime
315    let locktime = pop_i64(_raw_msg[*_context.offset..=(*_context.offset + 7)].borrow());
316    trace!(
317        "{} \n Output -- NftTransferOutput Parser -- Locktime : {:?}",
318        _context.tx_id,
319        locktime
320    );
321    *_context.offset += 8;
322
323    // Threshold
324    let threshold = pop_i32(_raw_msg[*_context.offset..=(*_context.offset + 3)].borrow());
325    trace!(
326        "{} \n Output -- NftTransferOutput Parser -- Threshold : {:?}",
327        _context.tx_id,
328        threshold
329    );
330    *_context.offset += 4;
331
332    // Number of addresses
333    let number_of_address = pop_i32(_raw_msg[*_context.offset..=(*_context.offset + 3)].borrow());
334    trace!(
335        "{} \n Output -- NftTransferOutput Parser -- Number of addresses : {:?}",
336        _context.tx_id,
337        number_of_address
338    );
339    *_context.offset += 4;
340
341    // Addresses
342    let mut index = 0;
343    let mut addresses = Vec::new();
344
345    while index < number_of_address {
346        let address = format!(
347            "X-{}",
348            bech32::encode(
349                _context.network_name.as_str(),
350                _raw_msg[*_context.offset..=(*_context.offset + 19)]
351                    .to_vec()
352                    .to_base32()
353            )?
354        );
355        trace!(
356            "{} \n Output -- NftTransferOutput Parser -- Addresses number {} {:?}",
357            _context.tx_id,
358            index,
359            address
360        );
361        addresses.push(address);
362        *_context.offset += 20;
363        index += 1;
364    }
365
366    Ok(Output {
367        type_id: 11,
368        amount: None,
369        group_id: Some(group_id),
370        payload: Some(payload),
371        locktime,
372        threshold,
373        addresses,
374    })
375}