cw_ica_controller/
helpers.rs

1//! This file contains helper functions for working with this contract from
2//! external contracts.
3
4use schemars::JsonSchema;
5use serde::{Deserialize, Serialize};
6
7use cosmwasm_std::{
8    instantiate2_address, to_json_binary, Addr, Api, CosmosMsg, Env, QuerierWrapper, StdError,
9    StdResult, WasmMsg,
10};
11
12use crate::types::{msg, state};
13
14pub use cw_ica_controller_derive::ica_callback_execute; // re-export for use in macros
15
16/// `CwIcaControllerContract` is a wrapper around Addr that provides helpers
17/// for working with this contract.
18#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
19pub struct CwIcaControllerContract(pub Addr);
20
21/// `CwIcaControllerCodeId` is a wrapper around u64 that provides helpers for
22/// initializing this contract.
23#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
24pub struct CwIcaControllerCode(pub u64);
25
26/// `CwIcaControllerContractQuerier` is a wrapper around [`QuerierWrapper`] that provides
27/// helpers for querying this contract.
28///
29/// This can be constructed by [`CwIcaControllerContract::query`] or [`Self::new`].
30pub struct CwIcaControllerContractQuerier<'a> {
31    querier: &'a QuerierWrapper<'a>,
32    addr: String,
33}
34
35impl CwIcaControllerContract {
36    /// new creates a new [`CwIcaControllerContract`]
37    #[must_use]
38    pub const fn new(addr: Addr) -> Self {
39        Self(addr)
40    }
41
42    /// addr returns the address of the contract
43    #[must_use]
44    pub fn addr(&self) -> Addr {
45        self.0.clone()
46    }
47
48    /// `execute` creates a [`WasmMsg::Execute`] message targeting this contract,
49    ///
50    /// # Errors
51    ///
52    /// This function returns an error if the given message cannot be serialized
53    pub fn execute(&self, msg: impl Into<msg::ExecuteMsg>) -> StdResult<CosmosMsg> {
54        let msg = to_json_binary(&msg.into())?;
55        Ok(WasmMsg::Execute {
56            contract_addr: self.addr().into(),
57            msg,
58            funds: vec![],
59        }
60        .into())
61    }
62
63    /// `query` creates a new [`LightClientContractQuerier`] for this contract.
64    #[must_use]
65    pub fn query<'a>(&self, querier: &'a QuerierWrapper) -> CwIcaControllerContractQuerier<'a> {
66        CwIcaControllerContractQuerier::new(querier, self.addr().into_string())
67    }
68
69    /// `update_admin` creates a [`WasmMsg::UpdateAdmin`] message targeting this contract
70    pub fn update_admin(&self, admin: impl Into<String>) -> CosmosMsg {
71        WasmMsg::UpdateAdmin {
72            contract_addr: self.addr().into(),
73            admin: admin.into(),
74        }
75        .into()
76    }
77
78    /// `clear_admin` creates a [`WasmMsg::ClearAdmin`] message targeting this contract
79    #[must_use]
80    pub fn clear_admin(&self) -> CosmosMsg {
81        WasmMsg::ClearAdmin {
82            contract_addr: self.addr().into(),
83        }
84        .into()
85    }
86
87    /// `migrate` creates a [`WasmMsg::Migrate`] message targeting this contract
88    ///
89    /// # Errors
90    ///
91    /// This function returns an error if the given message cannot be serialized
92    pub fn migrate(
93        &self,
94        msg: impl Into<msg::MigrateMsg>,
95        new_code_id: u64,
96    ) -> StdResult<CosmosMsg> {
97        let msg = to_json_binary(&msg.into())?;
98        Ok(WasmMsg::Migrate {
99            contract_addr: self.addr().into(),
100            new_code_id,
101            msg,
102        }
103        .into())
104    }
105}
106
107impl CwIcaControllerCode {
108    /// new creates a new [`CwIcaControllerCode`]
109    #[must_use]
110    pub const fn new(code_id: u64) -> Self {
111        Self(code_id)
112    }
113
114    /// `code_id` returns the code id of this code
115    #[must_use]
116    pub const fn code_id(&self) -> u64 {
117        self.0
118    }
119
120    /// `instantiate` creates a [`WasmMsg::Instantiate`] message targeting this code
121    ///
122    /// # Errors
123    ///
124    /// This function returns an error if the given message cannot be serialized
125    pub fn instantiate(
126        &self,
127        msg: impl Into<msg::InstantiateMsg>,
128        label: impl Into<String>,
129        admin: Option<impl Into<String>>,
130    ) -> StdResult<CosmosMsg> {
131        let msg = to_json_binary(&msg.into())?;
132        Ok(WasmMsg::Instantiate {
133            code_id: self.code_id(),
134            msg,
135            funds: vec![],
136            label: label.into(),
137            admin: admin.map(Into::into),
138        }
139        .into())
140    }
141
142    /// `instantiate2` returns a [`WasmMsg::Instantiate2`] message targeting this code
143    /// and the contract address.
144    ///
145    /// **Warning**: This function won't work on chains which have substantially changed
146    /// address generation such as Injective, test carefully.
147    ///
148    /// # Errors
149    ///
150    /// This function returns an error if the given message cannot be serialized or
151    /// if the contract address cannot be calculated.
152    #[allow(clippy::too_many_arguments)]
153    pub fn instantiate2(
154        &self,
155        api: &dyn Api,
156        querier: &QuerierWrapper,
157        env: &Env,
158        msg: impl Into<msg::InstantiateMsg>,
159        label: impl Into<String>,
160        admin: Option<impl Into<String>>,
161        salt: impl Into<String>,
162    ) -> StdResult<(CosmosMsg, Addr)> {
163        let salt = salt.into();
164        let code_info = querier.query_wasm_code_info(self.code_id())?;
165        let creator_cannonical = api.addr_canonicalize(env.contract.address.as_str())?;
166
167        let contract_addr = api.addr_humanize(
168            &instantiate2_address(
169                code_info.checksum.as_slice(),
170                &creator_cannonical,
171                salt.as_bytes(),
172            )
173            .map_err(|e| StdError::generic_err(e.to_string()))?,
174        )?;
175
176        let instantiate_msg = WasmMsg::Instantiate2 {
177            code_id: self.code_id(),
178            msg: to_json_binary(&msg.into())?,
179            funds: vec![],
180            label: label.into(),
181            admin: admin.map(Into::into),
182            salt: salt.as_bytes().into(),
183        };
184
185        Ok((instantiate_msg.into(), contract_addr))
186    }
187}
188
189impl<'a> CwIcaControllerContractQuerier<'a> {
190    /// Creates a new [`LightClientContractQuerier`]
191    #[must_use]
192    pub const fn new(querier: &'a QuerierWrapper<'a>, addr: String) -> Self {
193        Self { querier, addr }
194    }
195
196    /// `get_channel` sends a [`msg::QueryMsg::GetChannel`] query to this contract.
197    ///
198    /// # Errors
199    ///
200    /// This function returns an error if the query fails
201    pub fn get_channel(&self) -> StdResult<state::ChannelState> {
202        self.querier
203            .query_wasm_smart(&self.addr, &msg::QueryMsg::GetChannel {})
204    }
205
206    /// `get_contract_state` sends a [`msg::QueryMsg::GetContractState`] query to this contract.
207    ///
208    /// # Errors
209    ///
210    /// This function returns an error if the query fails
211    pub fn get_contract_state(&self) -> StdResult<state::ContractState> {
212        self.querier
213            .query_wasm_smart(&self.addr, &msg::QueryMsg::GetContractState {})
214    }
215
216    /// `ownership` sends a [`msg::QueryMsg::Ownership`] query to this contract.
217    ///
218    /// # Errors
219    /// This function returns an error if the query fails
220    pub fn ownership(&self) -> StdResult<cw_ownable::Ownership<String>> {
221        self.querier
222            .query_wasm_smart(&self.addr, &msg::QueryMsg::Ownership {})
223    }
224}