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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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}