abstract_interchain_tests/
module_to_module_interactions.rs

1pub use abstract_std::app;
2use abstract_std::{
3    ibc::{CallbackInfo, CallbackResult, ModuleIbcMsg},
4    ibc_client::{self},
5    objects::module::ModuleInfo,
6    IBC_CLIENT,
7};
8use cosmwasm_schema::{cw_serde, QueryResponses};
9pub use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
10use cosmwasm_std::{
11    from_json, to_json_binary, wasm_execute, AllBalanceResponse, Coin, Response, StdError,
12};
13use cw_controllers::AdminError;
14use cw_storage_plus::Item;
15
16pub type AppTestResult = Result<(), MockError>;
17
18abstract_app::app_msg_types!(MockAppContract, MockExecMsg, MockQueryMsg);
19
20#[cosmwasm_schema::cw_serde]
21pub struct MockInitMsg {}
22
23#[cosmwasm_schema::cw_serde]
24#[derive(cw_orch::ExecuteFns)]
25#[impl_into(ExecuteMsg)]
26pub enum MockExecMsg {
27    DoSomething {},
28    DoSomethingAdmin {},
29    DoSomethingIbc {
30        remote_chain: String,
31        target_module: ModuleInfo,
32    },
33    QuerySomethingIbc {
34        remote_chain: String,
35        address: String,
36    },
37}
38
39#[cosmwasm_schema::cw_serde]
40#[derive(cw_orch::QueryFns)]
41#[impl_into(QueryMsg)]
42#[derive(QueryResponses)]
43pub enum MockQueryMsg {
44    #[returns(ReceivedIbcCallbackStatus)]
45    GetReceivedIbcCallbackStatus {},
46
47    #[returns(ReceivedIbcQueryCallbackStatus)]
48    GetReceivedIbcQueryCallbackStatus {},
49
50    #[returns(ReceivedIbcModuleStatus)]
51    GetReceivedIbcModuleStatus {},
52}
53
54#[cosmwasm_schema::cw_serde]
55pub struct ReceivedIbcCallbackStatus {
56    pub received: bool,
57}
58
59#[cosmwasm_schema::cw_serde]
60pub struct ReceivedIbcQueryCallbackStatus {
61    pub balance: Vec<Coin>,
62}
63
64#[cosmwasm_schema::cw_serde]
65pub struct ReceivedIbcModuleStatus {
66    pub received: ModuleInfo,
67}
68
69#[cosmwasm_schema::cw_serde]
70pub struct MockMigrateMsg;
71
72#[cosmwasm_schema::cw_serde]
73pub struct MockReceiveMsg;
74
75#[cosmwasm_schema::cw_serde]
76pub struct MockSudoMsg;
77
78use abstract_sdk::{AbstractSdkError, ModuleInterface};
79use thiserror::Error;
80
81use abstract_app::{AppContract, AppError};
82
83#[derive(Error, Debug, PartialEq)]
84pub enum MockError {
85    #[error("{0}")]
86    Std(#[from] StdError),
87
88    #[error("{0}")]
89    DappError(#[from] AppError),
90
91    #[error("{0}")]
92    Abstract(#[from] abstract_std::AbstractError),
93
94    #[error("{0}")]
95    AbstractSdk(#[from] AbstractSdkError),
96
97    #[error("{0}")]
98    Admin(#[from] AdminError),
99}
100
101pub type MockAppContract = AppContract<
102    // MockModule,
103    MockError,
104    MockInitMsg,
105    MockExecMsg,
106    MockQueryMsg,
107    MockMigrateMsg,
108    MockReceiveMsg,
109    MockSudoMsg,
110>;
111
112#[cw_serde]
113pub struct IbcModuleToModuleMsg {
114    ibc_msg: String,
115}
116
117// Easy way to see if an ibc-callback was actually received.
118pub const IBC_CALLBACK_RECEIVED: Item<bool> = Item::new("ibc_callback_received");
119// Easy way to see if an module ibc called was actually received.
120pub const MODULE_IBC_RECEIVED: Item<ModuleInfo> = Item::new("module_ibc_received");
121
122// Easy way to see if an ibc-callback was actually received.
123pub const IBC_CALLBACK_QUERY_RECEIVED: Item<Vec<Coin>> = Item::new("ibc_callback_query_received");
124
125pub const fn mock_app(id: &'static str, version: &'static str) -> MockAppContract {
126    MockAppContract::new(id, version, None)
127        .with_instantiate(|deps, _, _, _, _| {
128            IBC_CALLBACK_RECEIVED.save(deps.storage, &false)?;
129            Ok(Response::new().set_data("mock_init".as_bytes()))
130        })
131        .with_execute(|deps, _env, _, app, msg| match msg {
132            MockExecMsg::DoSomethingIbc {
133                remote_chain,
134                target_module,
135            } => {
136                let ibc_client_addr = app.modules(deps.as_ref()).module_address(IBC_CLIENT)?;
137                // We send an IBC Client module message
138                let msg = wasm_execute(
139                    ibc_client_addr,
140                    &ibc_client::ExecuteMsg::ModuleIbcAction {
141                        host_chain: remote_chain,
142                        target_module,
143                        msg: to_json_binary(&IbcModuleToModuleMsg {
144                            ibc_msg: "module_to_module:msg".to_string(),
145                        })
146                        .unwrap(),
147                        callback_info: Some(CallbackInfo {
148                            id: "c_id".to_string(),
149                            msg: None,
150                        }),
151                    },
152                    vec![],
153                )?;
154
155                Ok(Response::new().add_message(msg))
156            }
157            MockExecMsg::QuerySomethingIbc {
158                address,
159                remote_chain,
160            } => {
161                let ibc_client_addr = app.modules(deps.as_ref()).module_address(IBC_CLIENT)?;
162                // We send an IBC Client module message
163                let msg = wasm_execute(
164                    ibc_client_addr,
165                    &ibc_client::ExecuteMsg::IbcQuery {
166                        host_chain: remote_chain,
167                        callback_info: CallbackInfo {
168                            id: "query_id".to_string(),
169                            msg: None,
170                        },
171                        query: cosmwasm_std::QueryRequest::Bank(
172                            cosmwasm_std::BankQuery::AllBalances { address },
173                        ),
174                    },
175                    vec![],
176                )?;
177
178                Ok(Response::new().add_message(msg))
179            }
180            _ => Ok(Response::new().set_data("mock_exec".as_bytes())),
181        })
182        .with_query(|deps, _, _, msg| match msg {
183            MockQueryMsg::GetReceivedIbcCallbackStatus {} => {
184                to_json_binary(&ReceivedIbcCallbackStatus {
185                    received: IBC_CALLBACK_RECEIVED.load(deps.storage)?,
186                })
187                .map_err(Into::into)
188            }
189            MockQueryMsg::GetReceivedIbcModuleStatus {} => {
190                to_json_binary(&ReceivedIbcModuleStatus {
191                    received: MODULE_IBC_RECEIVED.load(deps.storage)?,
192                })
193                .map_err(Into::into)
194            }
195            MockQueryMsg::GetReceivedIbcQueryCallbackStatus {} => {
196                to_json_binary(&ReceivedIbcQueryCallbackStatus {
197                    balance: IBC_CALLBACK_QUERY_RECEIVED.load(deps.storage)?,
198                })
199                .map_err(Into::into)
200            }
201        })
202        .with_sudo(|_, _, _, _| Ok(Response::new().set_data("mock_sudo".as_bytes())))
203        .with_receive(|_, _, _, _, _| Ok(Response::new().set_data("mock_receive".as_bytes())))
204        .with_ibc_callbacks(&[
205            ("c_id", |deps, _, _, _, _| {
206                IBC_CALLBACK_RECEIVED.save(deps.storage, &true).unwrap();
207                Ok(Response::new().add_attribute("mock_callback", "executed"))
208            }),
209            ("query_id", |deps, _, _, _, msg| match msg.result {
210                CallbackResult::Query { query: _, result } => {
211                    let result = result.unwrap()[0].clone();
212                    let deser: AllBalanceResponse = from_json(result)?;
213                    IBC_CALLBACK_QUERY_RECEIVED
214                        .save(deps.storage, &deser.amount)
215                        .unwrap();
216                    Ok(Response::new().add_attribute("mock_callback_query", "executed"))
217                }
218                _ => panic!("Expected query result"),
219            }),
220        ])
221        .with_replies(&[(1u64, |_, _, _, msg| {
222            Ok(Response::new().set_data(msg.result.unwrap().data.unwrap()))
223        })])
224        .with_migrate(|_, _, _, _| Ok(Response::new().set_data("mock_migrate".as_bytes())))
225        .with_module_ibc(|deps, _, _, msg| {
226            let ModuleIbcMsg { source_module, .. } = msg;
227            // We save the module info status
228            MODULE_IBC_RECEIVED.save(deps.storage, &source_module)?;
229            Ok(Response::new().add_attribute("mock_module_ibc", "executed"))
230        })
231}
232
233pub mod origin_app {
234    use abstract_testing::addresses::{TEST_MODULE_ID, TEST_VERSION};
235
236    use super::{mock_app, MockAppContract};
237    pub const MOCK_APP_ORIGIN: MockAppContract = mock_app(TEST_MODULE_ID, TEST_VERSION);
238    abstract_app::cw_orch_interface!(MOCK_APP_ORIGIN, MockAppContract, MockAppOriginI);
239}
240
241pub mod remote_app {
242    use super::{mock_app, MockAppContract};
243
244    pub const TEST_MODULE_ID_REMOTE: &str = "tester:test-module-id-remote";
245    pub const TEST_VERSION_REMOTE: &str = "0.45.7";
246    pub const MOCK_APP_REMOTE: MockAppContract =
247        mock_app(TEST_MODULE_ID_REMOTE, TEST_VERSION_REMOTE);
248    abstract_app::cw_orch_interface!(MOCK_APP_REMOTE, MockAppContract, MockAppRemoteI);
249}
250
251#[cfg(test)]
252pub mod test {
253
254    fn assert_remote_module_call_status(
255        app: &MockAppRemoteI<MockBech32>,
256        source_module_expected: Option<ModuleInfo>,
257    ) -> AnyResult<()> {
258        let source_module = app
259            .get_received_ibc_module_status()
260            .map(|s| s.received)
261            .ok();
262
263        assert_eq!(source_module, source_module_expected);
264        Ok(())
265    }
266
267    fn assert_callback_status(app: &MockAppOriginI<MockBech32>, status: bool) -> AnyResult<()> {
268        let get_received_ibc_callback_status_res: ReceivedIbcCallbackStatus =
269            app.get_received_ibc_callback_status()?;
270
271        assert_eq!(
272            ReceivedIbcCallbackStatus { received: status },
273            get_received_ibc_callback_status_res
274        );
275        Ok(())
276    }
277
278    fn assert_query_callback_status(
279        app: &MockAppOriginI<MockBech32>,
280        balance: Vec<Coin>,
281    ) -> AnyResult<()> {
282        let get_received_ibc_query_callback_status_res: ReceivedIbcQueryCallbackStatus =
283            app.get_received_ibc_query_callback_status()?;
284
285        assert_eq!(
286            ReceivedIbcQueryCallbackStatus { balance },
287            get_received_ibc_query_callback_status_res
288        );
289        Ok(())
290    }
291    use crate::{
292        interchain_accounts::create_test_remote_account,
293        module_to_module_interactions::{
294            origin_app::interface::MockAppOriginI,
295            remote_app::{interface::MockAppRemoteI, TEST_MODULE_ID_REMOTE, TEST_VERSION_REMOTE},
296            MockExecMsgFns, MockInitMsg, MockQueryMsgFns, ReceivedIbcCallbackStatus,
297            ReceivedIbcQueryCallbackStatus,
298        },
299        setup::{
300            ibc_abstract_setup, ibc_connect_polytone_and_abstract, mock_test::logger_test_init,
301        },
302        JUNO, STARGAZE,
303    };
304    use abstract_app::objects::{chain_name::ChainName, module::ModuleInfo};
305    use abstract_interface::{
306        AppDeployer, DeployStrategy, Manager, ManagerQueryFns, VCExecFns, VCQueryFns,
307    };
308    use abstract_std::manager::{self, ModuleInstallConfig};
309    use abstract_testing::addresses::{TEST_MODULE_ID, TEST_NAMESPACE, TEST_VERSION};
310    use anyhow::Result as AnyResult;
311    use cosmwasm_std::{coins, to_json_binary};
312    use cw_orch::prelude::*;
313    use cw_orch_interchain::{prelude::*, types::IbcPacketOutcome};
314
315    #[test]
316    fn target_module_must_exist() -> AnyResult<()> {
317        logger_test_init();
318        let mock_interchain =
319            MockBech32InterchainEnv::new(vec![(JUNO, "juno"), (STARGAZE, "stargaze")]);
320
321        // We just verified all steps pass
322        let (abstr_origin, _abstr_remote) = ibc_abstract_setup(&mock_interchain, JUNO, STARGAZE)?;
323        ibc_connect_polytone_and_abstract(&mock_interchain, STARGAZE, JUNO)?;
324
325        let remote_name = ChainName::from_chain_id(STARGAZE).to_string();
326
327        let (origin_account, _remote_account_id) =
328            create_test_remote_account(&abstr_origin, JUNO, STARGAZE, &mock_interchain, None)?;
329
330        let app = MockAppOriginI::new(
331            TEST_MODULE_ID,
332            abstr_origin.version_control.get_chain().clone(),
333        );
334
335        abstr_origin.version_control.claim_namespace(
336            origin_account.manager.config()?.account_id,
337            TEST_NAMESPACE.to_owned(),
338        )?;
339
340        app.deploy(TEST_VERSION.parse()?, DeployStrategy::Try)?;
341
342        origin_account.install_app(&app, &MockInitMsg {}, None)?;
343
344        // The user on origin chain wants to change the account description
345        let target_module_info =
346            ModuleInfo::from_id(TEST_MODULE_ID_REMOTE, TEST_VERSION_REMOTE.into())?;
347        let ibc_action_result = app.do_something_ibc(remote_name, target_module_info.clone())?;
348
349        let ibc_result = mock_interchain.wait_ibc(JUNO, ibc_action_result)?;
350
351        let expected_error_outcome = format!(
352            "Module {} does not have a stored module reference",
353            target_module_info
354        );
355        match &ibc_result.packets[0].outcome {
356            IbcPacketOutcome::Timeout { .. } => {
357                panic!("Expected a failed ack not a timeout !")
358            }
359            IbcPacketOutcome::Success { ack, .. } => assert!(String::from_utf8_lossy(ack)
360                .to_string()
361                .contains(&expected_error_outcome)),
362        }
363
364        Ok(())
365    }
366
367    #[test]
368    fn target_account_must_have_module_installed() -> AnyResult<()> {
369        logger_test_init();
370        let mock_interchain =
371            MockBech32InterchainEnv::new(vec![(JUNO, "juno"), (STARGAZE, "stargaze")]);
372
373        // We just verified all steps pass
374        let (abstr_origin, abstr_remote) = ibc_abstract_setup(&mock_interchain, JUNO, STARGAZE)?;
375        ibc_connect_polytone_and_abstract(&mock_interchain, STARGAZE, JUNO)?;
376
377        let remote_name = ChainName::from_chain_id(STARGAZE).to_string();
378
379        let (origin_account, _remote_account_id) =
380            create_test_remote_account(&abstr_origin, JUNO, STARGAZE, &mock_interchain, None)?;
381
382        let (remote_account, _remote_account_id) =
383            create_test_remote_account(&abstr_remote, STARGAZE, JUNO, &mock_interchain, None)?;
384
385        // Install local app
386        let app = MockAppOriginI::new(
387            TEST_MODULE_ID,
388            abstr_origin.version_control.get_chain().clone(),
389        );
390
391        abstr_origin
392            .version_control
393            .claim_namespace(origin_account.id()?, TEST_NAMESPACE.to_owned())?;
394
395        app.deploy(TEST_VERSION.parse()?, DeployStrategy::Try)?;
396
397        origin_account.install_app(&app, &MockInitMsg {}, None)?;
398
399        // Install remote app
400        let app_remote = MockAppRemoteI::new(
401            TEST_MODULE_ID_REMOTE,
402            abstr_remote.version_control.get_chain().clone(),
403        );
404
405        abstr_remote
406            .version_control
407            .claim_namespace(remote_account.id()?, TEST_NAMESPACE.to_owned())?;
408
409        app_remote.deploy(TEST_VERSION_REMOTE.parse()?, DeployStrategy::Try)?;
410
411        // The user on origin chain wants to change the account description
412        let target_module_info =
413            ModuleInfo::from_id(TEST_MODULE_ID_REMOTE, TEST_VERSION_REMOTE.into())?;
414        let ibc_action_result = app.do_something_ibc(remote_name, target_module_info.clone())?;
415
416        let ibc_result = mock_interchain.wait_ibc(JUNO, ibc_action_result)?;
417
418        let expected_error_outcome =
419            format!("App {} not installed on Account", target_module_info,);
420        match &ibc_result.packets[0].outcome {
421            IbcPacketOutcome::Timeout { .. } => {
422                panic!("Expected a failed ack not a timeout !")
423            }
424            IbcPacketOutcome::Success { ack, .. } => assert!(String::from_utf8_lossy(ack)
425                .to_string()
426                .contains(&expected_error_outcome)),
427        }
428
429        Ok(())
430    }
431
432    #[test]
433    fn works() -> AnyResult<()> {
434        logger_test_init();
435        let mock_interchain =
436            MockBech32InterchainEnv::new(vec![(JUNO, "juno"), (STARGAZE, "stargaze")]);
437
438        // We just verified all steps pass
439        let (abstr_origin, abstr_remote) = ibc_abstract_setup(&mock_interchain, JUNO, STARGAZE)?;
440        ibc_connect_polytone_and_abstract(&mock_interchain, STARGAZE, JUNO)?;
441
442        let remote_name = ChainName::from_chain_id(STARGAZE).to_string();
443
444        let (origin_account, remote_account_id) =
445            create_test_remote_account(&abstr_origin, JUNO, STARGAZE, &mock_interchain, None)?;
446
447        let (remote_account, _) =
448            create_test_remote_account(&abstr_remote, STARGAZE, JUNO, &mock_interchain, None)?;
449
450        // Install local app
451        let app = MockAppOriginI::new(
452            TEST_MODULE_ID,
453            abstr_origin.version_control.get_chain().clone(),
454        );
455
456        abstr_origin
457            .version_control
458            .claim_namespace(origin_account.id()?, TEST_NAMESPACE.to_owned())?;
459
460        app.deploy(TEST_VERSION.parse()?, DeployStrategy::Try)?;
461
462        origin_account.install_app(&app, &MockInitMsg {}, None)?;
463
464        // Install remote app
465        let app_remote = MockAppRemoteI::new(
466            TEST_MODULE_ID_REMOTE,
467            abstr_remote.version_control.get_chain().clone(),
468        );
469
470        abstr_remote
471            .version_control
472            .claim_namespace(remote_account.id()?, TEST_NAMESPACE.to_owned())?;
473
474        app_remote.deploy(TEST_VERSION_REMOTE.parse()?, DeployStrategy::Try)?;
475
476        let remote_install_response = origin_account.manager.execute_on_remote(
477            &remote_name,
478            manager::ExecuteMsg::InstallModules {
479                modules: vec![ModuleInstallConfig::new(
480                    ModuleInfo::from_id_latest(TEST_MODULE_ID_REMOTE)?,
481                    Some(to_json_binary(&MockInitMsg {})?),
482                )],
483            },
484        )?;
485
486        mock_interchain.check_ibc(JUNO, remote_install_response)?;
487
488        // We get the object for handling the actual module on the remote account
489        let remote_manager = abstr_remote
490            .version_control
491            .account_base(remote_account_id)?
492            .account_base
493            .manager;
494        let manager = Manager::new(
495            "remote-account-manager",
496            abstr_remote.version_control.get_chain().clone(),
497        );
498        manager.set_address(&remote_manager);
499        let module_address = manager.module_info(TEST_MODULE_ID_REMOTE)?.unwrap().address;
500        let remote_account_app = MockAppRemoteI::new(
501            "remote-account-app",
502            abstr_remote.version_control.get_chain().clone(),
503        );
504        remote_account_app.set_address(&module_address);
505
506        // The user on origin chain triggers a module-to-module interaction
507        let target_module_info =
508            ModuleInfo::from_id(TEST_MODULE_ID_REMOTE, TEST_VERSION_REMOTE.into())?;
509        let ibc_action_result = app.do_something_ibc(remote_name, target_module_info.clone())?;
510
511        assert_remote_module_call_status(&remote_account_app, None)?;
512        assert_callback_status(&app, false)?;
513
514        mock_interchain.check_ibc(JUNO, ibc_action_result)?;
515
516        assert_remote_module_call_status(
517            &remote_account_app,
518            Some(ModuleInfo::from_id(TEST_MODULE_ID, TEST_VERSION.into())?),
519        )?;
520        assert_callback_status(&app, true)?;
521
522        Ok(())
523    }
524
525    pub const REMOTE_AMOUNT: u128 = 5674309;
526    pub const REMOTE_DENOM: &str = "remote_denom";
527    #[test]
528    fn queries() -> AnyResult<()> {
529        logger_test_init();
530        let mock_interchain =
531            MockBech32InterchainEnv::new(vec![(JUNO, "juno"), (STARGAZE, "stargaze")]);
532
533        // We just verified all steps pass
534        let (abstr_origin, _abstr_remote) = ibc_abstract_setup(&mock_interchain, JUNO, STARGAZE)?;
535        ibc_connect_polytone_and_abstract(&mock_interchain, STARGAZE, JUNO)?;
536
537        let remote_name = ChainName::from_chain_id(STARGAZE).to_string();
538        let remote = mock_interchain.chain(STARGAZE)?;
539        let remote_address =
540            remote.addr_make_with_balance("remote-test", coins(REMOTE_AMOUNT, REMOTE_DENOM))?;
541
542        let (origin_account, _remote_account_id) =
543            create_test_remote_account(&abstr_origin, JUNO, STARGAZE, &mock_interchain, None)?;
544
545        // Install local app
546        let app = MockAppOriginI::new(
547            TEST_MODULE_ID,
548            abstr_origin.version_control.get_chain().clone(),
549        );
550
551        abstr_origin
552            .version_control
553            .claim_namespace(origin_account.id()?, TEST_NAMESPACE.to_owned())?;
554
555        app.deploy(TEST_VERSION.parse()?, DeployStrategy::Try)?;
556
557        origin_account.install_app(&app, &MockInitMsg {}, None)?;
558
559        let query_response = app.query_something_ibc(remote_address.to_string(), remote_name)?;
560
561        assert_query_callback_status(&app, coins(REMOTE_AMOUNT, REMOTE_DENOM)).unwrap_err();
562        mock_interchain.check_ibc(JUNO, query_response)?;
563        assert_query_callback_status(&app, coins(REMOTE_AMOUNT, REMOTE_DENOM))?;
564
565        Ok(())
566    }
567
568    pub mod security {
569        use abstract_std::ibc_client::ExecuteMsgFns;
570
571        use crate::module_to_module_interactions::IbcModuleToModuleMsg;
572
573        use super::*;
574
575        #[test]
576        fn calling_module_should_match() -> AnyResult<()> {
577            logger_test_init();
578            let mock_interchain =
579                MockBech32InterchainEnv::new(vec![(JUNO, "juno"), (STARGAZE, "stargaze")]);
580
581            // We just verified all steps pass
582            let (abstr_origin, abstr_remote) =
583                ibc_abstract_setup(&mock_interchain, JUNO, STARGAZE)?;
584            ibc_connect_polytone_and_abstract(&mock_interchain, STARGAZE, JUNO)?;
585
586            let remote_name = ChainName::from_chain_id(STARGAZE).to_string();
587
588            let (origin_account, remote_account_id) =
589                create_test_remote_account(&abstr_origin, JUNO, STARGAZE, &mock_interchain, None)?;
590
591            let (remote_account, _) =
592                create_test_remote_account(&abstr_remote, STARGAZE, JUNO, &mock_interchain, None)?;
593
594            // Install local app
595            let app = MockAppOriginI::new(
596                TEST_MODULE_ID,
597                abstr_origin.version_control.get_chain().clone(),
598            );
599
600            abstr_origin
601                .version_control
602                .claim_namespace(origin_account.id()?, TEST_NAMESPACE.to_owned())?;
603
604            app.deploy(TEST_VERSION.parse()?, DeployStrategy::Try)?;
605
606            origin_account.install_app(&app, &MockInitMsg {}, None)?;
607
608            // Install remote app
609            let app_remote = MockAppRemoteI::new(
610                TEST_MODULE_ID_REMOTE,
611                abstr_remote.version_control.get_chain().clone(),
612            );
613
614            abstr_remote
615                .version_control
616                .claim_namespace(remote_account.id()?, TEST_NAMESPACE.to_owned())?;
617
618            app_remote.deploy(TEST_VERSION_REMOTE.parse()?, DeployStrategy::Try)?;
619
620            let remote_install_response = origin_account.manager.execute_on_remote(
621                &remote_name,
622                manager::ExecuteMsg::InstallModules {
623                    modules: vec![ModuleInstallConfig::new(
624                        ModuleInfo::from_id_latest(TEST_MODULE_ID_REMOTE)?,
625                        Some(to_json_binary(&MockInitMsg {})?),
626                    )],
627                },
628            )?;
629
630            mock_interchain.check_ibc(JUNO, remote_install_response)?;
631
632            // We get the object for handling the actual module on the remote account
633            let remote_manager = abstr_remote
634                .version_control
635                .account_base(remote_account_id)?
636                .account_base
637                .manager;
638            let manager = Manager::new(
639                "remote-account-manager",
640                abstr_remote.version_control.get_chain().clone(),
641            );
642            manager.set_address(&remote_manager);
643            let module_address = manager.module_info(TEST_MODULE_ID_REMOTE)?.unwrap().address;
644            let remote_account_app = MockAppRemoteI::new(
645                "remote-account-app",
646                abstr_remote.version_control.get_chain().clone(),
647            );
648            remote_account_app.set_address(&module_address);
649
650            // The user on origin chain triggers a module-to-module interaction
651            let target_module_info =
652                ModuleInfo::from_id(TEST_MODULE_ID_REMOTE, TEST_VERSION_REMOTE.into())?;
653
654            // The user triggers manually a module-to-module interaction
655            abstr_origin
656                .ibc
657                .client
658                .module_ibc_action(
659                    remote_name,
660                    to_json_binary(&IbcModuleToModuleMsg {
661                        ibc_msg: "module_to_module:msg".to_string(),
662                    })
663                    .unwrap(),
664                    target_module_info,
665                    None,
666                )
667                .unwrap_err();
668
669            Ok(())
670        }
671    }
672}