neo_solidity/ir/expressions/calls/
value_transfer.rs1fn try_lower_value_transfer_helpers(
2 func: &Expression,
3 args: &[Expression],
4 ctx: &mut LoweringContext,
5 instructions: &mut Vec<Instruction>,
6) -> Option<bool> {
7 if let Expression::MemberAccess(_, inner, member) = func {
12 if let Expression::Variable(base) = inner.as_ref() {
13 if base.name == "Neo" && matches!(args.len(), 3 | 4) {
14 let contract = match member.name.as_str() {
15 "transferGas" => NativeContract::Gas,
16 "transferNeo" => NativeContract::Neo,
17 _ => return None,
18 };
19 if !lower_expression(&args[0], ctx, instructions) {
20 return Some(false);
21 }
22 if !lower_expression(&args[1], ctx, instructions) {
23 return Some(false);
24 }
25 if !lower_expression(&args[2], ctx, instructions) {
26 return Some(false);
27 }
28
29 if let Some(data) = args.get(3) {
30 if !lower_expression(data, ctx, instructions) {
31 return Some(false);
32 }
33 } else {
34 instructions.push(Instruction::PushLiteral(LiteralValue::ByteArray(
35 Vec::new(),
36 )));
37 }
38
39 instructions.push(Instruction::CallBuiltin {
40 builtin: BuiltinCall::NativeCall {
41 contract,
42 method: "transfer".to_string(),
43 },
44 arg_count: 4,
45 });
46
47 return Some(true);
48 }
49 }
50 }
51
52 if let Expression::MemberAccess(_, inner, member) = func {
60 if matches!(member.name.as_str(), "transfer" | "send") && args.len() == 1 {
61 let is_address_target = matches!(
62 infer_type_from_expression(inner.as_ref(), ctx),
63 Some(ValueType::Address)
64 );
65
66 if is_address_target {
67 instructions.push(Instruction::CallBuiltin {
69 builtin: BuiltinCall::Syscall(
70 "System.Runtime.GetExecutingScriptHash".to_string(),
71 ),
72 arg_count: 0,
73 });
74
75 if !lower_expression(inner.as_ref(), ctx, instructions) {
76 return Some(false);
77 }
78
79 if !lower_expression(&args[0], ctx, instructions) {
80 return Some(false);
81 }
82
83 instructions.push(Instruction::PushLiteral(LiteralValue::ByteArray(
85 Vec::new(),
86 )));
87
88 instructions.push(Instruction::CallBuiltin {
89 builtin: BuiltinCall::NativeCall {
90 contract: NativeContract::Gas,
91 method: "transfer".to_string(),
92 },
93 arg_count: 4,
94 });
95
96 if member.name == "transfer" {
97 let abort_label = ctx.next_label();
99 let end_label = ctx.next_label();
100 instructions.push(Instruction::JumpIf {
101 target: abort_label,
102 });
103 instructions.push(Instruction::PushLiteral(LiteralValue::Boolean(true)));
104 instructions.push(Instruction::Jump { target: end_label });
105 instructions.push(Instruction::Label(abort_label));
106 instructions.push(Instruction::PushLiteral(LiteralValue::Null));
107 instructions.push(Instruction::Throw);
108 instructions.push(Instruction::Label(end_label));
109 }
110
111 return Some(true);
112 }
113 }
114 }
115
116 None
117}