neo_solidity/cli/bytecode/bytecode_helpers/
array_runtime.rs

1fn emit_new_array(bytecode: &mut Vec<u8>) {
2    bytecode.push(0xC3); // NEWARRAY
3}
4
5fn emit_array_get(bytecode: &mut Vec<u8>) {
6    bytecode.push(0xCE); // PICKITEM
7}
8
9fn emit_array_set(bytecode: &mut Vec<u8>) {
10    bytecode.push(0xD0); // SETITEM
11}
12
13fn emit_load_runtime_value(
14    bytecode: &mut Vec<u8>,
15    value: &ir::RuntimeValue,
16    use_callt: bool,
17    token_patches: &mut Vec<MethodTokenPatch>,
18) {
19    match value {
20        ir::RuntimeValue::MsgSender => {
21            // Solidity `msg.sender` is the immediate caller:
22            // - entry contract: Transaction.Sender (first signer)
23            // - internal contract call: CallingScriptHash (caller contract)
24            //
25            // In Neo N3, contracts are typically invoked from an entry script (transaction
26            // script) that then calls into the contract. Detect entry calls by checking
27            // whether CallingScriptHash == EntryScriptHash.
28            emit_syscall(bytecode, "System.Runtime.GetEntryScriptHash");
29            emit_syscall(bytecode, "System.Runtime.GetCallingScriptHash");
30            bytecode.push(0x97); // EQUAL
31
32            // if !(calling == entry) jump to else (calling script hash)
33            let jmp_if_not_pos = bytecode.len();
34            bytecode.push(0x27); // JMPIFNOT_L
35            let jmp_if_not_operand = bytecode.len();
36            bytecode.extend_from_slice(&[0, 0, 0, 0]);
37
38            // then: Transaction.Sender
39            emit_syscall(bytecode, "System.Runtime.GetScriptContainer");
40            // Neo N3 Transaction stack item layout (devpack order):
41            // [Hash, Version, Nonce, Sender, ...]
42            push_integer_bigint(bytecode, &BigInt::from(3u8));
43            bytecode.push(0xCE); // PICKITEM (Transaction.Sender field)
44
45            // jump to end
46            let jmp_end_pos = bytecode.len();
47            bytecode.push(0x23); // JMP_L
48            let jmp_end_operand = bytecode.len();
49            bytecode.extend_from_slice(&[0, 0, 0, 0]);
50
51            // else:
52            let else_pos = bytecode.len();
53            emit_syscall(bytecode, "System.Runtime.GetCallingScriptHash");
54
55            // end:
56            let end_pos = bytecode.len();
57
58            let rel_else = (else_pos as i32)
59                .checked_sub(jmp_if_not_pos as i32)
60                .unwrap_or(0);
61            bytecode[jmp_if_not_operand..jmp_if_not_operand + 4]
62                .copy_from_slice(&rel_else.to_le_bytes());
63
64            let rel_end = (end_pos as i32).checked_sub(jmp_end_pos as i32).unwrap_or(0);
65            bytecode[jmp_end_operand..jmp_end_operand + 4].copy_from_slice(&rel_end.to_le_bytes());
66        }
67        ir::RuntimeValue::MsgValue => {
68            push_integer_bigint(bytecode, &BigInt::zero());
69        }
70        ir::RuntimeValue::MsgData => {
71            push_data(bytecode, &[]);
72        }
73        ir::RuntimeValue::TxOrigin => {
74            emit_syscall(bytecode, "System.Runtime.GetScriptContainer");
75            // Neo N3 Transaction stack item layout (devpack order):
76            // [Hash, Version, Nonce, Sender, ...]
77            push_integer_bigint(bytecode, &BigInt::from(3u8));
78            bytecode.push(0xCE); // PICKITEM (Transaction.Sender field)
79        }
80        // Neo's System.Runtime.GetTime returns milliseconds since epoch, while Solidity's
81        // block.timestamp is seconds. Normalize here to preserve Solidity semantics.
82        ir::RuntimeValue::BlockTimestamp => {
83            emit_syscall(bytecode, "System.Runtime.GetTime");
84            push_integer_bigint(bytecode, &BigInt::from(1000u64));
85            bytecode.push(0xA1); // DIV
86        }
87        ir::RuntimeValue::BlockNumber => {
88            emit_native_contract_call(
89                bytecode,
90                ir::NativeContract::Ledger,
91                "currentIndex",
92                0,
93                use_callt,
94                token_patches,
95            );
96        }
97    }
98}