Skip to main content

avm_rs/opcodes/
bytes.rs

1//! Byte operations and manipulation opcodes
2
3use crate::error::{AvmError, AvmResult};
4use crate::types::StackValue;
5use crate::vm::EvalContext;
6use base64::Engine;
7use num_traits::Zero;
8
9const MAX_BYTE_MATH_SIZE: usize = 64;
10
11/// Convert bytes to big-endian number (up to 64 bytes)
12fn bytes_to_uint(bytes: &[u8]) -> AvmResult<num_bigint::BigUint> {
13    if bytes.len() > MAX_BYTE_MATH_SIZE {
14        return Err(AvmError::invalid_program(format!(
15            "Byte array too large for math: {} > {}",
16            bytes.len(),
17            MAX_BYTE_MATH_SIZE
18        )));
19    }
20    Ok(num_bigint::BigUint::from_bytes_be(bytes))
21}
22
23/// Convert big-endian number back to bytes
24fn uint_to_bytes(val: &num_bigint::BigUint, min_len: usize) -> Vec<u8> {
25    let bytes = val.to_bytes_be();
26    if bytes.len() >= min_len {
27        bytes
28    } else {
29        let mut result = vec![0u8; min_len - bytes.len()];
30        result.extend_from_slice(&bytes);
31        result
32    }
33}
34
35/// Byte addition
36pub fn op_b_plus(ctx: &mut EvalContext) -> AvmResult<()> {
37    ctx.advance_pc(1)?;
38    let b = ctx.pop()?;
39    let a = ctx.pop()?;
40
41    let a_bytes = a.as_bytes()?;
42    let b_bytes = b.as_bytes()?;
43
44    let a_num = bytes_to_uint(a_bytes)?;
45    let b_num = bytes_to_uint(b_bytes)?;
46
47    let result = a_num + b_num;
48    let max_len = std::cmp::max(a_bytes.len(), b_bytes.len());
49    let result_bytes = uint_to_bytes(&result, max_len);
50
51    ctx.push(StackValue::Bytes(result_bytes))?;
52    Ok(())
53}
54
55/// Byte subtraction
56pub fn op_b_minus(ctx: &mut EvalContext) -> AvmResult<()> {
57    ctx.advance_pc(1)?;
58    let b = ctx.pop()?;
59    let a = ctx.pop()?;
60
61    let a_bytes = a.as_bytes()?;
62    let b_bytes = b.as_bytes()?;
63
64    let a_num = bytes_to_uint(a_bytes)?;
65    let b_num = bytes_to_uint(b_bytes)?;
66
67    if a_num < b_num {
68        return Err(AvmError::IntegerUnderflow);
69    }
70
71    let result = a_num - b_num;
72    let max_len = std::cmp::max(a_bytes.len(), b_bytes.len());
73    let result_bytes = uint_to_bytes(&result, max_len);
74
75    ctx.push(StackValue::Bytes(result_bytes))?;
76    Ok(())
77}
78
79/// Byte division
80pub fn op_b_div(ctx: &mut EvalContext) -> AvmResult<()> {
81    ctx.advance_pc(1)?;
82    let b = ctx.pop()?;
83    let a = ctx.pop()?;
84
85    let a_bytes = a.as_bytes()?;
86    let b_bytes = b.as_bytes()?;
87
88    let a_num = bytes_to_uint(a_bytes)?;
89    let b_num = bytes_to_uint(b_bytes)?;
90
91    if b_num.is_zero() {
92        return Err(AvmError::DivisionByZero);
93    }
94
95    let result = a_num / b_num;
96    let max_len = std::cmp::max(a_bytes.len(), b_bytes.len());
97    let result_bytes = uint_to_bytes(&result, max_len);
98
99    ctx.push(StackValue::Bytes(result_bytes))?;
100    Ok(())
101}
102
103/// Byte multiplication
104pub fn op_b_mul(ctx: &mut EvalContext) -> AvmResult<()> {
105    ctx.advance_pc(1)?;
106    let b = ctx.pop()?;
107    let a = ctx.pop()?;
108
109    let a_bytes = a.as_bytes()?;
110    let b_bytes = b.as_bytes()?;
111
112    let a_num = bytes_to_uint(a_bytes)?;
113    let b_num = bytes_to_uint(b_bytes)?;
114
115    let result = a_num * b_num;
116    let max_len = std::cmp::max(a_bytes.len(), b_bytes.len());
117    let result_bytes = uint_to_bytes(&result, max_len);
118
119    ctx.push(StackValue::Bytes(result_bytes))?;
120    Ok(())
121}
122
123/// Byte less than
124pub fn op_b_lt(ctx: &mut EvalContext) -> AvmResult<()> {
125    ctx.advance_pc(1)?;
126    let b = ctx.pop()?;
127    let a = ctx.pop()?;
128
129    let a_bytes = a.as_bytes()?;
130    let b_bytes = b.as_bytes()?;
131
132    let a_num = bytes_to_uint(a_bytes)?;
133    let b_num = bytes_to_uint(b_bytes)?;
134
135    let result = if a_num < b_num { 1 } else { 0 };
136    ctx.push(StackValue::Uint(result))?;
137    Ok(())
138}
139
140/// Byte greater than
141pub fn op_b_gt(ctx: &mut EvalContext) -> AvmResult<()> {
142    ctx.advance_pc(1)?;
143    let b = ctx.pop()?;
144    let a = ctx.pop()?;
145
146    let a_bytes = a.as_bytes()?;
147    let b_bytes = b.as_bytes()?;
148
149    let a_num = bytes_to_uint(a_bytes)?;
150    let b_num = bytes_to_uint(b_bytes)?;
151
152    let result = if a_num > b_num { 1 } else { 0 };
153    ctx.push(StackValue::Uint(result))?;
154    Ok(())
155}
156
157/// Byte less than or equal
158pub fn op_b_le(ctx: &mut EvalContext) -> AvmResult<()> {
159    ctx.advance_pc(1)?;
160    let b = ctx.pop()?;
161    let a = ctx.pop()?;
162
163    let a_bytes = a.as_bytes()?;
164    let b_bytes = b.as_bytes()?;
165
166    let a_num = bytes_to_uint(a_bytes)?;
167    let b_num = bytes_to_uint(b_bytes)?;
168
169    let result = if a_num <= b_num { 1 } else { 0 };
170    ctx.push(StackValue::Uint(result))?;
171    Ok(())
172}
173
174/// Byte greater than or equal
175pub fn op_b_ge(ctx: &mut EvalContext) -> AvmResult<()> {
176    ctx.advance_pc(1)?;
177    let b = ctx.pop()?;
178    let a = ctx.pop()?;
179
180    let a_bytes = a.as_bytes()?;
181    let b_bytes = b.as_bytes()?;
182
183    let a_num = bytes_to_uint(a_bytes)?;
184    let b_num = bytes_to_uint(b_bytes)?;
185
186    let result = if a_num >= b_num { 1 } else { 0 };
187    ctx.push(StackValue::Uint(result))?;
188    Ok(())
189}
190
191/// Byte equal
192pub fn op_b_eq(ctx: &mut EvalContext) -> AvmResult<()> {
193    ctx.advance_pc(1)?;
194    let b = ctx.pop()?;
195    let a = ctx.pop()?;
196
197    let a_bytes = a.as_bytes()?;
198    let b_bytes = b.as_bytes()?;
199
200    let result = if a_bytes == b_bytes { 1 } else { 0 };
201    ctx.push(StackValue::Uint(result))?;
202    Ok(())
203}
204
205/// Byte not equal
206pub fn op_b_ne(ctx: &mut EvalContext) -> AvmResult<()> {
207    ctx.advance_pc(1)?;
208    let b = ctx.pop()?;
209    let a = ctx.pop()?;
210
211    let a_bytes = a.as_bytes()?;
212    let b_bytes = b.as_bytes()?;
213
214    let result = if a_bytes != b_bytes { 1 } else { 0 };
215    ctx.push(StackValue::Uint(result))?;
216    Ok(())
217}
218
219/// Byte modulo
220pub fn op_b_mod(ctx: &mut EvalContext) -> AvmResult<()> {
221    ctx.advance_pc(1)?;
222    let b = ctx.pop()?;
223    let a = ctx.pop()?;
224
225    let a_bytes = a.as_bytes()?;
226    let b_bytes = b.as_bytes()?;
227
228    let a_num = bytes_to_uint(a_bytes)?;
229    let b_num = bytes_to_uint(b_bytes)?;
230
231    if b_num.is_zero() {
232        return Err(AvmError::DivisionByZero);
233    }
234
235    let result = a_num % b_num;
236    let max_len = std::cmp::max(a_bytes.len(), b_bytes.len());
237    let result_bytes = uint_to_bytes(&result, max_len);
238
239    ctx.push(StackValue::Bytes(result_bytes))?;
240    Ok(())
241}
242
243/// Byte bitwise OR
244pub fn op_b_or(ctx: &mut EvalContext) -> AvmResult<()> {
245    ctx.advance_pc(1)?;
246    let b = ctx.pop()?;
247    let a = ctx.pop()?;
248
249    let a_bytes = a.as_bytes()?;
250    let b_bytes = b.as_bytes()?;
251
252    // Pad to same length
253    let max_len = std::cmp::max(a_bytes.len(), b_bytes.len());
254    let mut a_padded = vec![0u8; max_len];
255    let mut b_padded = vec![0u8; max_len];
256
257    a_padded[max_len - a_bytes.len()..].copy_from_slice(a_bytes);
258    b_padded[max_len - b_bytes.len()..].copy_from_slice(b_bytes);
259
260    let result: Vec<u8> = a_padded
261        .iter()
262        .zip(b_padded.iter())
263        .map(|(a, b)| a | b)
264        .collect();
265
266    ctx.push(StackValue::Bytes(result))?;
267    Ok(())
268}
269
270/// Byte bitwise AND
271pub fn op_b_and(ctx: &mut EvalContext) -> AvmResult<()> {
272    ctx.advance_pc(1)?;
273    let b = ctx.pop()?;
274    let a = ctx.pop()?;
275
276    let a_bytes = a.as_bytes()?;
277    let b_bytes = b.as_bytes()?;
278
279    // Pad to same length
280    let max_len = std::cmp::max(a_bytes.len(), b_bytes.len());
281    let mut a_padded = vec![0u8; max_len];
282    let mut b_padded = vec![0u8; max_len];
283
284    a_padded[max_len - a_bytes.len()..].copy_from_slice(a_bytes);
285    b_padded[max_len - b_bytes.len()..].copy_from_slice(b_bytes);
286
287    let result: Vec<u8> = a_padded
288        .iter()
289        .zip(b_padded.iter())
290        .map(|(a, b)| a & b)
291        .collect();
292
293    ctx.push(StackValue::Bytes(result))?;
294    Ok(())
295}
296
297/// Byte bitwise XOR
298pub fn op_b_xor(ctx: &mut EvalContext) -> AvmResult<()> {
299    ctx.advance_pc(1)?;
300    let b = ctx.pop()?;
301    let a = ctx.pop()?;
302
303    let a_bytes = a.as_bytes()?;
304    let b_bytes = b.as_bytes()?;
305
306    // Pad to same length
307    let max_len = std::cmp::max(a_bytes.len(), b_bytes.len());
308    let mut a_padded = vec![0u8; max_len];
309    let mut b_padded = vec![0u8; max_len];
310
311    a_padded[max_len - a_bytes.len()..].copy_from_slice(a_bytes);
312    b_padded[max_len - b_bytes.len()..].copy_from_slice(b_bytes);
313
314    let result: Vec<u8> = a_padded
315        .iter()
316        .zip(b_padded.iter())
317        .map(|(a, b)| a ^ b)
318        .collect();
319
320    ctx.push(StackValue::Bytes(result))?;
321    Ok(())
322}
323
324/// Byte bitwise NOT
325pub fn op_b_not(ctx: &mut EvalContext) -> AvmResult<()> {
326    ctx.advance_pc(1)?;
327    let a = ctx.pop()?;
328
329    let a_bytes = a.as_bytes()?;
330    let result: Vec<u8> = a_bytes.iter().map(|b| !b).collect();
331
332    ctx.push(StackValue::Bytes(result))?;
333    Ok(())
334}
335
336/// Byte manipulation operations
337/// Get bit from bytes
338pub fn op_getbit(ctx: &mut EvalContext) -> AvmResult<()> {
339    ctx.advance_pc(1)?;
340    let bit_index = ctx.pop()?;
341    let value = ctx.pop()?;
342
343    let bytes = value.as_bytes()?;
344    let bit_idx = bit_index.as_uint()? as usize;
345
346    let total_bits = bytes.len() * 8;
347    if bit_idx >= total_bits {
348        return Err(AvmError::invalid_program(format!(
349            "Bit index {bit_idx} out of bounds for {total_bits} bits"
350        )));
351    }
352
353    let byte_idx = bit_idx / 8;
354    let bit_offset = 7 - (bit_idx % 8); // MSB is bit 0
355    let bit_value = (bytes[byte_idx] >> bit_offset) & 1;
356
357    ctx.push(StackValue::Uint(bit_value as u64))?;
358    Ok(())
359}
360
361/// Set bit in bytes
362pub fn op_setbit(ctx: &mut EvalContext) -> AvmResult<()> {
363    ctx.advance_pc(1)?;
364    let new_bit = ctx.pop()?;
365    let bit_index = ctx.pop()?;
366    let value = ctx.pop()?;
367
368    let bytes = value.as_bytes()?;
369    let bit_idx = bit_index.as_uint()? as usize;
370    let bit_val = new_bit.as_uint()? & 1;
371
372    let total_bits = bytes.len() * 8;
373    if bit_idx >= total_bits {
374        return Err(AvmError::invalid_program(format!(
375            "Bit index {bit_idx} out of bounds for {total_bits} bits"
376        )));
377    }
378
379    let mut result = bytes.to_vec();
380    let byte_idx = bit_idx / 8;
381    let bit_offset = 7 - (bit_idx % 8); // MSB is bit 0
382
383    if bit_val == 1 {
384        result[byte_idx] |= 1 << bit_offset;
385    } else {
386        result[byte_idx] &= !(1 << bit_offset);
387    }
388
389    ctx.push(StackValue::Bytes(result))?;
390    Ok(())
391}
392
393/// Get byte from bytes
394pub fn op_getbyte(ctx: &mut EvalContext) -> AvmResult<()> {
395    ctx.advance_pc(1)?;
396    let byte_index = ctx.pop()?;
397    let value = ctx.pop()?;
398
399    let bytes = value.as_bytes()?;
400    let byte_idx = byte_index.as_uint()? as usize;
401
402    if byte_idx >= bytes.len() {
403        return Err(AvmError::invalid_program(format!(
404            "Byte index {} out of bounds for {} bytes",
405            byte_idx,
406            bytes.len()
407        )));
408    }
409
410    ctx.push(StackValue::Uint(bytes[byte_idx] as u64))?;
411    Ok(())
412}
413
414/// Set byte in bytes
415pub fn op_setbyte(ctx: &mut EvalContext) -> AvmResult<()> {
416    ctx.advance_pc(1)?;
417    let new_byte = ctx.pop()?;
418    let byte_index = ctx.pop()?;
419    let value = ctx.pop()?;
420
421    let bytes = value.as_bytes()?;
422    let byte_idx = byte_index.as_uint()? as usize;
423    let byte_val = new_byte.as_uint()? as u8;
424
425    if byte_idx >= bytes.len() {
426        return Err(AvmError::invalid_program(format!(
427            "Byte index {} out of bounds for {} bytes",
428            byte_idx,
429            bytes.len()
430        )));
431    }
432
433    let mut result = bytes.to_vec();
434    result[byte_idx] = byte_val;
435
436    ctx.push(StackValue::Bytes(result))?;
437    Ok(())
438}
439
440/// Extract bytes with immediate start and length
441pub fn op_extract(ctx: &mut EvalContext) -> AvmResult<()> {
442    ctx.advance_pc(1)?;
443    let start = ctx.read_bytes(1)?[0] as usize;
444    ctx.advance_pc(1)?;
445    let length = ctx.read_bytes(1)?[0] as usize;
446    ctx.advance_pc(1)?;
447
448    let value = ctx.pop()?;
449    let bytes = value.as_bytes()?;
450
451    if start >= bytes.len() || start + length > bytes.len() {
452        return Err(AvmError::invalid_program(format!(
453            "Extract bounds [{}, {}) out of range for {} bytes",
454            start,
455            start + length,
456            bytes.len()
457        )));
458    }
459
460    let result = bytes[start..start + length].to_vec();
461    ctx.push(StackValue::Bytes(result))?;
462    Ok(())
463}
464
465/// Extract bytes with stack arguments
466pub fn op_extract3(ctx: &mut EvalContext) -> AvmResult<()> {
467    ctx.advance_pc(1)?;
468    let length = ctx.pop()?;
469    let start = ctx.pop()?;
470    let value = ctx.pop()?;
471
472    let bytes = value.as_bytes()?;
473    let start_idx = start.as_uint()? as usize;
474    let len = length.as_uint()? as usize;
475
476    if start_idx >= bytes.len() || start_idx + len > bytes.len() {
477        return Err(AvmError::invalid_program(format!(
478            "Extract bounds [{}, {}) out of range for {} bytes",
479            start_idx,
480            start_idx + len,
481            bytes.len()
482        )));
483    }
484
485    let result = bytes[start_idx..start_idx + len].to_vec();
486    ctx.push(StackValue::Bytes(result))?;
487    Ok(())
488}
489
490/// Extract uint16 from bytes
491pub fn op_extract_uint16(ctx: &mut EvalContext) -> AvmResult<()> {
492    ctx.advance_pc(1)?;
493    let start = ctx.pop()?;
494    let value = ctx.pop()?;
495
496    let bytes = value.as_bytes()?;
497    let start_idx = start.as_uint()? as usize;
498
499    if start_idx + 2 > bytes.len() {
500        return Err(AvmError::invalid_program(format!(
501            "Extract uint16 bounds [{}, {}) out of range for {} bytes",
502            start_idx,
503            start_idx + 2,
504            bytes.len()
505        )));
506    }
507
508    let result = u16::from_be_bytes([bytes[start_idx], bytes[start_idx + 1]]) as u64;
509    ctx.push(StackValue::Uint(result))?;
510    Ok(())
511}
512
513/// Extract uint32 from bytes
514pub fn op_extract_uint32(ctx: &mut EvalContext) -> AvmResult<()> {
515    ctx.advance_pc(1)?;
516    let start = ctx.pop()?;
517    let value = ctx.pop()?;
518
519    let bytes = value.as_bytes()?;
520    let start_idx = start.as_uint()? as usize;
521
522    if start_idx + 4 > bytes.len() {
523        return Err(AvmError::invalid_program(format!(
524            "Extract uint32 bounds [{}, {}) out of range for {} bytes",
525            start_idx,
526            start_idx + 4,
527            bytes.len()
528        )));
529    }
530
531    let result = u32::from_be_bytes([
532        bytes[start_idx],
533        bytes[start_idx + 1],
534        bytes[start_idx + 2],
535        bytes[start_idx + 3],
536    ]) as u64;
537    ctx.push(StackValue::Uint(result))?;
538    Ok(())
539}
540
541/// Extract uint64 from bytes
542pub fn op_extract_uint64(ctx: &mut EvalContext) -> AvmResult<()> {
543    ctx.advance_pc(1)?;
544    let start = ctx.pop()?;
545    let value = ctx.pop()?;
546
547    let bytes = value.as_bytes()?;
548    let start_idx = start.as_uint()? as usize;
549
550    if start_idx + 8 > bytes.len() {
551        return Err(AvmError::invalid_program(format!(
552            "Extract uint64 bounds [{}, {}) out of range for {} bytes",
553            start_idx,
554            start_idx + 8,
555            bytes.len()
556        )));
557    }
558
559    let result = u64::from_be_bytes([
560        bytes[start_idx],
561        bytes[start_idx + 1],
562        bytes[start_idx + 2],
563        bytes[start_idx + 3],
564        bytes[start_idx + 4],
565        bytes[start_idx + 5],
566        bytes[start_idx + 6],
567        bytes[start_idx + 7],
568    ]);
569    ctx.push(StackValue::Uint(result))?;
570    Ok(())
571}
572
573/// Replace bytes with immediate start and replacement bytes
574pub fn op_replace2(ctx: &mut EvalContext) -> AvmResult<()> {
575    ctx.advance_pc(1)?;
576    let start = ctx.read_bytes(1)?[0] as usize;
577    ctx.advance_pc(1)?;
578
579    let replacement = ctx.pop()?;
580    let value = ctx.pop()?;
581
582    let bytes = value.as_bytes()?;
583    let repl_bytes = replacement.as_bytes()?;
584
585    if start >= bytes.len() || start + repl_bytes.len() > bytes.len() {
586        return Err(AvmError::invalid_program(format!(
587            "Replace bounds [{}, {}) out of range for {} bytes",
588            start,
589            start + repl_bytes.len(),
590            bytes.len()
591        )));
592    }
593
594    let mut result = bytes.to_vec();
595    result[start..start + repl_bytes.len()].copy_from_slice(repl_bytes);
596
597    ctx.push(StackValue::Bytes(result))?;
598    Ok(())
599}
600
601/// Replace bytes with stack arguments
602pub fn op_replace3(ctx: &mut EvalContext) -> AvmResult<()> {
603    ctx.advance_pc(1)?;
604    let replacement = ctx.pop()?;
605    let start = ctx.pop()?;
606    let value = ctx.pop()?;
607
608    let bytes = value.as_bytes()?;
609    let repl_bytes = replacement.as_bytes()?;
610    let start_idx = start.as_uint()? as usize;
611
612    if start_idx >= bytes.len() || start_idx + repl_bytes.len() > bytes.len() {
613        return Err(AvmError::invalid_program(format!(
614            "Replace bounds [{}, {}) out of range for {} bytes",
615            start_idx,
616            start_idx + repl_bytes.len(),
617            bytes.len()
618        )));
619    }
620
621    let mut result = bytes.to_vec();
622    result[start_idx..start_idx + repl_bytes.len()].copy_from_slice(repl_bytes);
623
624    ctx.push(StackValue::Bytes(result))?;
625    Ok(())
626}
627
628/// Base64 decode
629pub fn op_base64_decode(ctx: &mut EvalContext) -> AvmResult<()> {
630    ctx.advance_pc(1)?;
631    let encoding = ctx.read_bytes(1)?[0]; // 0=URLEncoding, 1=StdEncoding
632    ctx.advance_pc(1)?;
633
634    let value = ctx.pop()?;
635    let input = value.as_bytes()?;
636
637    let input_str = std::str::from_utf8(input)
638        .map_err(|_| AvmError::invalid_program("Invalid UTF-8 in base64 input"))?;
639
640    let result = match encoding {
641        0 => base64::engine::general_purpose::URL_SAFE_NO_PAD.decode(input_str),
642        1 => base64::engine::general_purpose::STANDARD.decode(input_str),
643        _ => return Err(AvmError::invalid_program("Invalid base64 encoding type")),
644    };
645
646    match result {
647        Ok(decoded) => ctx.push(StackValue::Bytes(decoded))?,
648        Err(_) => return Err(AvmError::invalid_program("Invalid base64 input")),
649    }
650
651    Ok(())
652}
653
654/// JSON reference - simplified implementation
655pub fn op_json_ref(ctx: &mut EvalContext) -> AvmResult<()> {
656    ctx.advance_pc(1)?;
657    let return_type = ctx.read_bytes(1)?[0]; // 0=JSONString, 1=JSONUint64, 2=JSONObject
658    ctx.advance_pc(1)?;
659
660    let key = ctx.pop()?;
661    let json_data = ctx.pop()?;
662
663    let json_bytes = json_data.as_bytes()?;
664    let key_bytes = key.as_bytes()?;
665
666    let json_str = std::str::from_utf8(json_bytes)
667        .map_err(|_| AvmError::invalid_program("Invalid UTF-8 in JSON data"))?;
668    let key_str = std::str::from_utf8(key_bytes)
669        .map_err(|_| AvmError::invalid_program("Invalid UTF-8 in JSON key"))?;
670
671    // Parse JSON and extract the requested field
672    let parsed_json: serde_json::Value = serde_json::from_str(json_str)
673        .map_err(|_| AvmError::invalid_program("Invalid JSON data"))?;
674
675    // Extract the field value
676    let field_value = parsed_json.get(key_str);
677
678    match return_type {
679        0 => {
680            // JSONString
681            match field_value {
682                Some(serde_json::Value::String(s)) => {
683                    ctx.push(StackValue::Bytes(s.as_bytes().to_vec()))?;
684                }
685                Some(value) => {
686                    // Convert other types to string representation
687                    let s = value.to_string();
688                    ctx.push(StackValue::Bytes(s.into_bytes()))?;
689                }
690                None => {
691                    // Field not found - return empty string
692                    ctx.push(StackValue::Bytes(Vec::new()))?;
693                }
694            }
695        }
696        1 => {
697            // JSONUint64
698            match field_value {
699                Some(serde_json::Value::Number(n)) => {
700                    if let Some(u) = n.as_u64() {
701                        ctx.push(StackValue::Uint(u))?;
702                    } else {
703                        // Not a valid u64
704                        ctx.push(StackValue::Uint(0))?;
705                    }
706                }
707                _ => {
708                    // Field not found or not a number
709                    ctx.push(StackValue::Uint(0))?;
710                }
711            }
712        }
713        2 => {
714            // JSONObject
715            match field_value {
716                Some(serde_json::Value::Object(_)) | Some(serde_json::Value::Array(_)) => {
717                    let serialized = serde_json::to_string(field_value.unwrap()).map_err(|_| {
718                        AvmError::invalid_program("Failed to serialize JSON object")
719                    })?;
720                    ctx.push(StackValue::Bytes(serialized.into_bytes()))?;
721                }
722                Some(value) => {
723                    // Return the value as JSON string
724                    let serialized = serde_json::to_string(value)
725                        .map_err(|_| AvmError::invalid_program("Failed to serialize JSON value"))?;
726                    ctx.push(StackValue::Bytes(serialized.into_bytes()))?;
727                }
728                None => {
729                    // Field not found - return null
730                    ctx.push(StackValue::Bytes(b"null".to_vec()))?;
731                }
732            }
733        }
734        _ => return Err(AvmError::invalid_program("Invalid JSON return type")),
735    }
736
737    Ok(())
738}