1use cosmwasm_schema::QueryResponses;
2use cosmwasm_std::{Addr, Binary, CosmosMsg, Deps, Empty, QueryRequest, StdError, Uint64};
3
4use self::state::IbcInfrastructure;
5use crate::{
6 account::{self, ModuleInstallConfig},
7 ibc::{Callback, ModuleQuery},
8 ibc_host::HostAction,
9 objects::{
10 account::AccountId, module::ModuleInfo, module_reference::ModuleReference,
11 registry::RegistryContract, TruncatedChainId,
12 },
13 AbstractError,
14};
15
16use super::{polytone_callbacks, IBCLifecycleComplete};
17
18pub mod state {
19
20 use cosmwasm_std::{Addr, Binary, Coin};
21 use cw_storage_plus::{Item, Map};
22
23 use crate::{
24 ibc::ICS20PacketIdentifier,
25 objects::{
26 account::{AccountSequence, AccountTrace},
27 storage_namespaces, TruncatedChainId,
28 },
29 };
30
31 #[cosmwasm_schema::cw_serde]
33 pub struct IbcInfrastructure {
34 pub polytone_note: Addr,
36 pub remote_abstract_host: String,
38 pub remote_proxy: Option<String>,
40 }
41
42 #[cosmwasm_schema::cw_serde]
43 pub struct AccountCallbackPayload {
44 pub channel_id: String,
45 pub account_address: Addr,
46 pub funds: Coin,
48 pub msgs: Vec<Binary>,
50 }
51
52 pub const IBC_INFRA: Map<&TruncatedChainId, IbcInfrastructure> =
55 Map::new(storage_namespaces::ibc_client::IBC_INFRA);
56 pub const REVERSE_POLYTONE_NOTE: Map<&Addr, TruncatedChainId> =
57 Map::new(storage_namespaces::ibc_client::REVERSE_POLYTONE_NOTE);
58
59 pub const ACCOUNTS: Map<(&AccountTrace, AccountSequence, &TruncatedChainId), String> =
63 Map::new(storage_namespaces::ibc_client::ACCOUNTS);
64
65 pub const ACKS: Item<Vec<String>> = Item::new(storage_namespaces::ibc_client::ACKS);
67 pub const ICS20_ACCOUNT_CALLBACKS: Map<ICS20PacketIdentifier, (Addr, Coin, Vec<Binary>)> =
68 Map::new(storage_namespaces::ibc_client::ICS20_ACCOUNT_CALLBACKS);
69 pub const ICS20_ACCOUNT_CALLBACK_PAYLOAD: Item<AccountCallbackPayload> =
70 Item::new(storage_namespaces::ibc_client::ICS20_ACCOUNT_CALLBACK_PAYLOAD);
71}
72
73#[cosmwasm_schema::cw_serde]
75pub struct InstantiateMsg {}
76
77#[cosmwasm_schema::cw_serde]
78pub struct MigrateMsg {}
79
80#[cosmwasm_schema::cw_serde]
81#[derive(cw_orch::ExecuteFns)]
82pub enum ExecuteMsg {
83 UpdateOwnership(cw_ownable::Action),
85 RegisterInfrastructure {
88 chain: TruncatedChainId,
90 note: String,
92 host: String,
94 },
95 SendFunds {
99 host_chain: TruncatedChainId,
102 receiver: Option<String>,
105 memo: Option<String>,
106 },
107 SendFundsWithActions {
111 host_chain: TruncatedChainId,
114 actions: Vec<Binary>,
118 },
119 Register {
123 host_chain: TruncatedChainId,
126 namespace: Option<String>,
127 install_modules: Vec<ModuleInstallConfig>,
128 },
129 ModuleIbcAction {
132 host_chain: TruncatedChainId,
135 target_module: ModuleInfo,
137 msg: Binary,
139 callback: Option<Callback>,
141 },
142 IbcQuery {
145 host_chain: TruncatedChainId,
148 queries: Vec<QueryRequest<ModuleQuery>>,
150 callback: Callback,
152 },
153 RemoteAction {
157 host_chain: TruncatedChainId,
160 action: HostAction,
162 },
163 RemoveHost { host_chain: TruncatedChainId },
165 Callback(polytone_callbacks::CallbackMessage),
168}
169
170#[cosmwasm_schema::cw_serde]
172pub enum PolytoneNoteExecuteMsg {
173 Query {
177 msgs: Vec<QueryRequest<Empty>>,
178 callback: polytone_callbacks::CallbackRequest,
179 timeout_seconds: Uint64,
180 },
181 Execute {
193 msgs: Vec<CosmosMsg<Empty>>,
194 callback: Option<polytone_callbacks::CallbackRequest>,
195 timeout_seconds: Uint64,
196 },
197}
198
199#[cosmwasm_schema::cw_serde]
201pub enum IbcClientCallback {
202 ModuleRemoteAction {
203 sender_address: String,
204 callback: Callback,
205 initiator_msg: Binary,
206 },
207 ModuleRemoteQuery {
208 sender_address: String,
209 callback: Callback,
210 queries: Vec<QueryRequest<ModuleQuery>>,
211 },
212 CreateAccount {
213 account_id: AccountId,
214 },
215 WhoAmI {},
216}
217
218#[cosmwasm_schema::cw_serde]
222pub struct InstalledModuleIdentification {
223 pub module_info: ModuleInfo,
224 pub account_id: Option<AccountId>,
225}
226
227#[cosmwasm_schema::cw_serde]
228pub struct ModuleAddr {
229 pub reference: ModuleReference,
230 pub address: Addr,
231}
232
233impl InstalledModuleIdentification {
234 pub fn addr(
235 &self,
236 deps: Deps,
237 registry: RegistryContract,
238 ) -> Result<ModuleAddr, AbstractError> {
239 let target_module_resolved =
240 registry.query_module(self.module_info.clone(), &deps.querier)?;
241
242 let no_account_id_error =
243 StdError::generic_err("Account id not specified in installed module definition");
244
245 let target_addr = match &target_module_resolved.reference {
246 ModuleReference::Account(code_id) => {
247 let target_account_id = self.account_id.clone().ok_or(no_account_id_error)?;
248 let account = registry.account(&target_account_id, &deps.querier)?;
249
250 if deps
251 .querier
252 .query_wasm_contract_info(account.addr().as_str())?
253 .code_id
254 == *code_id
255 {
256 account.into_addr()
257 } else {
258 Err(StdError::generic_err(
259 "Account contract doesn't correspond to code id of the account",
260 ))?
261 }
262 }
263 ModuleReference::Native(addr)
264 | ModuleReference::Adapter(addr)
265 | ModuleReference::Service(addr) => addr.clone(),
266 ModuleReference::App(_) | ModuleReference::Standalone(_) => {
267 let target_account_id = self.account_id.clone().ok_or(no_account_id_error)?;
268 let account = registry.account(&target_account_id, &deps.querier)?;
269
270 let module_info: account::ModuleAddressesResponse = deps.querier.query_wasm_smart(
271 account.into_addr(),
272 &account::QueryMsg::ModuleAddresses {
273 ids: vec![self.module_info.id()],
274 },
275 )?;
276 module_info
277 .modules
278 .first()
279 .ok_or(AbstractError::AppNotInstalled(self.module_info.to_string()))?
280 .1
281 .clone()
282 }
283 };
284 Ok(ModuleAddr {
285 reference: target_module_resolved.reference,
286 address: target_addr,
287 })
288 }
289}
290
291#[cosmwasm_schema::cw_serde]
292#[derive(QueryResponses, cw_orch::QueryFns)]
293pub enum QueryMsg {
294 #[returns(cw_ownable::Ownership<Addr> )]
297 Ownership {},
298
299 #[returns(ConfigResponse)]
302 Config {},
303
304 #[returns(HostResponse)]
307 Host { chain_name: TruncatedChainId },
308
309 #[returns(ListAccountsResponse)]
312 ListAccounts {
313 start: Option<(AccountId, String)>,
314 limit: Option<u32>,
315 },
316
317 #[returns(AccountResponse)]
320 #[cw_orch(fn_name("remote_account"))]
321 Account {
322 chain_name: TruncatedChainId,
323 account_id: AccountId,
324 },
325
326 #[returns(ListRemoteHostsResponse)]
329 ListRemoteHosts {},
330
331 #[returns(ListRemoteProxiesResponse)]
334 ListRemoteProxies {},
335
336 #[returns(ListRemoteAccountsResponse)]
339 ListRemoteAccountsByAccountId { account_id: AccountId },
340
341 #[returns(ListIbcInfrastructureResponse)]
344 ListIbcInfrastructures {},
345}
346
347#[cosmwasm_schema::cw_serde]
348pub enum SudoMsg {
349 #[serde(rename = "ibc_lifecycle_complete")]
351 IBCLifecycleComplete(IBCLifecycleComplete),
352}
353#[cosmwasm_schema::cw_serde]
354pub struct ConfigResponse {
355 pub ans_host: Addr,
356 pub registry_address: Addr,
357}
358
359#[cosmwasm_schema::cw_serde]
360pub struct ListAccountsResponse {
361 pub accounts: Vec<(AccountId, TruncatedChainId, String)>,
362}
363
364#[cosmwasm_schema::cw_serde]
365pub struct ListRemoteHostsResponse {
366 pub hosts: Vec<(TruncatedChainId, String)>,
367}
368
369#[cosmwasm_schema::cw_serde]
370pub struct ListRemoteAccountsResponse {
371 pub accounts: Vec<(TruncatedChainId, Option<String>)>,
372}
373
374pub type ListRemoteProxiesResponse = ListRemoteAccountsResponse;
375
376#[cosmwasm_schema::cw_serde]
377pub struct ListIbcInfrastructureResponse {
378 pub counterparts: Vec<(TruncatedChainId, IbcInfrastructure)>,
379}
380
381#[cosmwasm_schema::cw_serde]
382pub struct HostResponse {
383 pub remote_host: String,
384 pub remote_polytone_proxy: Option<String>,
385}
386
387#[cosmwasm_schema::cw_serde]
388pub struct AccountResponse {
389 pub remote_account_addr: Option<String>,
390}
391
392#[cfg(test)]
393mod tests {
394 use cosmwasm_std::{to_json_binary, CosmosMsg, Empty};
395
396 use crate::app::ExecuteMsg;
397 use crate::ibc::{Callback, IbcResponseMsg, IbcResult};
398
399 #[coverage_helper::test]
402 fn test_response_msg_to_callback_msg() {
403 let receiver = "receiver".to_string();
404
405 let result = IbcResult::FatalError("ibc execution error".to_string());
406
407 let response_msg = IbcResponseMsg {
408 callback: Callback::new(&String::from("15")).unwrap(),
409 result,
410 };
411
412 let actual: CosmosMsg<Empty> = response_msg
413 .clone()
414 .into_cosmos_msg(receiver.clone())
415 .unwrap();
416
417 assert_eq!(
418 actual,
419 CosmosMsg::Wasm(cosmwasm_std::WasmMsg::Execute {
420 contract_addr: receiver,
421 msg: to_json_binary(&ExecuteMsg::<Empty>::IbcCallback(response_msg)).unwrap(),
423 funds: vec![],
424 })
425 )
426 }
427}