abstract_adapter/
lib.rs

1//! # Abstract Adapter
2//!
3//! Basis for an interfacing contract to an external service.
4#![cfg_attr(all(coverage_nightly, test), feature(coverage_attribute))]
5use cosmwasm_std::{Empty, Response};
6
7pub type AdapterResult<C = Empty> = Result<Response<C>, AdapterError>;
8// Default to Empty
9
10pub use error::AdapterError;
11
12pub use crate::state::AdapterContract;
13
14// Useful re-exports
15pub use abstract_std as std;
16// re-export objects specifically
17pub use abstract_sdk as sdk;
18pub use abstract_std::objects;
19pub mod traits {
20    pub use abstract_sdk::{features::*, prelude::*};
21}
22
23mod interface;
24pub use abstract_interface;
25#[cfg(feature = "test-utils")]
26pub use abstract_testing;
27
28mod endpoints;
29pub mod error;
30/// Abstract SDK trait implementations
31pub mod features;
32mod handler;
33pub mod msgs;
34#[cfg(feature = "schema")]
35pub mod schema;
36pub mod state;
37
38#[cfg(feature = "test-utils")]
39pub mod mock {
40    use abstract_sdk::{base::InstantiateEndpoint, AbstractSdkError};
41    use abstract_std::{adapter::*, objects::dependency::StaticDependency};
42    use abstract_testing::{mock_env_validated, prelude::*, TEST_VERSION};
43    use cosmwasm_std::{testing::*, OwnedDeps, Response, StdError};
44    use cw_storage_plus::Item;
45    use thiserror::Error;
46
47    use crate::{AdapterContract, AdapterError};
48
49    crate::adapter_msg_types!(MockAdapterContract, MockExecMsg, MockQueryMsg);
50
51    pub const TEST_METADATA: &str = "test_metadata";
52    pub const TEST_AUTHORIZED_ADDR: &str = "test_authorized_address";
53
54    #[derive(Error, Debug, PartialEq)]
55    pub enum MockError {
56        #[error(transparent)]
57        Std(#[from] StdError),
58
59        #[error(transparent)]
60        Adapter(#[from] AdapterError),
61
62        #[error(transparent)]
63        Abstract(#[from] abstract_std::AbstractError),
64
65        #[error(transparent)]
66        AbstractSdk(#[from] AbstractSdkError),
67    }
68
69    #[cosmwasm_schema::cw_serde]
70    pub struct MockInitMsg {}
71
72    #[cosmwasm_schema::cw_serde]
73    pub struct MockExecMsg {}
74
75    #[cosmwasm_schema::cw_serde]
76    #[derive(cw_orch::QueryFns, cosmwasm_schema::QueryResponses)]
77    pub enum MockQueryMsg {
78        #[returns(ReceivedIbcCallbackStatus)]
79        GetReceivedIbcCallbackStatus {},
80
81        #[returns(String)]
82        GetSomething {},
83    }
84
85    #[cosmwasm_schema::cw_serde]
86    pub struct ReceivedIbcCallbackStatus {
87        pub received: bool,
88    }
89
90    #[cosmwasm_schema::cw_serde]
91    pub struct MockSudoMsg {}
92
93    /// Mock Adapter type
94    pub type MockAdapterContract =
95        AdapterContract<MockError, MockInitMsg, MockExecMsg, MockQueryMsg, MockSudoMsg>;
96
97    pub const MOCK_DEP: StaticDependency = StaticDependency::new("module_id", &[">0.0.0"]);
98
99    // Easy way to see if an ibc-callback was actually received.
100    pub const IBC_CALLBACK_RECEIVED: Item<bool> = Item::new("ibc_callback_received");
101    /// use for testing
102    pub const MOCK_ADAPTER: MockAdapterContract =
103        MockAdapterContract::new(TEST_MODULE_ID, TEST_VERSION, Some(TEST_METADATA))
104            .with_instantiate(|deps, _, _, _, _| {
105                IBC_CALLBACK_RECEIVED.save(deps.storage, &false)?;
106
107                Ok(Response::new().set_data("mock_init".as_bytes()))
108            })
109            .with_execute(|_, _, _, _, _| Ok(Response::new().set_data("mock_exec".as_bytes())))
110            .with_query(|deps, _, _, msg| match msg {
111                MockQueryMsg::GetReceivedIbcCallbackStatus {} => {
112                    to_json_binary(&ReceivedIbcCallbackStatus {
113                        received: IBC_CALLBACK_RECEIVED.load(deps.storage)?,
114                    })
115                    .map_err(Into::into)
116                }
117                MockQueryMsg::GetSomething {} => to_json_binary("mock_query").map_err(Into::into),
118            })
119            .with_sudo(|_, _, _, _| Ok(Response::new().set_data("mock_sudo".as_bytes())))
120            .with_ibc_callback(|deps, _, _, _, _| {
121                IBC_CALLBACK_RECEIVED.save(deps.storage, &true).unwrap();
122                Ok(Response::new().set_data("mock_callback".as_bytes()))
123            })
124            .with_replies(&[(1u64, |_, _, _, msg| {
125                #[allow(deprecated)]
126                Ok(Response::new().set_data(msg.result.unwrap().data.unwrap()))
127            })]);
128
129    pub type AdapterMockResult = Result<(), MockError>;
130    // export these for upload usage
131    crate::export_endpoints!(MOCK_ADAPTER, MockAdapterContract);
132
133    crate::cw_orch_interface!(MOCK_ADAPTER, MockAdapterContract, MockInitMsg, MockAdapterI);
134    pub fn mock_init(
135        deps: &mut OwnedDeps<MockStorage, MockApi, MockQuerier>,
136    ) -> Result<Response, MockError> {
137        let adapter = MOCK_ADAPTER;
138        let abstr = AbstractMockAddrs::new(deps.api);
139
140        let info = message_info(&abstr.owner, &[]);
141        let env = mock_env_validated(deps.api);
142        let init_msg = InstantiateMsg {
143            base: BaseInstantiateMsg {
144                registry_address: abstr.registry.to_string(),
145            },
146            module: MockInitMsg {},
147        };
148        adapter.instantiate(deps.as_mut(), env, info, init_msg)
149    }
150
151    pub fn mock_init_custom(
152        deps: &mut OwnedDeps<MockStorage, MockApi, MockQuerier>,
153        module: MockAdapterContract,
154    ) -> Result<Response, MockError> {
155        let abstr = AbstractMockAddrs::new(deps.api);
156
157        let info = message_info(&abstr.owner, &[]);
158        let env = mock_env_validated(deps.api);
159        let init_msg = InstantiateMsg {
160            base: BaseInstantiateMsg {
161                registry_address: abstr.registry.to_string(),
162            },
163            module: MockInitMsg {},
164        };
165        module.instantiate(deps.as_mut(), env, info, init_msg)
166    }
167
168    /// Generate a cw-orch instance for a mock adapter
169    /// - $name: name of the contract (&str)
170    /// - $id: id of the contract (&str)
171    /// - $version: version of the contract (&str)
172    /// - $deps: dependencies of the contract (&[StaticDependency])
173    #[macro_export]
174    macro_rules! gen_adapter_mock {
175    ($name:ident, $id:expr, $version:expr, $deps:expr) => {
176        use $crate::std::adapter::*;
177        use $crate::sdk::base::Handler;
178        use ::cosmwasm_std::Empty;
179        use ::abstract_adapter::mock::{MockExecMsg, MockQueryMsg, MockInitMsg, MockAdapterContract, MockError};
180        use ::cw_orch::environment::CwEnv;
181
182        const MOCK_ADAPTER: ::abstract_adapter::mock::MockAdapterContract = ::abstract_adapter::mock::MockAdapterContract::new($id, $version, None)
183        .with_dependencies($deps)
184        .with_execute(|_, _, _, _, _| Ok(::cosmwasm_std::Response::new().set_data("mock_exec".as_bytes())));
185
186        fn instantiate(
187            deps: ::cosmwasm_std::DepsMut,
188            env: ::cosmwasm_std::Env,
189            info: ::cosmwasm_std::MessageInfo,
190            msg: <::abstract_adapter::mock::MockAdapterContract as ::abstract_sdk::base::InstantiateEndpoint>::InstantiateMsg,
191        ) -> Result<::cosmwasm_std::Response, <::abstract_adapter::mock::MockAdapterContract as ::abstract_sdk::base::Handler>::Error> {
192            use ::abstract_sdk::base::InstantiateEndpoint;
193            MOCK_ADAPTER.instantiate(deps, env, info, msg)
194        }
195
196        /// Execute entrypoint
197        fn execute(
198            deps: ::cosmwasm_std::DepsMut,
199            env: ::cosmwasm_std::Env,
200            info: ::cosmwasm_std::MessageInfo,
201            msg: <::abstract_adapter::mock::MockAdapterContract as ::abstract_sdk::base::ExecuteEndpoint>::ExecuteMsg,
202        ) -> Result<::cosmwasm_std::Response, <::abstract_adapter::mock::MockAdapterContract as ::abstract_sdk::base::Handler>::Error> {
203            use ::abstract_sdk::base::ExecuteEndpoint;
204            MOCK_ADAPTER.execute(deps, env, info, msg)
205        }
206
207        /// Query entrypoint
208        fn query(
209            deps: ::cosmwasm_std::Deps,
210            env: ::cosmwasm_std::Env,
211            msg: <::abstract_adapter::mock::MockAdapterContract as ::abstract_sdk::base::QueryEndpoint>::QueryMsg,
212        ) -> Result<::cosmwasm_std::Binary, <::abstract_adapter::mock::MockAdapterContract as ::abstract_sdk::base::Handler>::Error> {
213            use ::abstract_sdk::base::QueryEndpoint;
214            MOCK_ADAPTER.query(deps, env, msg)
215        }
216
217        type Exec = $crate::std::adapter::ExecuteMsg<MockExecMsg>;
218        type Query = $crate::std::adapter::QueryMsg<MockQueryMsg>;
219        type Init = $crate::std::adapter::InstantiateMsg<MockInitMsg>;
220        #[cw_orch::interface(Init, Exec, Query, Empty)]
221        pub struct $name ;
222
223        impl <T: ::cw_orch::prelude::CwEnv> ::abstract_interface::AdapterDeployer<T, MockInitMsg> for $name <T> {}
224
225        impl<Chain> $crate::abstract_interface::RegisteredModule for $name<Chain> {
226            type InitMsg = MockInitMsg;
227
228            fn module_id<'a>() -> &'a str {
229                $crate::traits::ModuleIdentification::module_id(&MOCK_ADAPTER)
230            }
231
232            fn module_version<'a>() -> &'a str {
233                MOCK_ADAPTER.version()
234            }
235
236            fn dependencies<'a>() -> &'a [$crate::objects::dependency::StaticDependency] {
237                MOCK_ADAPTER.dependencies()
238            }
239        }
240
241        impl<T: ::cw_orch::prelude::CwEnv> Uploadable for $name<T> {
242            fn wrapper() -> <Mock as ::cw_orch::environment::TxHandler>::ContractSource {
243                Box::new(ContractWrapper::<
244                    Exec,
245                    _,
246                    _,
247                    _,
248                    _,
249                    _,
250                >::new_with_empty(
251                    self::execute,
252                    self::instantiate,
253                    self::query,
254                ))
255            }
256        }
257
258        impl<Chain: ::cw_orch::environment::CwEnv> $name <Chain> {
259            pub fn new_test(chain: Chain) -> Self {
260                Self(
261                    ::cw_orch::contract::Contract::new($id, chain),
262                )
263            }
264        }
265    };
266}
267}