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