1use crate::erc20::Erc20Token;
2use alloy::primitives::{Address, AddressError, U256};
3use alloy_sol_types::SolValue;
4use cosmwasm_schema::cw_serde;
5use cosmwasm_std::{HexBinary, Uint128};
6
7pub trait EvmAddressLike {}
14
15impl EvmAddressLike for String {}
16
17impl EvmAddressLike for HexBinary {}
18
19impl EvmAddressLike for Address {}
20
21#[cw_serde]
23#[non_exhaustive]
24pub enum EvmMsg<T: EvmAddressLike> {
25 Call {
27 to: T,
29 data: HexBinary,
31 #[serde(skip_serializing_if = "Option::is_none")]
33 value: Option<Uint128>,
34 #[serde(skip_serializing_if = "Option::is_none")]
36 allow_failure: Option<bool>,
37 },
38 DelegateCall {
40 to: T,
42 data: HexBinary,
44 #[serde(skip_serializing_if = "Option::is_none")]
46 value: Option<Uint128>,
47 #[serde(skip_serializing_if = "Option::is_none")]
49 allow_failure: Option<bool>,
50 },
51}
52
53impl<T> EvmMsg<T>
54where
55 T: EvmAddressLike,
56{
57 pub fn call(to: T, data: impl Into<HexBinary>) -> Self {
58 EvmMsg::Call {
59 to,
60 data: data.into(),
61 value: None,
62 allow_failure: None,
63 }
64 }
65
66 pub fn call_with_value(to: T, data: impl Into<HexBinary>, value: Uint128) -> Self {
67 EvmMsg::Call {
68 to,
69 data: data.into(),
70 value: Some(value),
71 allow_failure: None,
72 }
73 }
74
75 pub fn delegate_call(to: T, data: impl Into<HexBinary>) -> Self {
76 EvmMsg::DelegateCall {
77 to,
78 data: data.into(),
79 value: None,
80 allow_failure: None,
81 }
82 }
83}
84
85impl EvmMsg<String> {
86 pub fn check(self) -> Result<EvmMsg<Address>, AddressError> {
88 match self {
89 EvmMsg::Call {
90 to,
91 data,
92 value,
93 allow_failure,
94 } => {
95 let to: Address = Address::parse_checksummed(to, None)?;
96 Ok(EvmMsg::Call {
97 to,
98 data,
99 value,
100 allow_failure,
101 })
102 }
103 EvmMsg::DelegateCall {
104 to,
105 data,
106 value,
107 allow_failure,
108 } => {
109 let to: Address = Address::parse_checksummed(to, None)?;
110 Ok(EvmMsg::DelegateCall {
111 to,
112 data,
113 value,
114 allow_failure,
115 })
116 }
117 }
118 }
119}
120
121impl EvmMsg<Address> {
122 pub fn encode(self) -> Vec<u8> {
123 match self {
124 EvmMsg::Call {
125 to,
126 data,
127 allow_failure,
128 value,
129 } => {
130 let data = data.to_vec();
131 let call = abi_types::CallMessage {
132 to,
133 data: data.to_vec().into(),
134 allowFailure: allow_failure.unwrap_or(false),
135 value: value.map(|v| U256::from(v.u128())).unwrap_or_default(),
136 }
137 .abi_encode();
138 abi_types::EvmMsg {
139 msgType: abi_types::EvmMsgType::Call,
140 message: call.into(),
141 }
142 .abi_encode()
143 }
144 EvmMsg::DelegateCall {
145 to,
146 data,
147 allow_failure,
148 value,
149 } => {
150 let data = data.to_vec();
151 let call = abi_types::CallMessage {
152 to,
153 data: data.to_vec().into(),
154 allowFailure: allow_failure.unwrap_or(false),
155 value: value.map(|v| U256::from(v.u128())).unwrap_or_default(),
156 }
157 .abi_encode();
158 abi_types::EvmMsg {
159 msgType: abi_types::EvmMsgType::DelegateCall,
160 message: call.into(),
161 }
162 .abi_encode()
163 }
164 }
165 }
166
167 #[allow(dead_code)]
168 fn unchecked(self) -> EvmMsg<String> {
169 match self {
170 EvmMsg::Call {
171 to,
172 data,
173 allow_failure,
174 value,
175 } => EvmMsg::Call {
176 to: to.to_string(),
177 data,
178 allow_failure,
179 value,
180 },
181 EvmMsg::DelegateCall {
182 to,
183 data,
184 allow_failure,
185 value,
186 } => EvmMsg::DelegateCall {
187 to: to.to_string(),
188 data,
189 allow_failure,
190 value,
191 },
192 }
193 }
194}
195
196pub(crate) mod abi_types {
197 use alloy_sol_types::sol;
198
199 sol! {
201 struct Packet {
203 string sender;
204 Msg msg;
205 }
206
207 struct Msg {
209 MsgType msgType;
210 bytes[] data;
212 }
213
214 enum MsgType {
216 Execute
217 }
219
220 struct EvmMsg {
223 EvmMsgType msgType;
224 bytes message;
225 }
226
227 enum EvmMsgType {
229 Call,
230 DelegateCall,
231 }
232
233 struct CallMessage {
235 address to;
236 bool allowFailure;
237 uint256 value;
238 bytes data;
239 }
240
241
242 struct ExecuteResult {
243 bool success;
244 bytes data;
245 }
246
247 struct ExecuteResponsePacket {
248 address executedBy;
249 ExecuteResult[] result;
250 }
251
252
253 struct Token {
254 address denom;
255 uint128 amount;
256 }
257
258 }
259}
260
261impl From<abi_types::Token> for Erc20Token<String> {
262 fn from(token: abi_types::Token) -> Self {
263 Erc20Token {
264 address: token.denom.to_string(),
265 amount: token.amount.into(),
266 }
267 }
268}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273
274 mod call_message {
275 use crate::ibc::{Msg, Packet};
276
277 use super::*;
278
279 #[test]
280 fn unchecked_encoding() {
281 let msg = abi_types::CallMessage {
282 to: "0x785B548D3d7064F77A26e479AC7847DBCE0c1B46"
283 .parse()
284 .unwrap(),
285 data: HexBinary::from_hex("b49004e9").unwrap().to_vec().into(),
286 allowFailure: false,
287 value: U256::from(0),
288 };
289
290 let encoded = msg.abi_encode();
291 let actual = HexBinary::from(encoded);
292
293 let expected = HexBinary::from_hex("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000785b548d3d7064f77a26e479ac7847dbce0c1b460000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004b49004e900000000000000000000000000000000000000000000000000000000").unwrap();
294
295 assert_eq!(actual, expected);
296 }
297
298 #[test]
299 fn checked_encoding() {
300 let msg = EvmMsg::call(
301 "0x785B548D3d7064F77A26e479AC7847DBCE0c1B46".to_string(),
302 HexBinary::from_hex("b49004e9").unwrap(),
303 )
304 .check()
305 .unwrap();
306
307 let encoded = msg.encode();
308 let actual = HexBinary::from(encoded);
309
310 let expected = HexBinary::from_hex("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000785b548d3d7064f77a26e479ac7847dbce0c1b460000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004b49004e900000000000000000000000000000000000000000000000000000000").unwrap();
311
312 assert_eq!(actual, expected);
313 }
314
315 const TEST_SENDER: &str =
316 "union1tw2y3uk7fwcjeh208gdwaqd3utkuzmnp2fyvqve00jg8vtyhuhfqsender";
317
318 #[test]
319 fn packet_encoding() {
320 let evm_msg = EvmMsg::call(
321 "0x785B548D3d7064F77A26e479AC7847DBCE0c1B46".to_string(),
322 HexBinary::from_hex("b49004e9").unwrap(),
323 );
324
325 let msg = Msg::Execute {
326 msgs: vec![evm_msg],
327 };
328 let request: Packet = Packet {
329 msg,
330 sender: TEST_SENDER.to_string(),
331 };
332 let encoded = request.encode().unwrap();
333 let actual = HexBinary::from(encoded);
334
335 let expected = HexBinary::from_hex("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000040756e696f6e317477327933756b376677636a65683230386764776171643375746b757a6d6e703266797671766530306a6738767479687568667173656e6465720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000785b548d3d7064f77a26e479ac7847dbce0c1b460000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000004b49004e900000000000000000000000000000000000000000000000000000000").unwrap();
336
337 assert_eq!(actual, expected);
338 }
339 }
340
341 #[test]
342 fn test_address() {
343 EvmMsg::call(
344 "0x785B548D3d7064F77A26e479AC7847DBCE0c1B46".to_string(),
345 HexBinary::from_hex("b49004e9").unwrap(),
346 );
347 }
348}