polytone_evm/
ibc.rs

1use crate::evm::abi_types::{
2    EvmMsg as IEvmMsg, EvmMsgType as IEvmMsgType, ExecuteResponsePacket as IExecuteResponsePacket,
3    ExecuteResult as IExecuteResult, Msg as IMsg, MsgType as IMsgType, Packet as IPacket,
4};
5use alloy::primitives::Address;
6use alloy_sol_types::SolValue;
7use cosmwasm_schema::cw_serde;
8use cosmwasm_std::HexBinary;
9use msg_data::MsgData as _;
10
11use crate::evm::EvmMsg;
12
13pub const VERSION: &str = "polytone-evm-1";
14
15#[cw_serde]
16pub struct Packet {
17    /// Message sender on the note chain.
18    pub sender: String,
19    /// Message to execute on voice chain.
20    pub msg: Msg,
21}
22
23impl Packet {
24    pub fn encode(self) -> Result<Vec<u8>, alloy_sol_types::Error> {
25        Ok(IPacket {
26            sender: self.sender.clone(),
27            msg: self.msg.encode()?,
28        }
29        .abi_encode())
30    }
31    pub fn decode(bytes: impl AsRef<[u8]>) -> Result<Self, alloy_sol_types::Error> {
32        let packet = IPacket::abi_decode(bytes.as_ref(), true)?;
33        Ok(Packet {
34            sender: packet.sender,
35            msg: Msg::decode(&packet.msg)?,
36        })
37    }
38}
39
40#[cw_serde]
41/// Message sent to EVM Voice contract
42pub enum Msg {
43    /// Execute a message on the EVM
44    Execute { msgs: Vec<EvmMsg<String>> },
45}
46
47#[cw_serde]
48pub struct ExecuteResponsePacket {
49    pub executed_by: String,
50    pub result: Vec<ExecuteResult>,
51}
52
53impl ExecuteResponsePacket {
54    pub fn decode_bytes(bz: impl AsRef<[u8]>) -> Result<Self, alloy_sol_types::Error> {
55        let packet = IExecuteResponsePacket::abi_decode(bz.as_ref(), true)?;
56        Ok(ExecuteResponsePacket {
57            executed_by: packet.executedBy.to_checksum(None),
58            result: packet
59                .result
60                .into_iter()
61                .map(|res| ExecuteResult {
62                    success: res.success,
63                    data: HexBinary::from(res.data.to_vec()),
64                })
65                .collect(),
66        })
67    }
68}
69
70#[cw_serde]
71pub struct ExecuteResult {
72    pub success: bool,
73    pub data: HexBinary,
74}
75
76pub mod msg_data {
77    use alloy::primitives::Bytes;
78    use cosmwasm_std::HexBinary;
79
80    use crate::evm::abi_types::CallMessage;
81
82    use super::*;
83
84    /// Trait that identifies encoding messages for EVM
85    pub trait MsgData: Sized {
86        type EvmType: SolValue;
87
88        fn encode(self) -> Result<Self::EvmType, alloy_sol_types::Error> {
89            unimplemented!("Type does not support encoding");
90        }
91        #[allow(unused_variables)]
92        fn decode(evm_type: &Self::EvmType) -> Result<Self, alloy_sol_types::Error> {
93            unimplemented!("Type does not support decoding");
94        }
95    }
96
97    impl MsgData for EvmMsg<Address> {
98        type EvmType = IEvmMsg;
99
100        fn encode(self) -> Result<Self::EvmType, alloy_sol_types::Error> {
101            match &self {
102                EvmMsg::Call { .. } => Ok(IEvmMsg {
103                    msgType: IEvmMsgType::Call,
104                    message: self.encode().into(),
105                }),
106                EvmMsg::DelegateCall { .. } => Ok(IEvmMsg {
107                    msgType: IEvmMsgType::DelegateCall,
108                    message: self.encode().into(),
109                }),
110            }
111        }
112    }
113
114    impl MsgData for EvmMsg<String> {
115        type EvmType = IEvmMsg;
116
117        fn decode(evm_msg: &IEvmMsg) -> Result<Self, alloy_sol_types::Error> {
118            match evm_msg.msgType {
119                IEvmMsgType::Call => {
120                    let call_msg = CallMessage::abi_decode(evm_msg.message.as_ref(), true)?;
121                    Ok(EvmMsg::Call {
122                        to: call_msg.to.to_string(),
123                        data: HexBinary::from(call_msg.data.to_vec()),
124                        allow_failure: Some(call_msg.allowFailure),
125                        value: Some(call_msg.value.to::<u128>().into()),
126                    })
127                }
128                IEvmMsgType::DelegateCall => {
129                    let call_msg = CallMessage::abi_decode(evm_msg.message.as_ref(), true)?;
130                    Ok(EvmMsg::DelegateCall {
131                        to: call_msg.to.to_string(),
132                        data: HexBinary::from(call_msg.data.to_vec()),
133                        allow_failure: Some(call_msg.allowFailure),
134                        value: Some(call_msg.value.to::<u128>().into()),
135                    })
136                }
137                IEvmMsgType::__Invalid => panic!(),
138            }
139        }
140    }
141
142    impl MsgData for Msg {
143        type EvmType = IMsg;
144
145        fn encode(self) -> Result<Self::EvmType, alloy_sol_types::Error> {
146            match self {
147                Msg::Execute { msgs } => Ok(IMsg {
148                    msgType: IMsgType::Execute,
149                    data: msgs
150                        .into_iter()
151                        .map(|m| m.check().unwrap().encode().into())
152                        .collect::<Vec<Bytes>>(),
153                }),
154            }
155        }
156
157        fn decode(msg: &IMsg) -> Result<Self, alloy_sol_types::Error> {
158            match msg.msgType {
159                IMsgType::Execute => {
160                    let mut msgs = Vec::with_capacity(msg.data.len());
161                    for data in &msg.data {
162                        let evm_msg = IEvmMsg::abi_decode(data, true)?;
163                        msgs.push(EvmMsg::decode(&evm_msg)?);
164                    }
165                    Ok(Msg::Execute { msgs })
166                }
167                IMsgType::__Invalid => panic!(),
168            }
169        }
170    }
171
172    impl MsgData for ExecuteResponsePacket {
173        type EvmType = IExecuteResponsePacket;
174        fn decode(evm_type: &Self::EvmType) -> Result<Self, alloy_sol_types::Error> {
175            let mut results = Vec::with_capacity(evm_type.result.len());
176            for res in &evm_type.result {
177                results.push(ExecuteResult::decode(res)?);
178            }
179            Ok(ExecuteResponsePacket {
180                executed_by: evm_type.executedBy.to_string(),
181                result: results,
182            })
183        }
184    }
185
186    impl MsgData for ExecuteResult {
187        type EvmType = IExecuteResult;
188        fn decode(evm_type: &Self::EvmType) -> Result<Self, alloy_sol_types::Error> {
189            Ok(ExecuteResult {
190                success: evm_type.success,
191                data: HexBinary::from(evm_type.data.to_vec()),
192            })
193        }
194    }
195}