1pub mod ibc_client;
2pub mod ibc_host;
3pub mod ica_client;
4pub mod polytone_callbacks;
5
6use cosmwasm_schema::cw_serde;
7use cosmwasm_std::{
8 to_json_binary, wasm_execute, Binary, CosmosMsg, Empty, Event, QueryRequest, StdError,
9 StdResult,
10};
11use cw_storage_plus::PrimaryKey;
12use schemars::JsonSchema;
13use serde::Serialize;
14
15use crate::{
16 base::ExecuteMsg,
17 objects::{module::ModuleInfo, TruncatedChainId},
18};
19use polytone_callbacks::{Callback as PolytoneCallback, ErrorResponse, ExecutionResponse};
20
21pub const PACKET_LIFETIME: u64 = 60 * 60;
22
23#[cosmwasm_schema::cw_serde]
26pub struct Callback {
28 pub msg: Binary,
31}
32impl Callback {
35 pub fn new<T: Serialize>(msg: &T) -> StdResult<Self> {
36 Ok(Self {
37 msg: to_json_binary(msg)?,
38 })
39 }
40}
41
42#[cosmwasm_schema::cw_serde]
44pub struct IbcResponseMsg {
46 pub callback: Callback,
48 pub result: IbcResult,
49}
50impl IbcResponseMsg {
53 pub fn into_json_binary(self) -> StdResult<Binary> {
55 let msg = ExecuteMsg::IbcCallback::<Empty, Empty>(self);
56 to_json_binary(&msg)
57 }
58
59 pub fn into_cosmos_msg<T: Into<String>, C>(self, contract_addr: T) -> StdResult<CosmosMsg<C>>
61 where
62 C: Clone + std::fmt::Debug + PartialEq + JsonSchema,
63 {
64 Ok(wasm_execute(
65 contract_addr.into(),
66 &ExecuteMsg::IbcCallback::<Empty, Empty>(self),
67 vec![],
68 )?
69 .into())
70 }
71}
72
73#[cosmwasm_schema::cw_serde]
74pub enum IbcResult {
75 Query {
76 queries: Vec<QueryRequest<ModuleQuery>>,
77 results: Result<Vec<Binary>, ErrorResponse>,
78 },
79
80 Execute {
81 initiator_msg: Binary,
82 result: Result<ExecutionResponse, String>,
83 },
84
85 FatalError(String),
95}
96
97impl IbcResult {
98 pub fn from_query(
99 callback: PolytoneCallback,
100 queries: Vec<QueryRequest<ModuleQuery>>,
101 ) -> Result<Self, StdError> {
102 match callback {
103 PolytoneCallback::Query(q) => Ok(Self::Query {
104 queries,
105 results: q,
106 }),
107 PolytoneCallback::Execute(_) => Err(StdError::generic_err(
108 "Expected a query result, got an execute result",
109 )),
110 PolytoneCallback::FatalError(e) => Ok(Self::FatalError(e)),
111 }
112 }
113
114 pub fn from_execute(
115 callback: PolytoneCallback,
116 initiator_msg: Binary,
117 ) -> Result<Self, StdError> {
118 match callback {
119 PolytoneCallback::Query(_) => Err(StdError::generic_err(
120 "Expected an execution result, got a query result",
121 )),
122 PolytoneCallback::Execute(e) => Ok(Self::Execute {
123 initiator_msg,
124 result: e,
125 }),
126 PolytoneCallback::FatalError(e) => Ok(Self::FatalError(e)),
127 }
128 }
129
130 pub fn get_query_result(&self, index: usize) -> StdResult<(QueryRequest<ModuleQuery>, Binary)> {
132 match &self {
133 IbcResult::Query { queries, results } => {
134 let results = results
135 .as_ref()
136 .map_err(|err| StdError::generic_err(err.error.clone()))?;
137 Ok((queries[index].clone(), results[index].clone()))
138 }
139 IbcResult::Execute { .. } => Err(StdError::generic_err(
140 "expected query, got execute ibc result",
141 )),
142 IbcResult::FatalError(err) => Err(StdError::generic_err(err.to_owned())),
143 }
144 }
145
146 pub fn get_execute_events(&self) -> StdResult<Vec<Event>> {
148 match &self {
149 IbcResult::Execute { result, .. } => {
150 let result = result
151 .as_ref()
152 .map_err(|err| StdError::generic_err(err.clone()))?;
153 let res = result
155 .result
156 .first()
157 .expect("execution response without submsg");
158 Ok(res.events.clone())
159 }
160 IbcResult::Query { .. } => Err(StdError::generic_err(
161 "expected execute, got query ibc result",
162 )),
163 IbcResult::FatalError(err) => Err(StdError::generic_err(err.to_owned())),
164 }
165 }
166}
167
168#[cw_serde]
169pub struct ModuleIbcMsg {
170 pub src_module_info: ModuleIbcInfo,
172 pub msg: Binary,
174}
175
176#[cw_serde]
178pub struct ModuleIbcInfo {
179 pub chain: TruncatedChainId,
181 pub module: ModuleInfo,
183}
184#[cw_serde]
188pub struct ModuleQuery {
189 pub target_module: ibc_client::InstalledModuleIdentification,
191 pub msg: Binary,
193}
194#[cosmwasm_schema::cw_serde]
198pub enum IBCLifecycleComplete {
199 #[serde(rename = "ibc_ack")]
200 IBCAck {
201 channel: String,
203 sequence: u64,
205 ack: String,
207 success: bool,
209 },
210 #[serde(rename = "ibc_timeout")]
211 IBCTimeout {
212 channel: String,
214 sequence: u64,
216 },
217}
218
219#[cosmwasm_schema::cw_serde]
220pub struct ICS20CallbackPayload {
221 pub channel_id: String,
222 pub callback: Callback,
223}
224
225#[cosmwasm_schema::cw_serde]
226pub struct ICS20PacketIdentifier {
227 pub channel_id: String,
228 pub sequence: u64,
229}
230
231impl PrimaryKey<'_> for ICS20PacketIdentifier {
232 type Prefix = String;
234
235 type SubPrefix = String;
237
238 type Suffix = u64;
240
241 type SuperSuffix = u64;
243
244 fn key(&self) -> Vec<cw_storage_plus::Key> {
245 let mut keys = self.channel_id.key();
246 keys.extend(self.sequence.key());
247 keys
248 }
249}