neo_solidity/cli/cli_parts/cli_manifest/permissions/
calls.rs1fn analyze_contract_calls(function: &ir::Function) -> Vec<ContractCallRequirement> {
2 let mut has_contract_calls = false;
3 for block in &function.basic_blocks {
4 for instr in &block.instructions {
5 if matches!(
6 instr,
7 ir::Instruction::CallBuiltin {
8 builtin: ir::BuiltinCall::ContractCall
9 | ir::BuiltinCall::ContractCallWithFlags,
10 ..
11 }
12 ) {
13 has_contract_calls = true;
14 break;
15 }
16 if let ir::Instruction::CallBuiltin {
17 builtin: ir::BuiltinCall::Syscall(name),
18 ..
19 } = instr
20 {
21 if name == "System.Contract.Call" {
22 has_contract_calls = true;
23 break;
24 }
25 }
26 }
27 if has_contract_calls {
28 break;
29 }
30 }
31
32 if !has_contract_calls {
33 return Vec::new();
34 }
35
36 let mut requirements = Vec::new();
37
38 for block in &function.basic_blocks {
39 let mut state = AbstractState::new(function.local_count);
45
46 for instr in &block.instructions {
47 if let ir::Instruction::CallBuiltin { builtin, arg_count } = instr {
48 let (contract_from_end, method_from_end, expected_args) = match builtin {
49 ir::BuiltinCall::ContractCall => (3usize, 2usize, 3usize),
50 ir::BuiltinCall::ContractCallWithFlags => (4usize, 3usize, 4usize),
51 ir::BuiltinCall::Syscall(name) if name == "System.Contract.Call" => {
52 (1usize, 2usize, 4usize)
54 }
55 _ => (0usize, 0usize, 0usize),
56 };
57
58 if expected_args > 0
59 && *arg_count == expected_args
60 && state.stack.len() >= expected_args
61 {
62 let stack_len = state.stack.len();
63 let contract_value = &state.stack[stack_len - contract_from_end];
64 if matches!(contract_value, AbstractValue::ExecutingScriptHash) {
65 if apply_instruction(&mut state, instr).is_err() {
72 state.stack.clear();
73 for slot in &mut state.locals {
74 *slot = AbstractValue::Unknown;
75 }
76 }
77 continue;
78 }
79
80 let contract = match contract_value {
81 AbstractValue::Literal(lit) => descriptor_from_literal(lit),
82 AbstractValue::ExecutingScriptHash | AbstractValue::Unknown => None,
83 };
84 let method = match &state.stack[stack_len - method_from_end] {
85 AbstractValue::Literal(lit) => method_name_from_literal(lit),
86 AbstractValue::ExecutingScriptHash => None,
87 AbstractValue::Unknown => None,
88 };
89 requirements.push(ContractCallRequirement { contract, method });
90 } else if expected_args > 0 {
91 requirements.push(ContractCallRequirement {
94 contract: None,
95 method: None,
96 });
97 }
98 }
99
100 if apply_instruction(&mut state, instr).is_err() {
101 state.stack.clear();
104 for slot in &mut state.locals {
105 *slot = AbstractValue::Unknown;
106 }
107 }
108 }
109 }
110
111 requirements
112}