neo_solidity/ir/expressions/member_access/
runtime_values.rs1fn try_lower_runtime_member_access(
2 inner: &Expression,
3 member: &Identifier,
4 ctx: &mut LoweringContext,
5 instructions: &mut Vec<Instruction>,
6) -> Option<bool> {
7 match member.name.as_str() {
8 "sender" => {
9 if let Expression::Variable(base) = inner {
10 if base.name == "msg" {
11 if ctx.function_name == "onNEP17Payment" {
12 instructions.push(Instruction::LoadParameter(0));
13 } else {
14 instructions
15 .push(Instruction::LoadRuntimeValue(RuntimeValue::MsgSender));
16 }
17 return Some(true);
18 }
19 }
20 None
21 }
22 "value" => {
23 if let Expression::Variable(base) = inner {
24 if base.name == "msg" {
25 if ctx.function_name == "onNEP17Payment" {
26 instructions.push(Instruction::LoadParameter(1));
27 } else {
28 instructions.push(Instruction::LoadRuntimeValue(RuntimeValue::MsgValue));
29 }
30 return Some(true);
31 }
32 }
33 None
34 }
35 "data" => {
36 if let Expression::Variable(base) = inner {
37 if base.name == "msg" {
38 if ctx.function_name == "onNEP17Payment" {
39 instructions.push(Instruction::LoadParameter(2));
40 } else {
41 instructions.push(Instruction::LoadRuntimeValue(RuntimeValue::MsgData));
42 }
43 return Some(true);
44 }
45 }
46 None
47 }
48 "sig" => {
49 if let Expression::Variable(base) = inner {
50 if base.name == "msg" {
51 ctx.record_error_with_suggestion(
52 "msg.sig is not available on Neo N3. Neo dispatches by method name, not 4-byte function selectors",
53 "use string-based method identification instead",
54 );
55 return Some(false);
56 }
57 }
58 None
59 }
60 "origin" => {
61 if let Expression::Variable(base) = inner {
62 if base.name == "tx" {
63 eprintln!(
65 "warning: tx.origin has different semantics on Neo N3. \
66 Neo uses multi-signature witnesses instead of a single origin. \
67 Consider using msg.sender or Runtime.CheckWitness() instead."
68 );
69 instructions.push(Instruction::LoadRuntimeValue(RuntimeValue::TxOrigin));
70 return Some(true);
71 }
72 }
73 None
74 }
75 "gasprice" => {
76 if let Expression::Variable(base) = inner {
77 if base.name == "tx" {
78 eprintln!(
80 "warning: tx.gasprice auto-mapped to Policy.getFeePerByte() \
81 on Neo N3. Neo fees are determined by script size and syscall costs."
82 );
83 instructions.push(Instruction::CallBuiltin {
84 builtin: BuiltinCall::NativeCall {
85 contract: NativeContract::Policy,
86 method: "getFeePerByte".to_string(),
87 },
88 arg_count: 0,
89 });
90 return Some(true);
91 }
92 }
93 None
94 }
95 "timestamp" => {
96 if let Expression::Variable(base) = inner {
97 if base.name == "block" {
98 instructions.push(Instruction::LoadRuntimeValue(RuntimeValue::BlockTimestamp));
99 return Some(true);
100 }
101 }
102 None
103 }
104 "number" => {
105 if let Expression::Variable(base) = inner {
106 if base.name == "block" {
107 instructions.push(Instruction::LoadRuntimeValue(RuntimeValue::BlockNumber));
108 return Some(true);
109 }
110 }
111 None
112 }
113 "chainid" => {
114 if let Expression::Variable(base) = inner {
115 if base.name == "block" {
116 instructions.push(Instruction::CallBuiltin {
120 builtin: BuiltinCall::Syscall("System.Runtime.GetNetwork".to_string()),
121 arg_count: 0,
122 });
123 return Some(true);
124 }
125 }
126 None
127 }
128 "coinbase" => {
129 if let Expression::Variable(base) = inner {
130 if base.name == "block" {
131 eprintln!(
134 "warning: block.coinbase auto-mapped to address(0) on Neo N3 \
135 (dBFT consensus has no miner). Use NativeCalls.getNextBlockValidators() \
136 for validator info."
137 );
138 instructions.push(Instruction::PushLiteral(LiteralValue::Address(
139 [0u8; 20].to_vec(),
140 )));
141 return Some(true);
142 }
143 }
144 None
145 }
146 "difficulty" | "prevrandao" => {
147 if let Expression::Variable(base) = inner {
148 if base.name == "block" {
149 eprintln!(
151 "warning: block.{} auto-mapped to Runtime.getRandom() on Neo N3 \
152 (dBFT consensus has no PoW difficulty).",
153 member.name
154 );
155 instructions.push(Instruction::CallBuiltin {
156 builtin: BuiltinCall::Syscall(
157 "System.Runtime.GetRandom".to_string(),
158 ),
159 arg_count: 0,
160 });
161 return Some(true);
162 }
163 }
164 None
165 }
166 "gaslimit" => {
167 if let Expression::Variable(base) = inner {
168 if base.name == "block" {
169 eprintln!(
171 "warning: block.gaslimit auto-mapped to Policy.getExecFeeFactor() \
172 on Neo N3. Neo uses GAS token for fees, not per-block gas limits."
173 );
174 instructions.push(Instruction::CallBuiltin {
175 builtin: BuiltinCall::NativeCall {
176 contract: NativeContract::Policy,
177 method: "getExecFeeFactor".to_string(),
178 },
179 arg_count: 0,
180 });
181 return Some(true);
182 }
183 }
184 None
185 }
186 "basefee" => {
187 if let Expression::Variable(base) = inner {
188 if base.name == "block" {
189 eprintln!(
191 "warning: block.basefee auto-mapped to Policy.getFeePerByte() \
192 on Neo N3. Neo uses a fixed fee structure, not EIP-1559 base fees."
193 );
194 instructions.push(Instruction::CallBuiltin {
195 builtin: BuiltinCall::NativeCall {
196 contract: NativeContract::Policy,
197 method: "getFeePerByte".to_string(),
198 },
199 arg_count: 0,
200 });
201 return Some(true);
202 }
203 }
204 None
205 }
206 _ => None,
207 }
208}