neo_solidity/ir/expressions/calls/builtins/
member_neo.rs1fn try_lower_neo_member_builtin(
2 base: &Identifier,
3 member: &Identifier,
4 args: &[Expression],
5 ctx: &mut LoweringContext,
6 instructions: &mut Vec<Instruction>,
7) -> Option<bool> {
8 if base.name != "Neo" {
9 return None;
10 }
11
12 match member.name.as_str() {
13 "isCommittee" => {
14 if args.len() != 1 {
15 ctx.record_error(format!(
16 "Neo.isCommittee requires 1 argument(s), got {}",
17 args.len()
18 ));
19 return Some(false);
20 }
21
22 let tmp_id = ctx.next_label();
27 let account_slot = ctx.allocate_local(
28 format!("__neo_is_committee_account_{tmp_id}"),
29 Some(ValueType::Address),
30 );
31 let committee_slot = ctx.allocate_local(
32 format!("__neo_is_committee_committee_{tmp_id}"),
33 Some(ValueType::Any),
34 );
35 let index_slot = ctx.allocate_local(
36 format!("__neo_is_committee_index_{tmp_id}"),
37 Some(ValueType::Integer {
38 signed: false,
39 bits: 256,
40 }),
41 );
42
43 if !lower_expression(&args[0], ctx, instructions) {
44 return Some(false);
45 }
46 instructions.push(Instruction::StoreLocal(account_slot));
47
48 instructions.push(Instruction::CallBuiltin {
49 builtin: BuiltinCall::NativeCall {
50 contract: NativeContract::Neo,
51 method: "getCommittee".to_string(),
52 },
53 arg_count: 0,
54 });
55 instructions.push(Instruction::StoreLocal(committee_slot));
56
57 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
58 BigInt::zero(),
59 )));
60 instructions.push(Instruction::StoreLocal(index_slot));
61
62 let loop_label = ctx.next_label();
63 let advance_label = ctx.next_label();
64 let done_label = ctx.next_label();
65 let end_label = ctx.next_label();
66
67 instructions.push(Instruction::Label(loop_label));
68 instructions.push(Instruction::LoadLocal(index_slot));
69 instructions.push(Instruction::LoadLocal(committee_slot));
70 instructions.push(Instruction::GetSize);
71 instructions.push(Instruction::BinaryOp(BinaryOperator::Lt));
72 instructions.push(Instruction::JumpIf { target: done_label });
73
74 instructions.push(Instruction::LoadLocal(committee_slot));
76 instructions.push(Instruction::LoadLocal(index_slot));
77 instructions.push(Instruction::ArrayGet);
78 instructions.push(Instruction::CallBuiltin {
79 builtin: BuiltinCall::Syscall("System.Contract.CreateStandardAccount".to_string()),
80 arg_count: 1,
81 });
82 instructions.push(Instruction::LoadLocal(account_slot));
83 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
84 instructions.push(Instruction::JumpIf {
85 target: advance_label,
86 });
87
88 instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(true)));
89 instructions.push(Instruction::Jump { target: end_label });
90
91 instructions.push(Instruction::Label(advance_label));
92 instructions.push(Instruction::LoadLocal(index_slot));
93 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
94 BigInt::one(),
95 )));
96 instructions.push(Instruction::BinaryOp(BinaryOperator::Add));
97 instructions.push(Instruction::StoreLocal(index_slot));
98 instructions.push(Instruction::Jump { target: loop_label });
99
100 instructions.push(Instruction::Label(done_label));
101 instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(false)));
102 instructions.push(Instruction::Label(end_label));
103 Some(true)
104 }
105 "getCommittee" => {
106 if !args.is_empty() {
107 ctx.record_error(format!(
108 "Neo.getCommittee requires 0 argument(s), got {}",
109 args.len()
110 ));
111 return Some(false);
112 }
113
114 let tmp_id = ctx.next_label();
117 let committee_keys_slot = ctx.allocate_local(
118 format!("__neo_committee_keys_{tmp_id}"),
119 Some(ValueType::Any),
120 );
121 let committee_addrs_slot = ctx.allocate_local(
122 format!("__neo_committee_addrs_{tmp_id}"),
123 Some(ValueType::Array(Box::new(ValueType::Address))),
124 );
125 let index_slot = ctx.allocate_local(
126 format!("__neo_committee_index_{tmp_id}"),
127 Some(ValueType::Integer {
128 signed: false,
129 bits: 256,
130 }),
131 );
132
133 instructions.push(Instruction::CallBuiltin {
134 builtin: BuiltinCall::NativeCall {
135 contract: NativeContract::Neo,
136 method: "getCommittee".to_string(),
137 },
138 arg_count: 0,
139 });
140 instructions.push(Instruction::StoreLocal(committee_keys_slot));
141
142 instructions.push(Instruction::LoadLocal(committee_keys_slot));
143 instructions.push(Instruction::GetSize);
144 instructions.push(Instruction::NewArray {
145 element_type: ValueType::Address,
146 });
147 instructions.push(Instruction::StoreLocal(committee_addrs_slot));
148
149 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
150 BigInt::zero(),
151 )));
152 instructions.push(Instruction::StoreLocal(index_slot));
153
154 let loop_label = ctx.next_label();
155 let done_label = ctx.next_label();
156 instructions.push(Instruction::Label(loop_label));
157 instructions.push(Instruction::LoadLocal(index_slot));
158 instructions.push(Instruction::LoadLocal(committee_keys_slot));
159 instructions.push(Instruction::GetSize);
160 instructions.push(Instruction::BinaryOp(BinaryOperator::Lt));
161 instructions.push(Instruction::JumpIf { target: done_label });
162
163 instructions.push(Instruction::LoadLocal(committee_addrs_slot));
165 instructions.push(Instruction::LoadLocal(index_slot));
166 instructions.push(Instruction::LoadLocal(committee_keys_slot));
167 instructions.push(Instruction::LoadLocal(index_slot));
168 instructions.push(Instruction::ArrayGet);
169 instructions.push(Instruction::CallBuiltin {
170 builtin: BuiltinCall::Syscall("System.Contract.CreateStandardAccount".to_string()),
171 arg_count: 1,
172 });
173 instructions.push(Instruction::ArraySet);
174
175 instructions.push(Instruction::LoadLocal(index_slot));
176 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
177 BigInt::one(),
178 )));
179 instructions.push(Instruction::BinaryOp(BinaryOperator::Add));
180 instructions.push(Instruction::StoreLocal(index_slot));
181 instructions.push(Instruction::Jump { target: loop_label });
182
183 instructions.push(Instruction::Label(done_label));
184 instructions.push(Instruction::LoadLocal(committee_addrs_slot));
185 Some(true)
186 }
187 "getValidators" => {
188 if !args.is_empty() {
189 ctx.record_error(format!(
190 "Neo.getValidators requires 0 argument(s), got {}",
191 args.len()
192 ));
193 return Some(false);
194 }
195
196 let tmp_id = ctx.next_label();
199 let validator_keys_slot = ctx.allocate_local(
200 format!("__neo_validator_keys_{tmp_id}"),
201 Some(ValueType::Any),
202 );
203 let validator_addrs_slot = ctx.allocate_local(
204 format!("__neo_validator_addrs_{tmp_id}"),
205 Some(ValueType::Array(Box::new(ValueType::Address))),
206 );
207 let index_slot = ctx.allocate_local(
208 format!("__neo_validator_index_{tmp_id}"),
209 Some(ValueType::Integer {
210 signed: false,
211 bits: 256,
212 }),
213 );
214
215 instructions.push(Instruction::CallBuiltin {
216 builtin: BuiltinCall::NativeCall {
217 contract: NativeContract::Neo,
218 method: "getNextBlockValidators".to_string(),
219 },
220 arg_count: 0,
221 });
222 instructions.push(Instruction::StoreLocal(validator_keys_slot));
223
224 instructions.push(Instruction::LoadLocal(validator_keys_slot));
225 instructions.push(Instruction::GetSize);
226 instructions.push(Instruction::NewArray {
227 element_type: ValueType::Address,
228 });
229 instructions.push(Instruction::StoreLocal(validator_addrs_slot));
230
231 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
232 BigInt::zero(),
233 )));
234 instructions.push(Instruction::StoreLocal(index_slot));
235
236 let loop_label = ctx.next_label();
237 let done_label = ctx.next_label();
238 instructions.push(Instruction::Label(loop_label));
239 instructions.push(Instruction::LoadLocal(index_slot));
240 instructions.push(Instruction::LoadLocal(validator_keys_slot));
241 instructions.push(Instruction::GetSize);
242 instructions.push(Instruction::BinaryOp(BinaryOperator::Lt));
243 instructions.push(Instruction::JumpIf { target: done_label });
244
245 instructions.push(Instruction::LoadLocal(validator_addrs_slot));
246 instructions.push(Instruction::LoadLocal(index_slot));
247 instructions.push(Instruction::LoadLocal(validator_keys_slot));
248 instructions.push(Instruction::LoadLocal(index_slot));
249 instructions.push(Instruction::ArrayGet);
250 instructions.push(Instruction::CallBuiltin {
251 builtin: BuiltinCall::Syscall("System.Contract.CreateStandardAccount".to_string()),
252 arg_count: 1,
253 });
254 instructions.push(Instruction::ArraySet);
255
256 instructions.push(Instruction::LoadLocal(index_slot));
257 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
258 BigInt::one(),
259 )));
260 instructions.push(Instruction::BinaryOp(BinaryOperator::Add));
261 instructions.push(Instruction::StoreLocal(index_slot));
262 instructions.push(Instruction::Jump { target: loop_label });
263
264 instructions.push(Instruction::Label(done_label));
265 instructions.push(Instruction::LoadLocal(validator_addrs_slot));
266 Some(true)
267 }
268 "isValidator" => {
269 if args.len() != 1 {
270 ctx.record_error(format!(
271 "Neo.isValidator requires 1 argument(s), got {}",
272 args.len()
273 ));
274 return Some(false);
275 }
276
277 let tmp_id = ctx.next_label();
278 let account_slot = ctx.allocate_local(
279 format!("__neo_is_validator_account_{tmp_id}"),
280 Some(ValueType::Address),
281 );
282 let validators_slot = ctx.allocate_local(
283 format!("__neo_is_validator_keys_{tmp_id}"),
284 Some(ValueType::Any),
285 );
286 let index_slot = ctx.allocate_local(
287 format!("__neo_is_validator_index_{tmp_id}"),
288 Some(ValueType::Integer {
289 signed: false,
290 bits: 256,
291 }),
292 );
293
294 if !lower_expression(&args[0], ctx, instructions) {
295 return Some(false);
296 }
297 instructions.push(Instruction::StoreLocal(account_slot));
298
299 instructions.push(Instruction::CallBuiltin {
300 builtin: BuiltinCall::NativeCall {
301 contract: NativeContract::Neo,
302 method: "getNextBlockValidators".to_string(),
303 },
304 arg_count: 0,
305 });
306 instructions.push(Instruction::StoreLocal(validators_slot));
307
308 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
309 BigInt::zero(),
310 )));
311 instructions.push(Instruction::StoreLocal(index_slot));
312
313 let loop_label = ctx.next_label();
314 let advance_label = ctx.next_label();
315 let done_label = ctx.next_label();
316 let end_label = ctx.next_label();
317
318 instructions.push(Instruction::Label(loop_label));
319 instructions.push(Instruction::LoadLocal(index_slot));
320 instructions.push(Instruction::LoadLocal(validators_slot));
321 instructions.push(Instruction::GetSize);
322 instructions.push(Instruction::BinaryOp(BinaryOperator::Lt));
323 instructions.push(Instruction::JumpIf { target: done_label });
324
325 instructions.push(Instruction::LoadLocal(validators_slot));
326 instructions.push(Instruction::LoadLocal(index_slot));
327 instructions.push(Instruction::ArrayGet);
328 instructions.push(Instruction::CallBuiltin {
329 builtin: BuiltinCall::Syscall("System.Contract.CreateStandardAccount".to_string()),
330 arg_count: 1,
331 });
332 instructions.push(Instruction::LoadLocal(account_slot));
333 instructions.push(Instruction::BinaryOp(BinaryOperator::Eq));
334 instructions.push(Instruction::JumpIf {
335 target: advance_label,
336 });
337
338 instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(true)));
339 instructions.push(Instruction::Jump { target: end_label });
340
341 instructions.push(Instruction::Label(advance_label));
342 instructions.push(Instruction::LoadLocal(index_slot));
343 instructions.push(Instruction::PushLiteral(LiteralValue::Integer(
344 BigInt::one(),
345 )));
346 instructions.push(Instruction::BinaryOp(BinaryOperator::Add));
347 instructions.push(Instruction::StoreLocal(index_slot));
348 instructions.push(Instruction::Jump { target: loop_label });
349
350 instructions.push(Instruction::Label(done_label));
351 instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(false)));
352 instructions.push(Instruction::Label(end_label));
353 Some(true)
354 }
355 _ => None,
356 }
357}