sway_core/abi_generation/
evm_abi.rs1use sway_types::integer_bits::IntegerBits;
2
3use crate::{
4 asm_generation::EvmAbiResult,
5 decl_engine::DeclId,
6 language::ty::{TyFunctionDecl, TyProgram, TyProgramKind},
7 Engines, TypeArgument, TypeId, TypeInfo,
8};
9
10pub fn generate_abi_program(program: &TyProgram, engines: &Engines) -> EvmAbiResult {
11 match &program.kind {
12 TyProgramKind::Contract { abi_entries, .. } => abi_entries
13 .iter()
14 .map(|x| generate_abi_function(x, engines))
15 .collect(),
16 TyProgramKind::Script { entry_function, .. }
17 | TyProgramKind::Predicate { entry_function, .. } => {
18 vec![generate_abi_function(entry_function, engines)]
19 }
20 _ => vec![],
21 }
22}
23
24fn get_type_str(type_id: &TypeId, engines: &Engines, resolved_type_id: TypeId) -> String {
26 let type_engine = engines.te();
27 if type_id.is_generic_parameter(engines, resolved_type_id) {
28 format!("generic {}", abi_str(&type_engine.get(*type_id), engines))
29 } else {
30 match (
31 &*type_engine.get(*type_id),
32 &*type_engine.get(resolved_type_id),
33 ) {
34 (TypeInfo::Custom { .. }, TypeInfo::Struct { .. }) => {
35 format!("struct {}", abi_str(&type_engine.get(*type_id), engines))
36 }
37 (TypeInfo::Custom { .. }, TypeInfo::Enum { .. }) => {
38 format!("enum {}", abi_str(&type_engine.get(*type_id), engines))
39 }
40 (TypeInfo::Tuple(fields), TypeInfo::Tuple(resolved_fields)) => {
41 assert_eq!(fields.len(), resolved_fields.len());
42 let field_strs = fields
43 .iter()
44 .map(|_| "_".to_string())
45 .collect::<Vec<String>>();
46 format!("({})", field_strs.join(", "))
47 }
48 (TypeInfo::Array(_, length), TypeInfo::Array(_, resolved_length)) => {
49 assert_eq!(
50 length.as_literal_val().unwrap(),
51 resolved_length.as_literal_val().unwrap()
52 );
53 format!("[_; {:?}]", engines.help_out(length))
54 }
55 (TypeInfo::Slice(_), TypeInfo::Slice(_)) => "__slice[_]".into(),
56 (TypeInfo::Custom { .. }, _) => {
57 format!("generic {}", abi_str(&type_engine.get(*type_id), engines))
58 }
59 _ => abi_str(&type_engine.get(*type_id), engines),
60 }
61 }
62}
63
64pub fn abi_str(type_info: &TypeInfo, engines: &Engines) -> String {
65 use TypeInfo::*;
66 let decl_engine = engines.de();
67 match type_info {
68 Unknown => "unknown".into(),
69 Never => "never".into(),
70 UnknownGeneric { name, .. } => name.to_string(),
71 Placeholder(_) => "_".to_string(),
72 TypeParam(param) => format!("typeparam({})", param.name),
73 StringSlice => "str".into(),
74 StringArray(x) => format!("str[{}]", x.val()),
75 UnsignedInteger(x) => match x {
76 IntegerBits::Eight => "uint8",
77 IntegerBits::Sixteen => "uint16",
78 IntegerBits::ThirtyTwo => "uint32",
79 IntegerBits::SixtyFour => "uint64",
80 IntegerBits::V256 => "uint256",
81 }
82 .into(),
83 Boolean => "bool".into(),
84 Custom {
85 qualified_call_path: call_path,
86 ..
87 } => call_path.call_path.suffix.to_string(),
88 Tuple(fields) => {
89 let field_strs = fields
90 .iter()
91 .map(|field| abi_str_type_arg(field, engines))
92 .collect::<Vec<String>>();
93 format!("({})", field_strs.join(", "))
94 }
95 B256 => "uint256".into(),
96 Numeric => "u64".into(), Contract => "contract".into(),
98 ErrorRecovery(_) => "unknown due to error".into(),
99 UntypedEnum(decl_id) => {
100 let decl = engines.pe().get_enum(decl_id);
101 format!("untyped enum {}", decl.name)
102 }
103 UntypedStruct(decl_id) => {
104 let decl = engines.pe().get_struct(decl_id);
105 format!("untyped struct {}", decl.name)
106 }
107 Enum(decl_ref) => {
108 let decl = decl_engine.get_enum(decl_ref);
109 format!("enum {}", decl.call_path.suffix)
110 }
111 Struct(decl_ref) => {
112 let decl = decl_engine.get_struct(decl_ref);
113 format!("struct {}", decl.call_path.suffix)
114 }
115 ContractCaller { abi_name, .. } => {
116 format!("contract caller {abi_name}")
117 }
118 Array(elem_ty, length) => {
119 format!(
120 "{}[{:?}]",
121 abi_str_type_arg(elem_ty, engines),
122 engines.help_out(length),
123 )
124 }
125 RawUntypedPtr => "raw untyped ptr".into(),
126 RawUntypedSlice => "raw untyped slice".into(),
127 Ptr(ty) => {
128 format!("__ptr {}", abi_str_type_arg(ty, engines))
129 }
130 Slice(ty) => {
131 format!("__slice {}", abi_str_type_arg(ty, engines))
132 }
133 Alias { ty, .. } => abi_str_type_arg(ty, engines),
134 TraitType {
135 name,
136 trait_type_id: _,
137 } => format!("trait type {}", name),
138 Ref {
139 to_mutable_value,
140 referenced_type,
141 } => {
142 format!(
143 "__ref {}{}", if *to_mutable_value { "mut " } else { "" },
145 abi_str_type_arg(referenced_type, engines)
146 )
147 }
148 }
149}
150
151pub fn abi_param_type(type_info: &TypeInfo, engines: &Engines) -> ethabi::ParamType {
152 use TypeInfo::*;
153 let type_engine = engines.te();
154 let decl_engine = engines.de();
155 match type_info {
156 StringArray(x) => {
157 ethabi::ParamType::FixedArray(Box::new(ethabi::ParamType::String), x.val())
158 }
159 UnsignedInteger(x) => match x {
160 IntegerBits::Eight => ethabi::ParamType::Uint(8),
161 IntegerBits::Sixteen => ethabi::ParamType::Uint(16),
162 IntegerBits::ThirtyTwo => ethabi::ParamType::Uint(32),
163 IntegerBits::SixtyFour => ethabi::ParamType::Uint(64),
164 IntegerBits::V256 => ethabi::ParamType::Uint(256),
165 },
166 Boolean => ethabi::ParamType::Bool,
167 B256 => ethabi::ParamType::Uint(256),
168 Contract => ethabi::ParamType::Address,
169 Enum { .. } => ethabi::ParamType::Uint(8),
170 Tuple(fields) => ethabi::ParamType::Tuple(
171 fields
172 .iter()
173 .map(|f| abi_param_type(&type_engine.get(f.type_id), engines))
174 .collect::<Vec<ethabi::ParamType>>(),
175 ),
176 Struct(decl_ref) => {
177 let decl = decl_engine.get_struct(decl_ref);
178 ethabi::ParamType::Tuple(
179 decl.fields
180 .iter()
181 .map(|f| abi_param_type(&type_engine.get(f.type_argument.type_id), engines))
182 .collect::<Vec<ethabi::ParamType>>(),
183 )
184 }
185 Array(elem_ty, ..) => ethabi::ParamType::Array(Box::new(abi_param_type(
186 &type_engine.get(elem_ty.type_id),
187 engines,
188 ))),
189 _ => panic!("cannot convert type to Solidity ABI param type: {type_info:?}",),
190 }
191}
192
193fn generate_abi_function(
194 fn_decl_id: &DeclId<TyFunctionDecl>,
195 engines: &Engines,
196) -> ethabi::operation::Operation {
197 let decl_engine = engines.de();
198 let fn_decl = decl_engine.get_function(fn_decl_id);
199 let input_types = fn_decl
201 .parameters
202 .iter()
203 .map(|x| ethabi::Param {
204 name: x.name.to_string(),
205 kind: ethabi::ParamType::Address,
206 internal_type: Some(get_type_str(
207 &x.type_argument.type_id,
208 engines,
209 x.type_argument.type_id,
210 )),
211 })
212 .collect::<Vec<_>>();
213
214 let output_type = ethabi::Param {
216 name: String::default(),
217 kind: ethabi::ParamType::Address,
218 internal_type: Some(get_type_str(
219 &fn_decl.return_type.type_id,
220 engines,
221 fn_decl.return_type.type_id,
222 )),
223 };
224
225 #[allow(deprecated)]
227 ethabi::operation::Operation::Function(ethabi::Function {
228 name: fn_decl.name.as_str().to_string(),
229 inputs: input_types,
230 outputs: vec![output_type],
231 constant: None,
232 state_mutability: ethabi::StateMutability::Payable,
233 })
234}
235
236fn abi_str_type_arg(type_arg: &TypeArgument, engines: &Engines) -> String {
237 abi_str(&engines.te().get(type_arg.type_id), engines)
238}