avalanche_rs/avm/parser/
transfer_op_parser.rs

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