diff --git a/framework/contracts/account/manager/tests/snapshots/adapters__account_install_adapter.snap b/framework/contracts/account/manager/tests/snapshots/adapters__account_install_adapter.snap index d9f8bc6dcc..6ed0a10493 100644 --- a/framework/contracts/account/manager/tests/snapshots/adapters__account_install_adapter.snap +++ b/framework/contracts/account/manager/tests/snapshots/adapters__account_install_adapter.snap @@ -112,6 +112,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/adapters__install_one_adapter.snap b/framework/contracts/account/manager/tests/snapshots/adapters__install_one_adapter.snap index 72f18889f8..f34b62079d 100644 --- a/framework/contracts/account/manager/tests/snapshots/adapters__install_one_adapter.snap +++ b/framework/contracts/account/manager/tests/snapshots/adapters__install_one_adapter.snap @@ -112,6 +112,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/adapters__install_one_adapter_with_fee.snap b/framework/contracts/account/manager/tests/snapshots/adapters__install_one_adapter_with_fee.snap index 49b95bc711..c7b0831ca6 100644 --- a/framework/contracts/account/manager/tests/snapshots/adapters__install_one_adapter_with_fee.snap +++ b/framework/contracts/account/manager/tests/snapshots/adapters__install_one_adapter_with_fee.snap @@ -114,6 +114,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/adapters__installing_specific_version_should_install_expected.snap b/framework/contracts/account/manager/tests/snapshots/adapters__installing_specific_version_should_install_expected.snap index 90ea822e0b..4069ebaf24 100644 --- a/framework/contracts/account/manager/tests/snapshots/adapters__installing_specific_version_should_install_expected.snap +++ b/framework/contracts/account/manager/tests/snapshots/adapters__installing_specific_version_should_install_expected.snap @@ -114,6 +114,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/adapters__reinstalling_adapter_should_be_allowed.snap b/framework/contracts/account/manager/tests/snapshots/adapters__reinstalling_adapter_should_be_allowed.snap index 72f18889f8..f34b62079d 100644 --- a/framework/contracts/account/manager/tests/snapshots/adapters__reinstalling_adapter_should_be_allowed.snap +++ b/framework/contracts/account/manager/tests/snapshots/adapters__reinstalling_adapter_should_be_allowed.snap @@ -112,6 +112,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/adapters__reinstalling_new_version_should_install_latest.snap b/framework/contracts/account/manager/tests/snapshots/adapters__reinstalling_new_version_should_install_latest.snap index 5f8fb83d8b..0eba2b6222 100644 --- a/framework/contracts/account/manager/tests/snapshots/adapters__reinstalling_new_version_should_install_latest.snap +++ b/framework/contracts/account/manager/tests/snapshots/adapters__reinstalling_new_version_should_install_latest.snap @@ -114,6 +114,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/apps__account_install_app.snap b/framework/contracts/account/manager/tests/snapshots/apps__account_install_app.snap index 7b36f9c462..83bc08147e 100644 --- a/framework/contracts/account/manager/tests/snapshots/apps__account_install_app.snap +++ b/framework/contracts/account/manager/tests/snapshots/apps__account_install_app.snap @@ -112,6 +112,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/apps__execute_on_proxy_through_manager.snap b/framework/contracts/account/manager/tests/snapshots/apps__execute_on_proxy_through_manager.snap index 532312ddcf..8e0e6ea58d 100644 --- a/framework/contracts/account/manager/tests/snapshots/apps__execute_on_proxy_through_manager.snap +++ b/framework/contracts/account/manager/tests/snapshots/apps__execute_on_proxy_through_manager.snap @@ -106,6 +106,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/install_modules__adds_module_to_account_modules.snap b/framework/contracts/account/manager/tests/snapshots/install_modules__adds_module_to_account_modules.snap index d0abe18522..26351debd0 100644 --- a/framework/contracts/account/manager/tests/snapshots/install_modules__adds_module_to_account_modules.snap +++ b/framework/contracts/account/manager/tests/snapshots/install_modules__adds_module_to_account_modules.snap @@ -122,6 +122,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/proxy__default_without_response_data.snap b/framework/contracts/account/manager/tests/snapshots/proxy__default_without_response_data.snap index 94e6dff7f0..20757f9c57 100644 --- a/framework/contracts/account/manager/tests/snapshots/proxy__default_without_response_data.snap +++ b/framework/contracts/account/manager/tests/snapshots/proxy__default_without_response_data.snap @@ -112,6 +112,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/proxy__exec_through_manager.snap b/framework/contracts/account/manager/tests/snapshots/proxy__exec_through_manager.snap index f49840a6ba..1795e4401e 100644 --- a/framework/contracts/account/manager/tests/snapshots/proxy__exec_through_manager.snap +++ b/framework/contracts/account/manager/tests/snapshots/proxy__exec_through_manager.snap @@ -106,6 +106,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/proxy__instantiate_proxy.snap b/framework/contracts/account/manager/tests/snapshots/proxy__instantiate_proxy.snap index f49840a6ba..1795e4401e 100644 --- a/framework/contracts/account/manager/tests/snapshots/proxy__instantiate_proxy.snap +++ b/framework/contracts/account/manager/tests/snapshots/proxy__instantiate_proxy.snap @@ -106,6 +106,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/proxy__proxy_install_multiple_modules.snap b/framework/contracts/account/manager/tests/snapshots/proxy__proxy_install_multiple_modules.snap index 23c0b03d16..94e2051220 100644 --- a/framework/contracts/account/manager/tests/snapshots/proxy__proxy_install_multiple_modules.snap +++ b/framework/contracts/account/manager/tests/snapshots/proxy__proxy_install_multiple_modules.snap @@ -88,6 +88,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000bstandalone11.0.0" diff --git a/framework/contracts/account/manager/tests/snapshots/proxy__proxy_install_standalone_modules.snap b/framework/contracts/account/manager/tests/snapshots/proxy__proxy_install_standalone_modules.snap index f0fae6629a..964c80ca21 100644 --- a/framework/contracts/account/manager/tests/snapshots/proxy__proxy_install_standalone_modules.snap +++ b/framework/contracts/account/manager/tests/snapshots/proxy__proxy_install_standalone_modules.snap @@ -84,6 +84,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000bstandalone11.0.0" diff --git a/framework/contracts/account/manager/tests/snapshots/proxy__proxy_with_response_data.snap b/framework/contracts/account/manager/tests/snapshots/proxy__proxy_with_response_data.snap index 76048f645a..9e99e3bbe8 100644 --- a/framework/contracts/account/manager/tests/snapshots/proxy__proxy_with_response_data.snap +++ b/framework/contracts/account/manager/tests/snapshots/proxy__proxy_with_response_data.snap @@ -112,6 +112,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/subaccount__account_move_ownership_to_falsy_sub_account.snap b/framework/contracts/account/manager/tests/snapshots/subaccount__account_move_ownership_to_falsy_sub_account.snap index 8028cf4cc6..65be670e2f 100644 --- a/framework/contracts/account/manager/tests/snapshots/subaccount__account_move_ownership_to_falsy_sub_account.snap +++ b/framework/contracts/account/manager/tests/snapshots/subaccount__account_move_ownership_to_falsy_sub_account.snap @@ -164,6 +164,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/subaccount__creating_on_subaccount_should_succeed.snap b/framework/contracts/account/manager/tests/snapshots/subaccount__creating_on_subaccount_should_succeed.snap index a22c1d7a14..80468ed7f3 100644 --- a/framework/contracts/account/manager/tests/snapshots/subaccount__creating_on_subaccount_should_succeed.snap +++ b/framework/contracts/account/manager/tests/snapshots/subaccount__creating_on_subaccount_should_succeed.snap @@ -108,6 +108,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/subaccount__installed_app_updating_on_subaccount_should_succeed.snap b/framework/contracts/account/manager/tests/snapshots/subaccount__installed_app_updating_on_subaccount_should_succeed.snap index bdea78292f..07cd5a38ef 100644 --- a/framework/contracts/account/manager/tests/snapshots/subaccount__installed_app_updating_on_subaccount_should_succeed.snap +++ b/framework/contracts/account/manager/tests/snapshots/subaccount__installed_app_updating_on_subaccount_should_succeed.snap @@ -136,6 +136,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/subaccount__proxy_updating_on_subaccount_should_succeed.snap b/framework/contracts/account/manager/tests/snapshots/subaccount__proxy_updating_on_subaccount_should_succeed.snap index 8a055ece3c..f61ceab4ed 100644 --- a/framework/contracts/account/manager/tests/snapshots/subaccount__proxy_updating_on_subaccount_should_succeed.snap +++ b/framework/contracts/account/manager/tests/snapshots/subaccount__proxy_updating_on_subaccount_should_succeed.snap @@ -136,6 +136,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/subaccount__recursive_updating_on_subaccount_should_succeed.snap b/framework/contracts/account/manager/tests/snapshots/subaccount__recursive_updating_on_subaccount_should_succeed.snap index 93f0ec1d64..615834b1c3 100644 --- a/framework/contracts/account/manager/tests/snapshots/subaccount__recursive_updating_on_subaccount_should_succeed.snap +++ b/framework/contracts/account/manager/tests/snapshots/subaccount__recursive_updating_on_subaccount_should_succeed.snap @@ -166,6 +166,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/subaccount__sub_account_move_ownership.snap b/framework/contracts/account/manager/tests/snapshots/subaccount__sub_account_move_ownership.snap index a2b53dcde7..1b0f6891d9 100644 --- a/framework/contracts/account/manager/tests/snapshots/subaccount__sub_account_move_ownership.snap +++ b/framework/contracts/account/manager/tests/snapshots/subaccount__sub_account_move_ownership.snap @@ -134,6 +134,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/subaccount__sub_account_move_ownership_to_sub_account.snap b/framework/contracts/account/manager/tests/snapshots/subaccount__sub_account_move_ownership_to_sub_account.snap index d2b174d12b..ce2c746ae0 100644 --- a/framework/contracts/account/manager/tests/snapshots/subaccount__sub_account_move_ownership_to_sub_account.snap +++ b/framework/contracts/account/manager/tests/snapshots/subaccount__sub_account_move_ownership_to_sub_account.snap @@ -194,6 +194,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/account/manager/tests/snapshots/subaccount__updating_on_subaccount_should_succeed.snap b/framework/contracts/account/manager/tests/snapshots/subaccount__updating_on_subaccount_should_succeed.snap index 8a055ece3c..f61ceab4ed 100644 --- a/framework/contracts/account/manager/tests/snapshots/subaccount__updating_on_subaccount_should_succeed.snap +++ b/framework/contracts/account/manager/tests/snapshots/subaccount__updating_on_subaccount_should_succeed.snap @@ -136,6 +136,8 @@ expression: all_storage - "{\"account_base\":5}" - - "\u0000\u0003lib\u0000\babstract\u0000\bans-host0.21.0" - "{\"native\":\"mock1mzdhwvvh22wrt07w59wxyd58822qavwkx5lcej7aqfkpqqlhaqfsetqc4t\"}" + - - "\u0000\u0003lib\u0000\babstract\u0000\bibc-host0.21.0" + - "{\"native\":\"mock14ejqjyq8um4p3xfqj74yld5waqljf88fz25yxnma0cngspxe3les6xzvf5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\nibc-client0.21.0" - "{\"native\":\"mock1aaf9r6s7nxhysuegqrxv0wpm27ypyv4886medd3mrkrw6t4yfcns7ctvz5\"}" - - "\u0000\u0003lib\u0000\babstract\u0000\u000emodule-factory0.21.0" diff --git a/framework/contracts/native/ibc-client/src/commands.rs b/framework/contracts/native/ibc-client/src/commands.rs index c117e74612..18517b03bf 100644 --- a/framework/contracts/native/ibc-client/src/commands.rs +++ b/framework/contracts/native/ibc-client/src/commands.rs @@ -3,23 +3,30 @@ use std::str::FromStr; use abstract_sdk::{ feature_objects::{AnsHost, VersionControlContract}, features::AccountIdentification, - Resolve, + namespaces::BASE_STATE, + ModuleRegistryInterface, Resolve, }; use abstract_std::{ + app::AppState, + ibc::CallbackInfo, ibc_client::{ state::{IbcInfrastructure, ACCOUNTS, CONFIG, IBC_INFRA, REVERSE_POLYTONE_NOTE}, - IbcClientCallback, + IbcClientCallback, InstalledModuleIdentification, }, ibc_host::{self, HostAction, InternalAction}, manager::{self, ModuleInstallConfig}, - objects::{chain_name::ChainName, AccountId, AssetEntry, ChannelEntry}, + objects::{ + chain_name::ChainName, module::ModuleInfo, module_reference::ModuleReference, AccountId, + AssetEntry, ChannelEntry, + }, version_control::AccountBase, ICS20, }; use cosmwasm_std::{ - to_json_binary, wasm_execute, Coin, CosmosMsg, Deps, DepsMut, Empty, Env, IbcMsg, MessageInfo, - Storage, + to_json_binary, wasm_execute, Binary, Coin, CosmosMsg, Deps, DepsMut, Empty, Env, IbcMsg, + MessageInfo, QueryRequest, Storage, }; +use cw_storage_plus::Item; use polytone::callbacks::CallbackRequest; use crate::{ @@ -177,31 +184,158 @@ pub fn execute_send_packet( let cfg = CONFIG.load(deps.storage)?; - // Verify that the sender is a proxy contract - let account_base = cfg + // The packet we need to send depends on the action we want to execute + + let note_message = match &action { + HostAction::Dispatch { .. } | HostAction::Helpers(_) => { + // Verify that the sender is a proxy contract + let account_base = cfg + .version_control + .assert_proxy(&info.sender, &deps.querier)?; + + // get account_id + let account_id = account_base.account_id(deps.as_ref())?; + + send_remote_host_action( + deps.as_ref(), + account_id, + account_base, + host_chain, + action, + None, + )? + } + HostAction::Internal(_) => { + // Can only call non-internal actions + return Err(IbcClientError::ForbiddenInternalCall {}); + } + }; + + Ok(IbcClientResponse::action("handle_send_msgs").add_message(note_message)) +} + +/// Sends a packet with an optional callback. +/// This is the top-level function to do IBC related actions. +#[allow(clippy::too_many_arguments)] +pub fn execute_send_module_to_module_packet( + deps: DepsMut, + env: Env, + info: MessageInfo, + host_chain: String, + target_module: ModuleInfo, + msg: Binary, + callback_info: Option, +) -> IbcClientResult { + let host_chain = ChainName::from_str(&host_chain)?; + let cfg = CONFIG.load(deps.storage)?; + + // Query the sender module information + let module_info = cfg .version_control - .assert_proxy(&info.sender, &deps.querier)?; + .module_registry(deps.as_ref())? + .module_info(info.sender.clone())?; + + // We need additional information depending on the module type + let source_module = match module_info.reference { + ModuleReference::AccountBase(_) => return Err(IbcClientError::Unauthorized {}), + ModuleReference::Native(_) => return Err(IbcClientError::Unauthorized {}), + ModuleReference::Standalone(_) => return Err(IbcClientError::Unauthorized {}), + ModuleReference::Adapter(_) => InstalledModuleIdentification { + module_info: module_info.info, + account_id: None, + }, + ModuleReference::App(_) => { + // We verify the associated account id + let proxy_addr = Item::::new(BASE_STATE) + .query(&deps.querier, info.sender.clone())? + .proxy_address; + let account_id = cfg.version_control.account_id(&proxy_addr, &deps.querier)?; + + InstalledModuleIdentification { + module_info: module_info.info, + account_id: Some(account_id), + } + } + _ => unimplemented!( + "This module type didn't exist when implementing module-to-module interactions" + ), + }; - // get account_id - let account_id = account_base.account_id(deps.as_ref())?; + // We send a message to the target module on the remote chain + // Send this message via the Polytone implementation - // Can only call non-internal actions - if let HostAction::Internal(_) = action { - return Err(IbcClientError::ForbiddenInternalCall {}); - } + let callback_request = callback_info.map(|c| CallbackRequest { + receiver: env.contract.address.to_string(), + msg: to_json_binary(&IbcClientCallback::ModuleRemoteAction { + sender_address: info.sender.to_string(), + callback_info: c, + initiator_msg: msg.clone(), + }) + .unwrap(), + }); + let ibc_infra = IBC_INFRA.load(deps.storage, &host_chain)?; + let note_contract = ibc_infra.polytone_note; + let remote_ibc_host = ibc_infra.remote_abstract_host; - let note_message = send_remote_host_action( - deps.as_ref(), - account_id, - account_base, - host_chain, - action, - None, + // message that will be called on the local note contract + let note_message = wasm_execute( + note_contract.to_string(), + &polytone_note::msg::ExecuteMsg::Execute { + msgs: vec![wasm_execute( + // The note's remote proxy will call the ibc host + remote_ibc_host, + &ibc_host::ExecuteMsg::ModuleExecute { + msg, + source_module, + target_module, + }, + vec![], + )? + .into()], + callback: callback_request, + timeout_seconds: PACKET_LIFETIME.into(), + }, + vec![], + )?; + Ok(IbcClientResponse::action("handle_send_module_to_module_packet").add_message(note_message)) +} + +/// Sends a packet with an optional callback. +/// This is the top-level function to do IBC related actions. +pub fn execute_send_query( + deps: DepsMut, + env: Env, + info: MessageInfo, + host_chain: String, + query: QueryRequest, + callback_info: CallbackInfo, +) -> IbcClientResult { + let host_chain = ChainName::from_str(&host_chain)?; + + let callback_request = CallbackRequest { + receiver: env.contract.address.to_string(), + msg: to_json_binary(&IbcClientCallback::ModuleRemoteQuery { + callback_info, + sender_address: info.sender.to_string(), + query: query.clone(), + }) + .unwrap(), + }; + + let ibc_infra = IBC_INFRA.load(deps.storage, &host_chain)?; + let note_contract = ibc_infra.polytone_note; + let note_message = wasm_execute( + note_contract.to_string(), + &polytone_note::msg::ExecuteMsg::Query { + msgs: vec![query], + callback: callback_request, + timeout_seconds: PACKET_LIFETIME.into(), + }, + vec![], )?; Ok(IbcClientResponse::action("handle_send_msgs").add_message(note_message)) } - /// Registers an Abstract Account on a remote chain. pub fn execute_register_account( deps: DepsMut, diff --git a/framework/contracts/native/ibc-client/src/contract.rs b/framework/contracts/native/ibc-client/src/contract.rs index 33387169f8..c2f1666fdf 100644 --- a/framework/contracts/native/ibc-client/src/contract.rs +++ b/framework/contracts/native/ibc-client/src/contract.rs @@ -90,6 +90,25 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> I ExecuteMsg::Callback(c) => { ibc::receive_action_callback(deps, env, info, c).map_err(Into::into) } + ExecuteMsg::ModuleIbcAction { + host_chain, + target_module, + msg, + callback_info, + } => commands::execute_send_module_to_module_packet( + deps, + env, + info, + host_chain, + target_module, + msg, + callback_info, + ), + ExecuteMsg::IbcQuery { + host_chain, + query, + callback_info, + } => commands::execute_send_query(deps, env, info, host_chain, query, callback_info), } } @@ -451,6 +470,7 @@ mod tests { manager, objects::{chain_name::ChainName, version_control::VersionControlError}, }; + use cosmwasm_std::wasm_execute; use crate::commands::PACKET_LIFETIME; diff --git a/framework/contracts/native/ibc-client/src/error.rs b/framework/contracts/native/ibc-client/src/error.rs index 47bd134a85..e0f96de783 100644 --- a/framework/contracts/native/ibc-client/src/error.rs +++ b/framework/contracts/native/ibc-client/src/error.rs @@ -33,9 +33,12 @@ pub enum IbcClientError { #[error("remote account changed from {old} to {addr}")] RemoteAccountChanged { addr: String, old: String }, - #[error("packages that contain internal calls are not allowed")] + #[error("Calling internal actions externally is not allowed")] ForbiddenInternalCall {}, + #[error("A non-module package (native or accounts) cannot execute an ibc module call")] + ForbiddenModuleCall {}, + #[error("The host you are trying to connect is already connected")] HostAlreadyExists {}, diff --git a/framework/contracts/native/ibc-client/src/ibc.rs b/framework/contracts/native/ibc-client/src/ibc.rs index 3d337c6e61..7c88ecf7a0 100644 --- a/framework/contracts/native/ibc-client/src/ibc.rs +++ b/framework/contracts/native/ibc-client/src/ibc.rs @@ -1,4 +1,5 @@ use abstract_std::{ + ibc::{CallbackResult, IbcResponseMsg}, ibc_client::{ state::{ACCOUNTS, IBC_INFRA, REVERSE_POLYTONE_NOTE}, IbcClientCallback, @@ -86,5 +87,35 @@ pub fn receive_action_callback( .add_attribute("chain", host_chain.to_string()), ) } + IbcClientCallback::ModuleRemoteAction { + callback_info, + sender_address, + initiator_msg, + } => { + let callback = IbcResponseMsg { + id: callback_info.id.clone(), + msg: callback_info.msg, + result: CallbackResult::from_execute(callback.result, initiator_msg)?, + }; + Ok(IbcClientResponse::action("module_action_ibc_callback") + .add_message(callback.into_cosmos_msg(sender_address)?) + .add_attribute("chain", host_chain.to_string()) + .add_attribute("callback_id", callback_info.id)) + } + IbcClientCallback::ModuleRemoteQuery { + sender_address, + callback_info, + query, + } => { + let callback = IbcResponseMsg { + id: callback_info.id.clone(), + msg: callback_info.msg, + result: CallbackResult::from_query(callback.result, query)?, + }; + Ok(IbcClientResponse::action("module_query_ibc_callback") + .add_message(callback.into_cosmos_msg(sender_address)?) + .add_attribute("chain", host_chain.to_string()) + .add_attribute("callback_id", callback_info.id)) + } } } diff --git a/framework/contracts/native/ibc-host/src/endpoints/execute.rs b/framework/contracts/native/ibc-host/src/endpoints/execute.rs index 7be1ecee40..b808112777 100644 --- a/framework/contracts/native/ibc-host/src/endpoints/execute.rs +++ b/framework/contracts/native/ibc-host/src/endpoints/execute.rs @@ -7,7 +7,7 @@ use abstract_std::{ }; use cosmwasm_std::{DepsMut, Env, MessageInfo}; -use super::packet::handle_host_action; +use super::packet::{handle_host_action, handle_host_module_action}; use crate::{ contract::{HostResponse, HostResult}, HostError, @@ -44,6 +44,14 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> H cw_ownable::update_ownership(deps, &env.block, &info.sender, action)?; Ok(HostResponse::action("update_ownership")) } + ExecuteMsg::ModuleExecute { + msg, + source_module, + target_module, + } => { + let client_chain: ChainName = REVERSE_CHAIN_PROXIES.load(deps.storage, &info.sender)?; + handle_host_module_action(deps, client_chain, source_module, target_module, msg) + } } } diff --git a/framework/contracts/native/ibc-host/src/endpoints/packet.rs b/framework/contracts/native/ibc-host/src/endpoints/packet.rs index c04b7a7eda..dd7ceafb36 100644 --- a/framework/contracts/native/ibc-host/src/endpoints/packet.rs +++ b/framework/contracts/native/ibc-host/src/endpoints/packet.rs @@ -1,18 +1,30 @@ -use abstract_sdk::std::ibc_host::{HostAction, InternalAction}; use abstract_std::{ + base::ExecuteMsg as MiddlewareExecMsg, + ibc::ModuleIbcMsg, + ibc_client::InstalledModuleIdentification, ibc_host::{ - state::{ActionAfterCreationCache, TEMP_ACTION_AFTER_CREATION}, - HelperAction, + state::{ActionAfterCreationCache, CONFIG, TEMP_ACTION_AFTER_CREATION}, + HelperAction, HostAction, InternalAction, + }, + objects::{ + chain_name::ChainName, module::ModuleInfo, module_reference::ModuleReference, AccountId, }, - objects::{chain_name::ChainName, AccountId}, }; -use cosmwasm_std::{DepsMut, Env}; +use cosmwasm_std::{wasm_execute, Binary, DepsMut, Empty, Env, Response}; use crate::{ account_commands::{self, receive_dispatch, receive_register, receive_send_all_back}, contract::HostResult, + HostError, }; +pub fn client_to_host_account_id(remote_chain: ChainName, account_id: AccountId) -> AccountId { + let mut account_id = account_id.clone(); + account_id.trace_mut().push_chain(remote_chain); + + account_id +} + /// Handle actions that are passed to the IBC host contract /// This function is not permissioned and access control needs to be handled outside of it /// Usually the `client_chain` argument needs to be derived from the message sender @@ -25,8 +37,7 @@ pub fn handle_host_action( host_action: HostAction, ) -> HostResult { // Push the client chain to the account trace - let mut account_id = received_account_id.clone(); - account_id.trace_mut().push_chain(client_chain.clone()); + let account_id = client_to_host_account_id(client_chain.clone(), received_account_id.clone()); // get the local account information match host_action { @@ -105,3 +116,47 @@ pub fn handle_host_action( } .map_err(Into::into) } + +/// Handle actions that are passed to the IBC host contract and originate from a registered module +pub fn handle_host_module_action( + deps: DepsMut, + client_chain: ChainName, + source_module: InstalledModuleIdentification, + target_module: ModuleInfo, + msg: Binary, +) -> HostResult { + // We resolve the target module + let vc = CONFIG.load(deps.storage)?.version_control; + let target_module = InstalledModuleIdentification { + module_info: target_module, + account_id: source_module + .account_id + .map(|a| client_to_host_account_id(client_chain.clone(), a)), + }; + + let target_module_resolved = target_module.addr(deps.as_ref(), vc)?; + + match target_module_resolved.reference { + ModuleReference::AccountBase(_) | ModuleReference::Native(_) => { + return Err(HostError::WrongModuleAction( + "Can't send module-to-module message to an account or a native module".to_string(), + )) + } + _ => {} + } + + // We pass the message on to the module + let msg = wasm_execute( + target_module_resolved.address, + &MiddlewareExecMsg::ModuleIbc::(ModuleIbcMsg { + client_chain, + source_module: source_module.module_info, + msg, + }), + vec![], + )?; + + Ok(Response::new() + .add_attribute("action", "module-ibc-call") + .add_message(msg)) +} diff --git a/framework/contracts/native/ibc-host/src/error.rs b/framework/contracts/native/ibc-host/src/error.rs index ee86e05849..f57ee62600 100644 --- a/framework/contracts/native/ibc-host/src/error.rs +++ b/framework/contracts/native/ibc-host/src/error.rs @@ -1,6 +1,6 @@ use abstract_sdk::AbstractSdkError; use abstract_std::{ - objects::{ans_host::AnsHostError, version_control::VersionControlError}, + objects::{ans_host::AnsHostError, version_control::VersionControlError, AccountId}, AbstractError, }; use cosmwasm_std::StdError; @@ -42,6 +42,20 @@ pub enum HostError { #[error("Chain or proxy address already registered.")] ProxyAddressExists {}, + + #[error("Can't send a module-to-module packet to {0}, wrong module type")] + WrongModuleAction(String), + + #[error("Missing module {module_info} on account {account_id}")] + MissingModule { + module_info: String, + account_id: AccountId, + }, + + #[error( + "You need to specify an account id for an account-specific module (apps and standalone)" + )] + AccountIdNotSpecified {}, } impl From for HostError { diff --git a/framework/docs/src/4_get_started/3_module_builder.md b/framework/docs/src/4_get_started/3_module_builder.md index 72e74f77df..2c9185c108 100644 --- a/framework/docs/src/4_get_started/3_module_builder.md +++ b/framework/docs/src/4_get_started/3_module_builder.md @@ -135,6 +135,7 @@ This appendix contains all the available handlers, what type of handler `Fn` the - `with_sudo`: Called when the App's `SudoMsg` is called on the sudo entry point. - `with_receive`: Called when the App's `ExecuteMsg::Receive` variant is called on the execute entry point. - `with_ibc_callbacks`: Called when the App's `ExecuteMsg::IbcCallback` is called on the execute entry point. Matches the callback's callback ID to its associated function. +- `with_module_ibc`: Called when a Module wants to call another module over IBC. In the case of adapters, the handlers are the same, except for `with_migrate` and `with_sudo` that are missing for reasons we explain in the [adapter section](../3_framework/6_module_types.md#adapters). @@ -364,6 +365,39 @@ customizable but contains the IBC action acknowledgment. + +### Module Ibc + +The module ibc handler is a mutable entry point of the contract. It is similar to the `execute` handler but is +specifically geared towards handling module-to-module IBC calls. On this endpoint, the sender is a module on a remote chain. Module developers should test the `client_chain` AND `source_module` variables against their local storage. Without it, any module could execute the logic inside this functio + + + +
+ +#### Function Signature + +```rust,ignore +{{#include ../../../packages/abstract-sdk/src/base/contract_base.rs:module_ibc}} +``` + +#### Message + +Called when the App's `ExecuteMsg::ModuleIbc` variant is called on the execute entry point. The receiving type is not +customizable. It contains : + +- `client_chain` the remote chain identification +- `source_module` the sending module on the remote chain +- `msg` the message sent by the module. This is usually deserialized by the module's developer to trigger actions. + +```rust,ignore +{{#include ../../../packages/abstract-core/src/base.rs:exec}} + +{{#include ../../../packages/abstract-core/src/native/ibc.rs:module_ibc_msg}} +``` + +
+ ## Dependencies There is another method accessible on the module builder, which is the `with_dependencies` function. As it states it diff --git a/framework/packages/abstract-adapter/Cargo.toml b/framework/packages/abstract-adapter/Cargo.toml index db900a905e..5f0f64d988 100644 --- a/framework/packages/abstract-adapter/Cargo.toml +++ b/framework/packages/abstract-adapter/Cargo.toml @@ -34,6 +34,8 @@ abstract-testing = { workspace = true, optional = true } cw-orch = { workspace = true, optional = true } # Keep this as a version and update when publishing new versions abstract-interface = { path = "../../packages/abstract-interface", version = "0.21.0", optional = true } +abstract-ibc-client = { version = "0.21.0", path = "../../contracts/native/ibc-client" } +abstract-ibc-host = { version = "0.21.0", path = "../../contracts/native/ibc-host" } [dev-dependencies] speculoos = { workspace = true } diff --git a/framework/packages/abstract-adapter/src/endpoints.rs b/framework/packages/abstract-adapter/src/endpoints.rs index 0c7537f2f5..9ba4355142 100644 --- a/framework/packages/abstract-adapter/src/endpoints.rs +++ b/framework/packages/abstract-adapter/src/endpoints.rs @@ -1,6 +1,7 @@ mod execute; mod ibc_callback; mod instantiate; +mod module_ibc; mod query; mod receive; mod reply; diff --git a/framework/packages/abstract-adapter/src/endpoints/execute.rs b/framework/packages/abstract-adapter/src/endpoints/execute.rs index ab680370bf..42ec1cfbf9 100644 --- a/framework/packages/abstract-adapter/src/endpoints/execute.rs +++ b/framework/packages/abstract-adapter/src/endpoints/execute.rs @@ -1,5 +1,5 @@ use abstract_sdk::{ - base::{ExecuteEndpoint, Handler, IbcCallbackEndpoint, ReceiveEndpoint}, + base::{ExecuteEndpoint, Handler, IbcCallbackEndpoint, ModuleIbcEndpoint, ReceiveEndpoint}, features::ModuleIdentification, AbstractResponse, AccountVerification, }; @@ -44,6 +44,7 @@ impl< .map_err(From::from), ExecuteMsg::IbcCallback(msg) => self.ibc_callback(deps, env, info, msg), ExecuteMsg::Receive(msg) => self.receive(deps, env, info, msg), + ExecuteMsg::ModuleIbc(msg) => self.module_ibc(deps, env, info, msg), } } } diff --git a/framework/packages/abstract-adapter/src/endpoints/ibc_callback.rs b/framework/packages/abstract-adapter/src/endpoints/ibc_callback.rs index b896ca0393..040a805c5f 100644 --- a/framework/packages/abstract-adapter/src/endpoints/ibc_callback.rs +++ b/framework/packages/abstract-adapter/src/endpoints/ibc_callback.rs @@ -1,5 +1,8 @@ -use abstract_sdk::{base::IbcCallbackEndpoint, features::AbstractRegistryAccess, AbstractSdkError}; -use abstract_std::{objects::module::ModuleInfo, AbstractError, IBC_CLIENT}; +use abstract_sdk::{base::IbcCallbackEndpoint, features::AbstractRegistryAccess}; +use abstract_std::{ + objects::module::{ModuleInfo, ModuleVersion}, + AbstractError, IBC_CLIENT, +}; use cosmwasm_std::{Addr, Deps}; use crate::{state::ContractError, AdapterContract}; @@ -12,21 +15,14 @@ impl::into)?; - Ok(vc_query_result.reference.unwrap_native().map_err(|err| { - let err: AbstractSdkError = err.into(); - err - })?) + Ok(vc_query_result.reference.unwrap_native()?) } } diff --git a/framework/packages/abstract-adapter/src/endpoints/instantiate.rs b/framework/packages/abstract-adapter/src/endpoints/instantiate.rs index a69c1a3fc0..4e4cf68942 100644 --- a/framework/packages/abstract-adapter/src/endpoints/instantiate.rs +++ b/framework/packages/abstract-adapter/src/endpoints/instantiate.rs @@ -2,13 +2,16 @@ use abstract_sdk::{ base::{Handler, InstantiateEndpoint}, feature_objects::{AnsHost, VersionControlContract}, }; -use abstract_std::{adapter::InstantiateMsg, objects::module_version::set_module_data}; +use abstract_std::{ + adapter::{AdapterState, InstantiateMsg}, + objects::module_version::set_module_data, +}; use cosmwasm_std::{DepsMut, Env, MessageInfo, Response}; use cw2::set_contract_version; use schemars::JsonSchema; use serde::Serialize; -use crate::state::{AdapterContract, ApiState, ContractError}; +use crate::state::{AdapterContract, ContractError}; impl< Error: ContractError, @@ -38,7 +41,7 @@ impl< }; // Base state - let state = ApiState { + let state = AdapterState { version_control, ans_host, }; @@ -61,7 +64,7 @@ mod tests { feature_objects::{AnsHost, VersionControlContract}, }; use abstract_std::{ - adapter::{BaseInstantiateMsg, InstantiateMsg}, + adapter::{AdapterState, BaseInstantiateMsg, InstantiateMsg}, objects::module_version::{ModuleData, MODULE}, }; use abstract_testing::prelude::*; @@ -72,10 +75,7 @@ mod tests { use cw2::{ContractVersion, CONTRACT}; use speculoos::prelude::*; - use crate::{ - mock::{AdapterMockResult, MockInitMsg, MOCK_ADAPTER, MOCK_DEP, TEST_METADATA}, - state::ApiState, - }; + use crate::mock::{AdapterMockResult, MockInitMsg, MOCK_ADAPTER, MOCK_DEP, TEST_METADATA}; #[test] fn successful() -> AdapterMockResult { @@ -115,7 +115,7 @@ mod tests { assert!(none_authorized); let state = api.base_state.load(&deps.storage)?; - assert_that!(state).is_equal_to(ApiState { + assert_that!(state).is_equal_to(AdapterState { version_control: VersionControlContract { address: Addr::unchecked(TEST_VERSION_CONTROL), }, diff --git a/framework/packages/abstract-adapter/src/endpoints/module_ibc.rs b/framework/packages/abstract-adapter/src/endpoints/module_ibc.rs new file mode 100644 index 0000000000..7b2032db5f --- /dev/null +++ b/framework/packages/abstract-adapter/src/endpoints/module_ibc.rs @@ -0,0 +1,27 @@ +use crate::{state::ContractError, AdapterContract}; +use abstract_sdk::{base::ModuleIbcEndpoint, features::AbstractRegistryAccess}; +use abstract_std::{ + objects::module::{ModuleInfo, ModuleVersion}, + AbstractError, IBC_HOST, +}; +use cosmwasm_std::Addr; + +impl + ModuleIbcEndpoint + for AdapterContract +{ + fn ibc_host(&self, deps: cosmwasm_std::Deps) -> Result { + let vc_query_result = self + .abstract_registry(deps)? + .query_module( + ModuleInfo::from_id( + IBC_HOST, + ModuleVersion::from(abstract_ibc_host::contract::CONTRACT_VERSION), + )?, + &deps.querier, + ) + .map_err(Into::::into)?; + + Ok(vc_query_result.reference.unwrap_native()?) + } +} diff --git a/framework/packages/abstract-adapter/src/lib.rs b/framework/packages/abstract-adapter/src/lib.rs index 5b033d90c6..68cc01ad33 100644 --- a/framework/packages/abstract-adapter/src/lib.rs +++ b/framework/packages/abstract-adapter/src/lib.rs @@ -133,7 +133,7 @@ pub mod mock { }) .with_sudo(|_, _, _, _| Ok(Response::new().set_data("mock_sudo".as_bytes()))) .with_receive(|_, _, _, _, _| Ok(Response::new().set_data("mock_receive".as_bytes()))) - .with_ibc_callbacks(&[("c_id", |deps, _, _, _, _, _| { + .with_ibc_callbacks(&[("c_id", |deps, _, _, _, _| { IBC_CALLBACK_RECEIVED.save(deps.storage, &true).unwrap(); Ok(Response::new().set_data("mock_callback".as_bytes())) })]) diff --git a/framework/packages/abstract-adapter/src/schema.rs b/framework/packages/abstract-adapter/src/schema.rs index a200e50b22..2111b7b4b8 100644 --- a/framework/packages/abstract-adapter/src/schema.rs +++ b/framework/packages/abstract-adapter/src/schema.rs @@ -16,6 +16,7 @@ impl< Error: From + From + From + + From + 'static, CustomExecMsg: Serialize + JsonSchema + AdapterExecuteMsg, CustomInitMsg: Serialize + JsonSchema, diff --git a/framework/packages/abstract-adapter/src/state.rs b/framework/packages/abstract-adapter/src/state.rs index ae73ce425c..ce002eba6d 100644 --- a/framework/packages/abstract-adapter/src/state.rs +++ b/framework/packages/abstract-adapter/src/state.rs @@ -1,20 +1,15 @@ -use std::fmt::Debug; - use abstract_sdk::{ base::{ AbstractContract, ExecuteHandlerFn, Handler, IbcCallbackHandlerFn, InstantiateHandlerFn, - QueryHandlerFn, ReceiveHandlerFn, ReplyHandlerFn, SudoHandlerFn, + ModuleIbcHandlerFn, QueryHandlerFn, ReceiveHandlerFn, ReplyHandlerFn, SudoHandlerFn, }, - feature_objects::{AnsHost, VersionControlContract}, namespaces::BASE_STATE, std::version_control::AccountBase, AbstractSdkError, }; -use abstract_std::objects::dependency::StaticDependency; +use abstract_std::{adapter::AdapterState, objects::dependency::StaticDependency, AbstractError}; use cosmwasm_std::{Addr, Empty, StdError, StdResult, Storage}; use cw_storage_plus::{Item, Map}; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; use crate::AdapterError; @@ -22,24 +17,22 @@ pub const AUTHORIZED_ADDRESSES_NAMESPACE: &str = "authorized_addresses"; pub const MAXIMUM_AUTHORIZED_ADDRESSES: u32 = 15; pub trait ContractError: - From + From + From + 'static + From + + From + + From + + From + + 'static { } impl ContractError for T where - T: From + From + From + 'static + T: From + + From + + From + + From + + 'static { } -/// The BaseState contains the main addresses needed for sending and verifying messages -/// Every DApp should use the provided **ans_host** contract for token/contract address resolution. -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct ApiState { - /// Used to verify requests - pub version_control: VersionControlContract, - /// AnsHost contract struct (address) - pub ans_host: AnsHost, -} - /// The state variables for our AdapterContract. pub struct AdapterContract< Error: ContractError, @@ -52,7 +45,7 @@ pub struct AdapterContract< Self: Handler, { pub(crate) contract: AbstractContract, - pub(crate) base_state: Item<'static, ApiState>, + pub(crate) base_state: Item<'static, AdapterState>, /// Map ProxyAddr -> AuthorizedAddrs pub authorized_addresses: Map<'static, Addr, Vec>, /// The Account on which commands are executed. Set each time in the [`abstract_std::adapter::ExecuteMsg::Base`] handler. @@ -80,7 +73,7 @@ impl StdResult { + pub fn state(&self, store: &dyn Storage) -> StdResult { self.base_state.load(store) } @@ -152,6 +145,15 @@ impl, + ) -> Self { + self.contract = self.contract.with_module_ibc(module_handler); + self + } } #[cfg(test)] @@ -183,7 +185,7 @@ mod tests { .with_query(|_, _, _, _| cosmwasm_std::to_json_binary("mock_query").map_err(Into::into)) .with_sudo(|_, _, _, _| Ok(Response::new().set_data("mock_sudo".as_bytes()))) .with_receive(|_, _, _, _, _| Ok(Response::new().set_data("mock_receive".as_bytes()))) - .with_ibc_callbacks(&[("c_id", |_, _, _, _, _, _| { + .with_ibc_callbacks(&[("c_id", |_, _, _, _, _| { Ok(Response::new().set_data("mock_callback".as_bytes())) })]) .with_replies(&[(1u64, |_, _, _, msg| { diff --git a/framework/packages/abstract-app/Cargo.toml b/framework/packages/abstract-app/Cargo.toml index ad5aed169d..0adf7bbd46 100644 --- a/framework/packages/abstract-app/Cargo.toml +++ b/framework/packages/abstract-app/Cargo.toml @@ -36,6 +36,7 @@ abstract-testing = { workspace = true, optional = true } cw-orch = { workspace = true, optional = true } abstract-interface = { path = "../../packages/abstract-interface", version = "0.21.0", optional = true } +abstract-ibc-host = { version = "0.21.0", path = "../../contracts/native/ibc-host" } [dev-dependencies] cosmwasm-schema = { workspace = true } diff --git a/framework/packages/abstract-app/src/endpoints.rs b/framework/packages/abstract-app/src/endpoints.rs index 9b58d1f888..614995454b 100644 --- a/framework/packages/abstract-app/src/endpoints.rs +++ b/framework/packages/abstract-app/src/endpoints.rs @@ -2,6 +2,7 @@ mod execute; mod ibc_callback; pub mod instantiate; mod migrate; +mod module_ibc; mod query; mod receive; mod reply; diff --git a/framework/packages/abstract-app/src/endpoints/execute.rs b/framework/packages/abstract-app/src/endpoints/execute.rs index 8cd91c56aa..7558265a13 100644 --- a/framework/packages/abstract-app/src/endpoints/execute.rs +++ b/framework/packages/abstract-app/src/endpoints/execute.rs @@ -1,6 +1,9 @@ -use abstract_sdk::{base::ReceiveEndpoint, features::AbstractResponse}; +use abstract_sdk::{ + base::{ModuleIbcEndpoint, ReceiveEndpoint}, + features::AbstractResponse, +}; use abstract_std::app::{AppExecuteMsg, BaseExecuteMsg, ExecuteMsg}; -use cosmwasm_std::{DepsMut, Env, MessageInfo, Response, StdError}; +use cosmwasm_std::{DepsMut, Env, MessageInfo, Response}; use schemars::JsonSchema; use serde::Serialize; @@ -48,8 +51,7 @@ impl< .map_err(From::from), ExecuteMsg::IbcCallback(msg) => self.ibc_callback(deps, env, info, msg), ExecuteMsg::Receive(msg) => self.receive(deps, env, info, msg), - #[allow(unreachable_patterns)] - _ => Err(StdError::generic_err("Unsupported App execute message variant").into()), + ExecuteMsg::ModuleIbc(msg) => self.module_ibc(deps, env, info, msg), } } } diff --git a/framework/packages/abstract-app/src/endpoints/instantiate.rs b/framework/packages/abstract-app/src/endpoints/instantiate.rs index 4cfd40de35..b0269082ee 100644 --- a/framework/packages/abstract-app/src/endpoints/instantiate.rs +++ b/framework/packages/abstract-app/src/endpoints/instantiate.rs @@ -1,6 +1,6 @@ use abstract_sdk::feature_objects::{AnsHost, VersionControlContract}; use abstract_std::{ - app::{BaseInstantiateMsg, InstantiateMsg}, + app::{AppState, BaseInstantiateMsg, InstantiateMsg}, objects::module_version::set_module_data, }; use cosmwasm_std::{DepsMut, Env, MessageInfo, Response}; @@ -9,7 +9,7 @@ use schemars::JsonSchema; use serde::{de::DeserializeOwned, Serialize}; use crate::{ - state::{AppContract, AppState, ContractError}, + state::{AppContract, ContractError}, Handler, InstantiateEndpoint, }; diff --git a/framework/packages/abstract-app/src/endpoints/module_ibc.rs b/framework/packages/abstract-app/src/endpoints/module_ibc.rs new file mode 100644 index 0000000000..5dabee991b --- /dev/null +++ b/framework/packages/abstract-app/src/endpoints/module_ibc.rs @@ -0,0 +1,43 @@ +use abstract_sdk::{base::ModuleIbcEndpoint, features::AbstractRegistryAccess}; +use abstract_std::{ + objects::module::{ModuleInfo, ModuleVersion}, + AbstractError, IBC_HOST, +}; +use cosmwasm_std::Addr; + +use crate::{state::ContractError, AppContract}; + +impl< + Error: ContractError, + CustomInitMsg, + CustomExecMsg, + CustomQueryMsg, + CustomMigrateMsg, + ReceiveMsg, + SudoMsg, + > ModuleIbcEndpoint + for AppContract< + Error, + CustomInitMsg, + CustomExecMsg, + CustomQueryMsg, + CustomMigrateMsg, + ReceiveMsg, + SudoMsg, + > +{ + fn ibc_host(&self, deps: cosmwasm_std::Deps) -> Result { + let vc_query_result = self + .abstract_registry(deps)? + .query_module( + ModuleInfo::from_id( + IBC_HOST, + ModuleVersion::from(abstract_ibc_host::contract::CONTRACT_VERSION), + )?, + &deps.querier, + ) + .map_err(Into::::into)?; + + Ok(vc_query_result.reference.unwrap_native()?) + } +} diff --git a/framework/packages/abstract-app/src/lib.rs b/framework/packages/abstract-app/src/lib.rs index d7d33b9714..3b19f4795f 100644 --- a/framework/packages/abstract-app/src/lib.rs +++ b/framework/packages/abstract-app/src/lib.rs @@ -155,7 +155,7 @@ pub mod mock { }) .with_sudo(|_, _, _, _| Ok(Response::new().set_data("mock_sudo".as_bytes()))) .with_receive(|_, _, _, _, _| Ok(Response::new().set_data("mock_receive".as_bytes()))) - .with_ibc_callbacks(&[("c_id", |deps, _, _, _, _, _| { + .with_ibc_callbacks(&[("c_id", |deps, _, _, _, _| { IBC_CALLBACK_RECEIVED.save(deps.storage, &true).unwrap(); Ok(Response::new().add_attribute("mock_callback", "executed")) diff --git a/framework/packages/abstract-app/src/state.rs b/framework/packages/abstract-app/src/state.rs index a3032102e2..0c1f72f734 100644 --- a/framework/packages/abstract-app/src/state.rs +++ b/framework/packages/abstract-app/src/state.rs @@ -1,17 +1,15 @@ use abstract_sdk::{ - base::SudoHandlerFn, - feature_objects::{AnsHost, VersionControlContract}, + base::{ModuleIbcHandlerFn, SudoHandlerFn}, namespaces::{ADMIN_NAMESPACE, BASE_STATE}, AbstractSdkError, }; use abstract_std::{ + app::AppState, objects::{dependency::StaticDependency, nested_admin::NestedAdmin}, AbstractError, }; -use cosmwasm_std::{Addr, Empty, StdResult, Storage}; +use cosmwasm_std::{Empty, StdResult, Storage}; use cw_storage_plus::Item; -use schemars::JsonSchema; -use serde::{Deserialize, Serialize}; use crate::{ AbstractContract, AppError, ExecuteHandlerFn, IbcCallbackHandlerFn, InstantiateHandlerFn, @@ -36,17 +34,6 @@ impl ContractError for T where { } -/// The BaseState contains the main addresses needed for sending and verifying messages -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct AppState { - /// Proxy contract address for relaying transactions - pub proxy_address: Addr, - /// AnsHost contract struct (address) - pub ans_host: AnsHost, - /// Used to verify requests - pub version_control: VersionControlContract, -} - /// The state variables for our AppContract. pub struct AppContract< Error: ContractError, @@ -176,6 +163,15 @@ impl< self.contract = self.contract.with_ibc_callbacks(callbacks); self } + + /// add Module IBC to contract + pub const fn with_module_ibc( + mut self, + module_handler: ModuleIbcHandlerFn, + ) -> Self { + self.contract = self.contract.with_module_ibc(module_handler); + self + } } #[cfg(test)] @@ -193,7 +189,7 @@ mod tests { .with_query(|_, _, _, _| cosmwasm_std::to_json_binary("mock_query").map_err(Into::into)) .with_sudo(|_, _, _, _| Ok(Response::new().set_data("mock_sudo".as_bytes()))) .with_receive(|_, _, _, _, _| Ok(Response::new().set_data("mock_receive".as_bytes()))) - .with_ibc_callbacks(&[("c_id", |_, _, _, _, _, _| { + .with_ibc_callbacks(&[("c_id", |_, _, _, _, _| { Ok(Response::new().set_data("mock_callback".as_bytes())) })]) .with_replies(&[(1u64, |_, _, _, msg| { diff --git a/framework/packages/abstract-interface/src/deployment.rs b/framework/packages/abstract-interface/src/deployment.rs index 3ea6bba906..bfdf94b606 100644 --- a/framework/packages/abstract-interface/src/deployment.rs +++ b/framework/packages/abstract-interface/src/deployment.rs @@ -256,6 +256,10 @@ impl Abstract { self.ibc.client.as_instance(), ibc_client::contract::CONTRACT_VERSION.to_string(), ), + ( + self.ibc.host.as_instance(), + ibc_host::contract::CONTRACT_VERSION.to_string(), + ), ] } } diff --git a/framework/packages/abstract-sdk/src/base/contract_base.rs b/framework/packages/abstract-sdk/src/base/contract_base.rs index 62583f4d61..40827bef55 100644 --- a/framework/packages/abstract-sdk/src/base/contract_base.rs +++ b/framework/packages/abstract-sdk/src/base/contract_base.rs @@ -1,7 +1,7 @@ +use abstract_std::ibc::{IbcResponseMsg, ModuleIbcMsg}; use cosmwasm_std::{Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, Storage}; use cw2::{ContractVersion, CONTRACT}; use cw_storage_plus::Item; -use polytone::callbacks::Callback; use super::handler::Handler; use crate::{std::objects::dependency::StaticDependency, AbstractSdkError, AbstractSdkResult}; @@ -29,13 +29,18 @@ pub type QueryHandlerFn = fn(Deps, Env, &Module, CustomQueryMsg) -> Result; // ANCHOR_END: query -type CallbackMessage = Option; // ANCHOR: ibc /// Function signature for an IBC callback handler. pub type IbcCallbackHandlerFn = - fn(DepsMut, Env, MessageInfo, Module, CallbackMessage, Callback) -> Result; + fn(DepsMut, Env, MessageInfo, Module, IbcResponseMsg) -> Result; // ANCHOR_END: ibc +// ANCHOR: module_ibc +/// Function signature for an Module to Module IBC handler. +pub type ModuleIbcHandlerFn = + fn(DepsMut, Env, Module, ModuleIbcMsg) -> Result; +// ANCHOR_END: module_ibc + // ANCHOR: mig /// Function signature for a migrate handler. pub type MigrateHandlerFn = @@ -94,6 +99,8 @@ pub struct AbstractContract)], + /// Module IBC handler for passing messages between a module on different chains. + pub(crate) module_ibc_handler: Option>, } impl> AbstractContract @@ -114,6 +121,7 @@ where sudo_handler: None, instantiate_handler: None, query_handler: None, + module_ibc_handler: None, } } /// Gets the cw2 version of the contract. @@ -147,6 +155,15 @@ where self } + /// add IBC callback handler to contract + pub const fn with_module_ibc( + mut self, + module_handler: ModuleIbcHandlerFn, + ) -> Self { + self.module_ibc_handler = Some(module_handler); + self + } + /// Add instantiate handler to the contract. pub const fn with_instantiate( mut self, @@ -360,7 +377,7 @@ mod test { fn test_with_ibc_callback_handlers() { const IBC_ID: &str = "aoeu"; const HANDLER: IbcCallbackHandlerFn = - |_, _, _, _, _, _| Ok(Response::default().add_attribute("test", "ibc")); + |_, _, _, _, _| Ok(Response::default().add_attribute("test", "ibc")); let contract = MockAppContract::new("test_contract", "0.1.0", ModuleMetadata::default()) .with_ibc_callbacks(&[(IBC_ID, HANDLER)]); diff --git a/framework/packages/abstract-sdk/src/base/endpoints.rs b/framework/packages/abstract-sdk/src/base/endpoints.rs index d8176e9c53..f0d3d54240 100644 --- a/framework/packages/abstract-sdk/src/base/endpoints.rs +++ b/framework/packages/abstract-sdk/src/base/endpoints.rs @@ -130,6 +130,7 @@ mod execute; mod ibc_callback; mod instantiate; pub(crate) mod migrate; +mod modules_ibc; mod query; mod receive; mod reply; @@ -140,6 +141,7 @@ pub use execute::ExecuteEndpoint; pub use ibc_callback::IbcCallbackEndpoint; pub use instantiate::InstantiateEndpoint; pub use migrate::MigrateEndpoint; +pub use modules_ibc::ModuleIbcEndpoint; pub use query::QueryEndpoint; pub use receive::ReceiveEndpoint; pub use reply::ReplyEndpoint; diff --git a/framework/packages/abstract-sdk/src/base/endpoints/ibc_callback.rs b/framework/packages/abstract-sdk/src/base/endpoints/ibc_callback.rs index fd387eb5b3..08217cb01a 100644 --- a/framework/packages/abstract-sdk/src/base/endpoints/ibc_callback.rs +++ b/framework/packages/abstract-sdk/src/base/endpoints/ibc_callback.rs @@ -25,15 +25,10 @@ pub trait IbcCallbackEndpoint: Handler { } .into()); }; - let IbcResponseMsg { - id, - msg: callback_msg, - result, - } = msg; - let maybe_handler = self.maybe_ibc_callback_handler(&id); + let maybe_handler = self.maybe_ibc_callback_handler(&msg.id); maybe_handler.map_or_else( || Ok(Response::new()), - |handler| handler(deps, env, info, self, callback_msg, result), + |handler| handler(deps, env, info, self, msg), ) } } diff --git a/framework/packages/abstract-sdk/src/base/endpoints/modules_ibc.rs b/framework/packages/abstract-sdk/src/base/endpoints/modules_ibc.rs new file mode 100644 index 0000000000..ad6ded7c67 --- /dev/null +++ b/framework/packages/abstract-sdk/src/base/endpoints/modules_ibc.rs @@ -0,0 +1,38 @@ +use crate::features::ModuleIdentification; +use crate::{base::Handler, AbstractSdkError}; +use abstract_std::ibc::ModuleIbcMsg; +use cosmwasm_std::{Addr, Deps, DepsMut, Env, MessageInfo, Response}; + +/// Trait for a contract to call itself on an IBC counterpart. +pub trait ModuleIbcEndpoint: Handler { + /// Get the address of the ibc host associated with this module + fn ibc_host(&self, deps: Deps) -> Result; + + /// Handler for the `ExecuteMsg::ModuleIbc(ModuleIbcMsg)` variant. + fn module_ibc( + self, + deps: DepsMut, + env: Env, + info: MessageInfo, + msg: ModuleIbcMsg, + ) -> Result { + // Only an IBC host can call this endpoint + let ibc_host = self.ibc_host(deps.as_ref())?; + if info.sender.ne(&ibc_host) { + return Err(AbstractSdkError::ModuleIbcNotCalledByHost { + caller: info.sender, + host_addr: ibc_host, + module: self.info().0.to_string(), + } + .into()); + }; + + // If there is no handler and this endpoint is called we need to error + let handler = + self.maybe_module_ibc_handler() + .ok_or(AbstractSdkError::NoModuleIbcHandler( + self.module_id().to_string(), + ))?; + handler(deps, env, self, msg) + } +} diff --git a/framework/packages/abstract-sdk/src/base/handler.rs b/framework/packages/abstract-sdk/src/base/handler.rs index 6d717563ab..882418d62d 100644 --- a/framework/packages/abstract-sdk/src/base/handler.rs +++ b/framework/packages/abstract-sdk/src/base/handler.rs @@ -4,7 +4,7 @@ use cw2::ContractVersion; use super::contract_base::{ AbstractContract, ExecuteHandlerFn, IbcCallbackHandlerFn, InstantiateHandlerFn, - MigrateHandlerFn, QueryHandlerFn, ReceiveHandlerFn, SudoHandlerFn, + MigrateHandlerFn, ModuleIbcHandlerFn, QueryHandlerFn, ReceiveHandlerFn, SudoHandlerFn, }; use crate::{ base::{ @@ -176,6 +176,11 @@ where } None } + /// Get an IBC module call handler if it exists. + fn maybe_module_ibc_handler(&self) -> Option> { + let contract = self.contract(); + contract.module_ibc_handler + } /// Get a reply handler if it exists. fn maybe_reply_handler(&self, id: u64) -> Option> { let contract = self.contract(); diff --git a/framework/packages/abstract-sdk/src/base/mod.rs b/framework/packages/abstract-sdk/src/base/mod.rs index 21aed52fd0..6bde48aa83 100644 --- a/framework/packages/abstract-sdk/src/base/mod.rs +++ b/framework/packages/abstract-sdk/src/base/mod.rs @@ -9,11 +9,11 @@ mod handler; pub use contract_base::{ AbstractContract, ExecuteHandlerFn, IbcCallbackHandlerFn, InstantiateHandlerFn, - MigrateHandlerFn, QueryHandlerFn, ReceiveHandlerFn, ReplyHandlerFn, SudoHandlerFn, - VersionString, + MigrateHandlerFn, ModuleIbcHandlerFn, QueryHandlerFn, ReceiveHandlerFn, ReplyHandlerFn, + SudoHandlerFn, VersionString, }; pub use endpoints::{ - ExecuteEndpoint, IbcCallbackEndpoint, InstantiateEndpoint, MigrateEndpoint, QueryEndpoint, - ReceiveEndpoint, ReplyEndpoint, SudoEndpoint, + ExecuteEndpoint, IbcCallbackEndpoint, InstantiateEndpoint, MigrateEndpoint, ModuleIbcEndpoint, + QueryEndpoint, ReceiveEndpoint, ReplyEndpoint, SudoEndpoint, }; pub use handler::Handler; diff --git a/framework/packages/abstract-sdk/src/error.rs b/framework/packages/abstract-sdk/src/error.rs index 92fd1b31e7..3f27e1e11f 100644 --- a/framework/packages/abstract-sdk/src/error.rs +++ b/framework/packages/abstract-sdk/src/error.rs @@ -54,6 +54,18 @@ pub enum AbstractSdkError { module: String, }, + // callback not called by IBC host + #[error("Module {module} Ibc Endpoint called by {caller} instead of IBC host {host_addr}.")] + ModuleIbcNotCalledByHost { + caller: Addr, + host_addr: Addr, + module: String, + }, + + // callback not called by IBC host + #[error("Called an IBC module action on {0}, when no endpoint was registered.")] + NoModuleIbcHandler(String), + // admin of proxy is not set #[error("Admin of proxy {proxy_addr} is not set.")] AdminNotSet { proxy_addr: Addr }, diff --git a/framework/packages/abstract-sdk/src/feature_objects.rs b/framework/packages/abstract-sdk/src/feature_objects.rs index 010d5e6c2f..44df98a16d 100644 --- a/framework/packages/abstract-sdk/src/feature_objects.rs +++ b/framework/packages/abstract-sdk/src/feature_objects.rs @@ -5,7 +5,7 @@ //! requiring the usage of a base contract. pub use abstract_std::objects::{ans_host::AnsHost, version_control::VersionControlContract}; -use abstract_std::version_control::AccountBase; +use abstract_std::{version_control::AccountBase, VERSION_CONTROL}; use cosmwasm_std::{Addr, Deps}; use crate::{ @@ -70,6 +70,12 @@ impl crate::features::AbstractRegistryAccess for VersionControlContract { } } +impl ModuleIdentification for VersionControlContract { + fn module_id(&self) -> abstract_std::objects::module::ModuleId<'static> { + VERSION_CONTROL + } +} + impl crate::features::AbstractNameService for AnsHost { fn ans_host(&self, _deps: Deps) -> AbstractSdkResult { Ok(self.clone()) diff --git a/framework/packages/abstract-std/src/adapter.rs b/framework/packages/abstract-std/src/adapter.rs index 38e43a8e66..021a830f48 100644 --- a/framework/packages/abstract-std/src/adapter.rs +++ b/framework/packages/abstract-std/src/adapter.rs @@ -16,7 +16,10 @@ use crate::{ ExecuteMsg as MiddlewareExecMsg, InstantiateMsg as MiddlewareInstantiateMsg, QueryMsg as MiddlewareQueryMsg, }, - objects::module_version::ModuleDataResponse, + objects::{ + ans_host::AnsHost, module_version::ModuleDataResponse, + version_control::VersionControlContract, + }, }; pub type ExecuteMsg = @@ -156,3 +159,13 @@ pub struct AuthorizedAddressesResponse { /// Contains all authorized addresses pub addresses: Vec, } + +/// The BaseState contains the main addresses needed for sending and verifying messages +/// Every DApp should use the provided **ans_host** contract for token/contract address resolution. +#[cosmwasm_schema::cw_serde] +pub struct AdapterState { + /// Used to verify requests + pub version_control: VersionControlContract, + /// AnsHost contract struct (address) + pub ans_host: AnsHost, +} diff --git a/framework/packages/abstract-std/src/app.rs b/framework/packages/abstract-std/src/app.rs index 97e3952112..81f7b75b2a 100644 --- a/framework/packages/abstract-std/src/app.rs +++ b/framework/packages/abstract-std/src/app.rs @@ -9,7 +9,10 @@ use crate::{ ExecuteMsg as EndpointExecMsg, InstantiateMsg as EndpointInstantiateMsg, MigrateMsg as EndpointMigrateMsg, QueryMsg as EndpointQueryMsg, }, - objects::{module_version::ModuleDataResponse, nested_admin::TopLevelOwnerResponse}, + objects::{ + ans_host::AnsHost, module_version::ModuleDataResponse, nested_admin::TopLevelOwnerResponse, + version_control::VersionControlContract, + }, version_control::AccountBase, }; @@ -110,3 +113,14 @@ pub struct AppConfigResponse { #[cosmwasm_schema::cw_serde] pub struct BaseMigrateMsg {} + +/// The BaseState contains the main addresses needed for sending and verifying messages +#[cosmwasm_schema::cw_serde] +pub struct AppState { + /// Proxy contract address for relaying transactions + pub proxy_address: Addr, + /// AnsHost contract struct (address) + pub ans_host: AnsHost, + /// Used to verify requests + pub version_control: VersionControlContract, +} diff --git a/framework/packages/abstract-std/src/base.rs b/framework/packages/abstract-std/src/base.rs index 386df1e96f..f6bf663435 100644 --- a/framework/packages/abstract-std/src/base.rs +++ b/framework/packages/abstract-std/src/base.rs @@ -1,7 +1,7 @@ use cosmwasm_schema::QueryResponses; use cosmwasm_std::Empty; -use crate::ibc::IbcResponseMsg; +use crate::ibc::{IbcResponseMsg, ModuleIbcMsg}; // ANCHOR: exec /// Wrapper around all possible messages that can be sent to the module. @@ -14,6 +14,10 @@ pub enum ExecuteMsg { /// IbcReceive to process IBC callbacks /// In order to trust this, the apps and adapters verify this comes from the ibc-client contract. IbcCallback(IbcResponseMsg), + /// ModuleIbc endpoint to receive messages from modules on other chains + /// In order to trust this, the apps and adapters verify this comes from the ibc-host contract. + /// They should also trust the sending chain + ModuleIbc(ModuleIbcMsg), /// Receive endpoint for CW20 / external service integrations Receive(ReceiveMsg), } diff --git a/framework/packages/abstract-std/src/native/ibc.rs b/framework/packages/abstract-std/src/native/ibc.rs index 65b62bf881..9a20dc1ad8 100644 --- a/framework/packages/abstract-std/src/native/ibc.rs +++ b/framework/packages/abstract-std/src/native/ibc.rs @@ -1,8 +1,17 @@ -use cosmwasm_std::{to_json_binary, wasm_execute, Binary, CosmosMsg, StdResult}; -use polytone::callbacks::Callback; +use cosmwasm_schema::cw_serde; +use cosmwasm_std::{ + to_json_binary, wasm_execute, Binary, CosmosMsg, Empty, QueryRequest, StdError, StdResult, +}; +use polytone::callbacks::{Callback, ErrorResponse, ExecutionResponse}; use schemars::JsonSchema; -// CallbackInfo from modules, that is turned into an IbcResponseMsg by the ibc client +use crate::{ + base::ExecuteMsg, + objects::{chain_name::ChainName, module::ModuleInfo}, +}; + +/// CallbackInfo from modules, that is turned into an IbcResponseMsg by the ibc client +/// A callback can only be sent to itself #[cosmwasm_schema::cw_serde] pub struct CallbackInfo { /// Used to identify the callback that is sent (acts like the reply ID) @@ -10,8 +19,6 @@ pub struct CallbackInfo { /// Used to add information to the callback. /// This is usually used to provide information to the ibc callback function for context pub msg: Option, - /// Contract that will be called with the callback message - pub receiver: String, } /// IbcResponseMsg should be de/serialized under `IbcCallback()` variant in a ExecuteMsg @@ -22,13 +29,13 @@ pub struct IbcResponseMsg { /// The msg sent with the callback request. /// This is usually used to provide information to the ibc callback function for context pub msg: Option, - pub result: Callback, + pub result: CallbackResult, } impl IbcResponseMsg { /// serializes the message pub fn into_json_binary(self) -> StdResult { - let msg = IbcCallbackMsg::IbcCallback(self); + let msg = ExecuteMsg::IbcCallback::(self); to_json_binary(&msg) } @@ -39,16 +46,67 @@ impl IbcResponseMsg { { Ok(wasm_execute( contract_addr.into(), - &IbcCallbackMsg::IbcCallback(self), + &ExecuteMsg::IbcCallback::(self), vec![], )? .into()) } } -/// This is just a helper to properly serialize the above message. -/// The actual receiver should include this variant in the larger ExecuteMsg enum #[cosmwasm_schema::cw_serde] -pub(crate) enum IbcCallbackMsg { - IbcCallback(IbcResponseMsg), +pub enum CallbackResult { + Query { + query: QueryRequest, + result: Result, ErrorResponse>, + }, + + Execute { + initiator_msg: Binary, + result: Result, + }, + + /// An error occured that could not be recovered from. The only + /// known way that this can occur is message handling running out + /// of gas, in which case the error will be `codespace: sdk, code: + /// 11`. + /// + /// This error is not named becuase it could also occur due to a + /// panic or unhandled error during message processing. We don't + /// expect this to happen and have carefully written the code to + /// avoid it. + FatalError(String), +} + +impl CallbackResult { + pub fn from_query(callback: Callback, query: QueryRequest) -> Result { + match callback { + Callback::Query(q) => Ok(Self::Query { query, result: q }), + Callback::Execute(_) => Err(StdError::generic_err( + "Expected a query result, got an execute result", + )), + Callback::FatalError(e) => Ok(Self::FatalError(e)), + } + } + + pub fn from_execute(callback: Callback, initiator_msg: Binary) -> Result { + match callback { + Callback::Query(_) => Err(StdError::generic_err( + "Expected an execution result, got a query result", + )), + Callback::Execute(e) => Ok(Self::Execute { + initiator_msg, + result: e, + }), + Callback::FatalError(e) => Ok(Self::FatalError(e)), + } + } +} + +// ANCHOR: module_ibc_msg +#[cw_serde] +pub struct ModuleIbcMsg { + pub client_chain: ChainName, + pub source_module: ModuleInfo, + pub msg: Binary, } +// ANCHOR_END: module_ibc_msg diff --git a/framework/packages/abstract-std/src/native/ibc_client.rs b/framework/packages/abstract-std/src/native/ibc_client.rs index 150ece3b1c..781ac6e055 100644 --- a/framework/packages/abstract-std/src/native/ibc_client.rs +++ b/framework/packages/abstract-std/src/native/ibc_client.rs @@ -1,12 +1,17 @@ use cosmwasm_schema::QueryResponses; -use cosmwasm_std::{Addr, Coin}; +use cosmwasm_std::{Addr, Binary, Coin, Deps, Empty, QueryRequest, StdError}; use polytone::callbacks::CallbackMessage; use self::state::IbcInfrastructure; use crate::{ + ibc::CallbackInfo, ibc_host::HostAction, - manager::ModuleInstallConfig, - objects::{account::AccountId, chain_name::ChainName, AssetEntry}, + manager::{self, ModuleInstallConfig}, + objects::{ + account::AccountId, chain_name::ChainName, module::ModuleInfo, + module_reference::ModuleReference, version_control::VersionControlContract, AssetEntry, + }, + AbstractError, }; pub mod state { @@ -99,6 +104,17 @@ pub enum ExecuteMsg { namespace: Option, install_modules: Vec, }, + ModuleIbcAction { + host_chain: String, + target_module: ModuleInfo, + msg: Binary, + callback_info: Option, + }, + IbcQuery { + host_chain: String, + query: QueryRequest, + callback_info: CallbackInfo, + }, RemoteAction { // host chain to be executed on // Example: "osmosis" @@ -117,10 +133,100 @@ pub enum ExecuteMsg { /// This enum is used for sending callbacks to the note contract of the IBC client #[cosmwasm_schema::cw_serde] pub enum IbcClientCallback { - CreateAccount { account_id: AccountId }, + ModuleRemoteAction { + sender_address: String, + callback_info: CallbackInfo, + initiator_msg: Binary, + }, + ModuleRemoteQuery { + sender_address: String, + callback_info: CallbackInfo, + query: QueryRequest, + }, + CreateAccount { + account_id: AccountId, + }, WhoAmI {}, } +/// This is used for identifying calling modules +/// For adapters, we don't need the account id because it's independent of an account +/// For apps and standalone, the account id is used to identify the calling module +#[cosmwasm_schema::cw_serde] +pub struct InstalledModuleIdentification { + pub module_info: ModuleInfo, + pub account_id: Option, +} + +#[cosmwasm_schema::cw_serde] +pub struct ModuleAddr { + pub reference: ModuleReference, + pub address: Addr, +} + +impl InstalledModuleIdentification { + pub fn addr( + &self, + deps: Deps, + vc: VersionControlContract, + ) -> Result { + let target_module_resolved = vc.query_module(self.module_info.clone(), &deps.querier)?; + + let no_account_id_error = + StdError::generic_err("Account id not specified in installed module definition"); + + let target_addr = match &target_module_resolved.reference { + ModuleReference::AccountBase(code_id) => { + let target_account_id = self.account_id.clone().ok_or(no_account_id_error)?; + let account_base = vc.account_base(&target_account_id, &deps.querier)?; + + if deps + .querier + .query_wasm_contract_info(&account_base.proxy)? + .code_id + == *code_id + { + account_base.proxy + } else if deps + .querier + .query_wasm_contract_info(&account_base.manager)? + .code_id + == *code_id + { + account_base.manager + } else { + Err(StdError::generic_err( + "Account base contract doesn't correspond to any of the proxy or manager", + ))? + } + } + ModuleReference::Native(addr) => addr.clone(), + ModuleReference::Adapter(addr) => addr.clone(), + ModuleReference::App(_) | ModuleReference::Standalone(_) => { + let target_account_id = self.account_id.clone().ok_or(no_account_id_error)?; + let account_base = vc.account_base(&target_account_id, &deps.querier)?; + + let module_info: manager::ModuleAddressesResponse = deps.querier.query_wasm_smart( + account_base.manager, + &manager::QueryMsg::ModuleAddresses { + ids: vec![self.module_info.id()], + }, + )?; + module_info + .modules + .first() + .ok_or(AbstractError::AppNotInstalled(self.module_info.to_string()))? + .1 + .clone() + } + }; + Ok(ModuleAddr { + reference: target_module_resolved.reference, + address: target_addr, + }) + } +} + #[cosmwasm_schema::cw_serde] #[cfg_attr(feature = "interface", derive(cw_orch::QueryFns))] #[derive(QueryResponses)] @@ -224,11 +330,11 @@ pub struct RemoteProxyResponse { #[cfg(test)] mod tests { use cosmwasm_std::{to_json_binary, CosmosMsg, Empty}; - use polytone::callbacks::Callback; use speculoos::prelude::*; - use crate::ibc::IbcCallbackMsg; - use crate::ibc::IbcResponseMsg; + use crate::app::ExecuteMsg; + use crate::ibc::{CallbackResult, IbcResponseMsg}; + // ... (other test functions) #[test] @@ -237,7 +343,7 @@ mod tests { let callback_id = "15".to_string(); let callback_msg = to_json_binary("15").unwrap(); - let result = Callback::FatalError("ibc execution error".to_string()); + let result = CallbackResult::FatalError("ibc execution error".to_string()); let response_msg = IbcResponseMsg { id: callback_id, @@ -253,7 +359,7 @@ mod tests { assert_that!(actual).is_equal_to(CosmosMsg::Wasm(cosmwasm_std::WasmMsg::Execute { contract_addr: receiver, // we can't test the message because the fields in it are private - msg: to_json_binary(&IbcCallbackMsg::IbcCallback(response_msg)).unwrap(), + msg: to_json_binary(&ExecuteMsg::::IbcCallback(response_msg)).unwrap(), funds: vec![], })) } diff --git a/framework/packages/abstract-std/src/native/ibc_host.rs b/framework/packages/abstract-std/src/native/ibc_host.rs index e1a9f59cc1..c54dec1d0d 100644 --- a/framework/packages/abstract-std/src/native/ibc_host.rs +++ b/framework/packages/abstract-std/src/native/ibc_host.rs @@ -8,12 +8,12 @@ //! The api structure is well-suited for implementing standard interfaces to external services like dexes, lending platforms, etc. use cosmwasm_schema::QueryResponses; -use cosmwasm_std::Addr; +use cosmwasm_std::{Addr, Binary}; use crate::{ - manager, - manager::ModuleInstallConfig, - objects::{account::AccountId, chain_name::ChainName, AssetEntry}, + ibc_client::InstalledModuleIdentification, + manager::{self, ModuleInstallConfig}, + objects::{account::AccountId, chain_name::ChainName, module::ModuleInfo, AssetEntry}, }; pub mod state { @@ -127,6 +127,12 @@ pub enum ExecuteMsg { proxy_address: String, action: HostAction, }, + /// Allows for remote execution from the Polytone implementation on a local module + ModuleExecute { + source_module: InstalledModuleIdentification, + target_module: ModuleInfo, + msg: Binary, + }, } /// Query Host message diff --git a/interchain/interchain-tests/Cargo.toml b/interchain/interchain-tests/Cargo.toml index fad589548e..2c8aede55b 100644 --- a/interchain/interchain-tests/Cargo.toml +++ b/interchain/interchain-tests/Cargo.toml @@ -13,6 +13,7 @@ cw-orch-proto = { workspace = true } abstract-std = { workspace = true, features = ["interface"] } abstract-app = { workspace = true, features = ["test-utils"] } +abstract-sdk = { workspace = true } abstract-adapter = { workspace = true, features = ["test-utils"] } abstract-testing = { workspace = true } abstract-interface = { workspace = true } @@ -27,3 +28,8 @@ ibc-relayer-types = "0.25" cw-orch-polytone = { workspace = true } polytone = { workspace = true } +cosmwasm-schema.workspace = true +cw-controllers = { workspace = true } +cw-storage-plus.workspace = true +thiserror.workspace = true +base64 = "0.22.0" diff --git a/interchain/interchain-tests/src/interchain_accounts.rs b/interchain/interchain-tests/src/interchain_accounts.rs index 113a8e2d39..09d980f4a4 100644 --- a/interchain/interchain-tests/src/interchain_accounts.rs +++ b/interchain/interchain-tests/src/interchain_accounts.rs @@ -93,9 +93,9 @@ mod test { objects::{gov_type::GovernanceDetails, UncheckedChannelEntry}, IBC_CLIENT, ICS20, PROXY, }; - use abstract_testing::prelude::*; + use anyhow::Result as AnyResult; - use cosmwasm_std::{coins, wasm_execute, Uint128}; + use cosmwasm_std::{coins, to_json_binary, wasm_execute, Uint128}; use cw_orch::mock::cw_multi_test::AppResponse; use cw_orch_polytone::Polytone; use ibc_relayer_types::core::ics24_host::identifier::PortId; diff --git a/interchain/interchain-tests/src/lib.rs b/interchain/interchain-tests/src/lib.rs index abe3647377..b9e446c47c 100644 --- a/interchain/interchain-tests/src/lib.rs +++ b/interchain/interchain-tests/src/lib.rs @@ -3,4 +3,5 @@ pub const STARGAZE: &str = "stargaze-1"; pub const OSMOSIS: &str = "osmosis-1"; pub mod interchain_accounts; +pub mod module_to_module_interactions; pub mod setup; diff --git a/interchain/interchain-tests/src/module_to_module_interactions.rs b/interchain/interchain-tests/src/module_to_module_interactions.rs new file mode 100644 index 0000000000..912cfea854 --- /dev/null +++ b/interchain/interchain-tests/src/module_to_module_interactions.rs @@ -0,0 +1,695 @@ +pub use abstract_std::app; +use abstract_std::{ + ibc::{CallbackInfo, CallbackResult, ModuleIbcMsg}, + ibc_client::{self}, + objects::module::ModuleInfo, + IBC_CLIENT, +}; +use cosmwasm_schema::{cw_serde, QueryResponses}; +pub use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info}; +use cosmwasm_std::{ + from_json, to_json_binary, wasm_execute, AllBalanceResponse, Coin, Response, StdError, +}; +use cw_controllers::AdminError; +use cw_storage_plus::Item; + +pub type AppTestResult = Result<(), MockError>; + +abstract_app::app_msg_types!(MockAppContract, MockExecMsg, MockQueryMsg); + +#[cosmwasm_schema::cw_serde] +pub struct MockInitMsg {} + +#[cosmwasm_schema::cw_serde] +#[derive(cw_orch::ExecuteFns)] +#[impl_into(ExecuteMsg)] +pub enum MockExecMsg { + DoSomething {}, + DoSomethingAdmin {}, + DoSomethingIbc { + remote_chain: String, + target_module: ModuleInfo, + }, + QuerySomethingIbc { + remote_chain: String, + address: String, + }, +} + +#[cosmwasm_schema::cw_serde] +#[derive(cw_orch::QueryFns)] +#[impl_into(QueryMsg)] +#[derive(QueryResponses)] +pub enum MockQueryMsg { + #[returns(ReceivedIbcCallbackStatus)] + GetReceivedIbcCallbackStatus {}, + + #[returns(ReceivedIbcQueryCallbackStatus)] + GetReceivedIbcQueryCallbackStatus {}, + + #[returns(ReceivedIbcModuleStatus)] + GetReceivedIbcModuleStatus {}, +} + +#[cosmwasm_schema::cw_serde] +pub struct ReceivedIbcCallbackStatus { + pub received: bool, +} + +#[cosmwasm_schema::cw_serde] +pub struct ReceivedIbcQueryCallbackStatus { + pub balance: Vec, +} + +#[cosmwasm_schema::cw_serde] +pub struct ReceivedIbcModuleStatus { + pub received: ModuleInfo, +} + +#[cosmwasm_schema::cw_serde] +pub struct MockMigrateMsg; + +#[cosmwasm_schema::cw_serde] +pub struct MockReceiveMsg; + +#[cosmwasm_schema::cw_serde] +pub struct MockSudoMsg; + +use abstract_sdk::{AbstractSdkError, ModuleInterface}; +use thiserror::Error; + +use abstract_app::{AppContract, AppError}; + +#[derive(Error, Debug, PartialEq)] +pub enum MockError { + #[error("{0}")] + Std(#[from] StdError), + + #[error("{0}")] + DappError(#[from] AppError), + + #[error("{0}")] + Abstract(#[from] abstract_std::AbstractError), + + #[error("{0}")] + AbstractSdk(#[from] AbstractSdkError), + + #[error("{0}")] + Admin(#[from] AdminError), +} + +pub type MockAppContract = AppContract< + // MockModule, + MockError, + MockInitMsg, + MockExecMsg, + MockQueryMsg, + MockMigrateMsg, + MockReceiveMsg, + MockSudoMsg, +>; + +#[cw_serde] +pub struct IbcModuleToModuleMsg { + ibc_msg: String, +} + +// Easy way to see if an ibc-callback was actually received. +pub const IBC_CALLBACK_RECEIVED: Item = Item::new("ibc_callback_received"); +// Easy way to see if an module ibc called was actually received. +pub const MODULE_IBC_RECEIVED: Item = Item::new("module_ibc_received"); + +// Easy way to see if an ibc-callback was actually received. +pub const IBC_CALLBACK_QUERY_RECEIVED: Item> = Item::new("ibc_callback_query_received"); + +pub const fn mock_app(id: &'static str, version: &'static str) -> MockAppContract { + MockAppContract::new(id, version, None) + .with_instantiate(|deps, _, _, _, _| { + IBC_CALLBACK_RECEIVED.save(deps.storage, &false)?; + Ok(Response::new().set_data("mock_init".as_bytes())) + }) + .with_execute(|deps, _env, _, app, msg| match msg { + MockExecMsg::DoSomethingIbc { + remote_chain, + target_module, + } => { + let ibc_client_addr = app.modules(deps.as_ref()).module_address(IBC_CLIENT)?; + // We send an IBC Client module message + let msg = wasm_execute( + ibc_client_addr, + &ibc_client::ExecuteMsg::ModuleIbcAction { + host_chain: remote_chain, + target_module, + msg: to_json_binary(&IbcModuleToModuleMsg { + ibc_msg: "module_to_module:msg".to_string(), + }) + .unwrap(), + callback_info: Some(CallbackInfo { + id: "c_id".to_string(), + msg: None, + }), + }, + vec![], + )?; + + Ok(Response::new().add_message(msg)) + } + MockExecMsg::QuerySomethingIbc { + address, + remote_chain, + } => { + let ibc_client_addr = app.modules(deps.as_ref()).module_address(IBC_CLIENT)?; + // We send an IBC Client module message + let msg = wasm_execute( + ibc_client_addr, + &ibc_client::ExecuteMsg::IbcQuery { + host_chain: remote_chain, + callback_info: CallbackInfo { + id: "query_id".to_string(), + msg: None, + }, + query: cosmwasm_std::QueryRequest::Bank( + cosmwasm_std::BankQuery::AllBalances { address }, + ), + }, + vec![], + )?; + + Ok(Response::new().add_message(msg)) + } + _ => Ok(Response::new().set_data("mock_exec".as_bytes())), + }) + .with_query(|deps, _, _, msg| match msg { + MockQueryMsg::GetReceivedIbcCallbackStatus {} => { + to_json_binary(&ReceivedIbcCallbackStatus { + received: IBC_CALLBACK_RECEIVED.load(deps.storage)?, + }) + .map_err(Into::into) + } + MockQueryMsg::GetReceivedIbcModuleStatus {} => { + to_json_binary(&ReceivedIbcModuleStatus { + received: MODULE_IBC_RECEIVED.load(deps.storage)?, + }) + .map_err(Into::into) + } + MockQueryMsg::GetReceivedIbcQueryCallbackStatus {} => { + to_json_binary(&ReceivedIbcQueryCallbackStatus { + balance: IBC_CALLBACK_QUERY_RECEIVED.load(deps.storage)?, + }) + .map_err(Into::into) + } + }) + .with_sudo(|_, _, _, _| Ok(Response::new().set_data("mock_sudo".as_bytes()))) + .with_receive(|_, _, _, _, _| Ok(Response::new().set_data("mock_receive".as_bytes()))) + .with_ibc_callbacks(&[ + ("c_id", |deps, _, _, _, _| { + IBC_CALLBACK_RECEIVED.save(deps.storage, &true).unwrap(); + Ok(Response::new().add_attribute("mock_callback", "executed")) + }), + ("query_id", |deps, _, _, _, msg| match msg.result { + CallbackResult::Query { query: _, result } => { + let result = result.unwrap()[0].clone(); + let deser: AllBalanceResponse = from_json(result)?; + IBC_CALLBACK_QUERY_RECEIVED + .save(deps.storage, &deser.amount) + .unwrap(); + Ok(Response::new().add_attribute("mock_callback_query", "executed")) + } + _ => panic!("Expected query result"), + }), + ]) + .with_replies(&[(1u64, |_, _, _, msg| { + Ok(Response::new().set_data(msg.result.unwrap().data.unwrap())) + })]) + .with_migrate(|_, _, _, _| Ok(Response::new().set_data("mock_migrate".as_bytes()))) + .with_module_ibc(|deps, _, _, msg| { + let ModuleIbcMsg { source_module, .. } = msg; + // We save the module info status + MODULE_IBC_RECEIVED.save(deps.storage, &source_module)?; + Ok(Response::new().add_attribute("mock_module_ibc", "executed")) + }) +} + +pub mod origin_app { + use abstract_testing::addresses::{TEST_MODULE_ID, TEST_VERSION}; + + use super::{mock_app, MockAppContract}; + pub const MOCK_APP_ORIGIN: MockAppContract = mock_app(TEST_MODULE_ID, TEST_VERSION); + abstract_app::cw_orch_interface!(MOCK_APP_ORIGIN, MockAppContract, MockAppOriginI); +} + +pub mod remote_app { + use super::{mock_app, MockAppContract}; + + pub const TEST_MODULE_ID_REMOTE: &str = "tester:test-module-id-remote"; + pub const TEST_VERSION_REMOTE: &str = "0.45.7"; + pub const MOCK_APP_REMOTE: MockAppContract = + mock_app(TEST_MODULE_ID_REMOTE, TEST_VERSION_REMOTE); + abstract_app::cw_orch_interface!(MOCK_APP_REMOTE, MockAppContract, MockAppRemoteI); +} + +#[cfg(test)] +pub mod test { + + fn assert_remote_module_call_status( + app: &MockAppRemoteI, + source_module_expected: Option, + ) -> AnyResult<()> { + let source_module = app + .get_received_ibc_module_status() + .map(|s| s.received) + .ok(); + + assert_eq!(source_module, source_module_expected); + Ok(()) + } + + fn assert_callback_status(app: &MockAppOriginI, status: bool) -> AnyResult<()> { + let get_received_ibc_callback_status_res: ReceivedIbcCallbackStatus = + app.get_received_ibc_callback_status()?; + + assert_eq!( + ReceivedIbcCallbackStatus { received: status }, + get_received_ibc_callback_status_res + ); + Ok(()) + } + + fn assert_query_callback_status( + app: &MockAppOriginI, + balance: Vec, + ) -> AnyResult<()> { + let get_received_ibc_query_callback_status_res: ReceivedIbcQueryCallbackStatus = + app.get_received_ibc_query_callback_status()?; + + assert_eq!( + ReceivedIbcQueryCallbackStatus { balance }, + get_received_ibc_query_callback_status_res + ); + Ok(()) + } + use crate::{ + interchain_accounts::create_test_remote_account, + module_to_module_interactions::{ + origin_app::interface::MockAppOriginI, + remote_app::{interface::MockAppRemoteI, TEST_MODULE_ID_REMOTE, TEST_VERSION_REMOTE}, + MockExecMsgFns, MockInitMsg, MockQueryMsgFns, ReceivedIbcCallbackStatus, + ReceivedIbcQueryCallbackStatus, + }, + setup::{ + ibc_abstract_setup, ibc_connect_polytone_and_abstract, mock_test::logger_test_init, + }, + JUNO, STARGAZE, + }; + use abstract_app::objects::{chain_name::ChainName, module::ModuleInfo}; + use abstract_interface::{ + AppDeployer, DeployStrategy, Manager, ManagerQueryFns, VCExecFns, VCQueryFns, + }; + use abstract_std::manager::{self, ModuleInstallConfig}; + use abstract_testing::addresses::{TEST_MODULE_ID, TEST_NAMESPACE, TEST_VERSION}; + use anyhow::Result as AnyResult; + use base64::{engine::general_purpose, Engine}; + use cosmwasm_std::{coins, to_json_binary}; + use cw_orch::interchain::MockBech32InterchainEnv; + use cw_orch::prelude::*; + + #[test] + fn target_module_must_exist() -> AnyResult<()> { + logger_test_init(); + let mock_interchain = + MockBech32InterchainEnv::new(vec![(JUNO, "juno"), (STARGAZE, "stargaze")]); + + // We just verified all steps pass + let (abstr_origin, _abstr_remote) = ibc_abstract_setup(&mock_interchain, JUNO, STARGAZE)?; + ibc_connect_polytone_and_abstract(&mock_interchain, STARGAZE, JUNO)?; + + let remote_name = ChainName::from_chain_id(STARGAZE).to_string(); + + let (origin_account, _remote_account_id) = + create_test_remote_account(&abstr_origin, JUNO, STARGAZE, &mock_interchain, None)?; + + let app = MockAppOriginI::new( + TEST_MODULE_ID, + abstr_origin.version_control.get_chain().clone(), + ); + + abstr_origin.version_control.claim_namespace( + origin_account.manager.config()?.account_id, + TEST_NAMESPACE.to_owned(), + )?; + + app.deploy(TEST_VERSION.parse()?, DeployStrategy::Try)?; + + origin_account.install_app(&app, &MockInitMsg {}, None)?; + + // The user on origin chain wants to change the account description + let target_module_info = + ModuleInfo::from_id(TEST_MODULE_ID_REMOTE, TEST_VERSION_REMOTE.into())?; + let ibc_action_result = app.do_something_ibc(remote_name, target_module_info.clone())?; + + let ibc_result = mock_interchain.wait_ibc(JUNO, ibc_action_result)?; + + let expected_error_outcome = format!( + "Module {} does not have a stored module reference", + target_module_info + ); + match &ibc_result.packets[0].outcome { + cw_orch::interchain::types::IbcPacketOutcome::Timeout { .. } => { + panic!("Expected a failed ack not a timeout !") + } + cw_orch::interchain::types::IbcPacketOutcome::Success { ack, .. } => match ack { + cw_orch::interchain::types::IbcPacketAckDecode::Error(e) => { + assert!(e.contains(&expected_error_outcome)); + } + cw_orch::interchain::types::IbcPacketAckDecode::Success(_) => { + panic!("Expected a error ack") + } + cw_orch::interchain::types::IbcPacketAckDecode::NotParsed(original_ack) => { + let error_str = + String::from_utf8_lossy(&general_purpose::STANDARD.decode(original_ack)?) + .to_string(); + assert!(error_str.contains(&expected_error_outcome)); + } + }, + } + + Ok(()) + } + + #[test] + fn target_account_must_have_module_installed() -> AnyResult<()> { + logger_test_init(); + let mock_interchain = + MockBech32InterchainEnv::new(vec![(JUNO, "juno"), (STARGAZE, "stargaze")]); + + // We just verified all steps pass + let (abstr_origin, abstr_remote) = ibc_abstract_setup(&mock_interchain, JUNO, STARGAZE)?; + ibc_connect_polytone_and_abstract(&mock_interchain, STARGAZE, JUNO)?; + + let remote_name = ChainName::from_chain_id(STARGAZE).to_string(); + + let (origin_account, _remote_account_id) = + create_test_remote_account(&abstr_origin, JUNO, STARGAZE, &mock_interchain, None)?; + + let (remote_account, _remote_account_id) = + create_test_remote_account(&abstr_remote, STARGAZE, JUNO, &mock_interchain, None)?; + + // Install local app + let app = MockAppOriginI::new( + TEST_MODULE_ID, + abstr_origin.version_control.get_chain().clone(), + ); + + abstr_origin + .version_control + .claim_namespace(origin_account.id()?, TEST_NAMESPACE.to_owned())?; + + app.deploy(TEST_VERSION.parse()?, DeployStrategy::Try)?; + + origin_account.install_app(&app, &MockInitMsg {}, None)?; + + // Install remote app + let app_remote = MockAppRemoteI::new( + TEST_MODULE_ID_REMOTE, + abstr_remote.version_control.get_chain().clone(), + ); + + abstr_remote + .version_control + .claim_namespace(remote_account.id()?, TEST_NAMESPACE.to_owned())?; + + app_remote.deploy(TEST_VERSION_REMOTE.parse()?, DeployStrategy::Try)?; + + // The user on origin chain wants to change the account description + let target_module_info = + ModuleInfo::from_id(TEST_MODULE_ID_REMOTE, TEST_VERSION_REMOTE.into())?; + let ibc_action_result = app.do_something_ibc(remote_name, target_module_info.clone())?; + + let ibc_result = mock_interchain.wait_ibc(JUNO, ibc_action_result)?; + + let expected_error_outcome = + format!("App {} not installed on Account", target_module_info,); + match &ibc_result.packets[0].outcome { + cw_orch::interchain::types::IbcPacketOutcome::Timeout { .. } => { + panic!("Expected a failed ack not a timeout !") + } + cw_orch::interchain::types::IbcPacketOutcome::Success { ack, .. } => match ack { + cw_orch::interchain::types::IbcPacketAckDecode::Error(e) => { + assert!(e.contains(&expected_error_outcome)); + } + cw_orch::interchain::types::IbcPacketAckDecode::Success(_) => { + panic!("Expected a error ack") + } + cw_orch::interchain::types::IbcPacketAckDecode::NotParsed(original_ack) => { + let error_str = + String::from_utf8_lossy(&general_purpose::STANDARD.decode(original_ack)?) + .to_string(); + assert!(error_str.contains(&expected_error_outcome)); + } + }, + } + + Ok(()) + } + + #[test] + fn works() -> AnyResult<()> { + logger_test_init(); + let mock_interchain = + MockBech32InterchainEnv::new(vec![(JUNO, "juno"), (STARGAZE, "stargaze")]); + + // We just verified all steps pass + let (abstr_origin, abstr_remote) = ibc_abstract_setup(&mock_interchain, JUNO, STARGAZE)?; + ibc_connect_polytone_and_abstract(&mock_interchain, STARGAZE, JUNO)?; + + let remote_name = ChainName::from_chain_id(STARGAZE).to_string(); + + let (origin_account, remote_account_id) = + create_test_remote_account(&abstr_origin, JUNO, STARGAZE, &mock_interchain, None)?; + + let (remote_account, _) = + create_test_remote_account(&abstr_remote, STARGAZE, JUNO, &mock_interchain, None)?; + + // Install local app + let app = MockAppOriginI::new( + TEST_MODULE_ID, + abstr_origin.version_control.get_chain().clone(), + ); + + abstr_origin + .version_control + .claim_namespace(origin_account.id()?, TEST_NAMESPACE.to_owned())?; + + app.deploy(TEST_VERSION.parse()?, DeployStrategy::Try)?; + + origin_account.install_app(&app, &MockInitMsg {}, None)?; + + // Install remote app + let app_remote = MockAppRemoteI::new( + TEST_MODULE_ID_REMOTE, + abstr_remote.version_control.get_chain().clone(), + ); + + abstr_remote + .version_control + .claim_namespace(remote_account.id()?, TEST_NAMESPACE.to_owned())?; + + app_remote.deploy(TEST_VERSION_REMOTE.parse()?, DeployStrategy::Try)?; + + let remote_install_response = origin_account.manager.execute_on_remote( + &remote_name, + manager::ExecuteMsg::InstallModules { + modules: vec![ModuleInstallConfig::new( + ModuleInfo::from_id_latest(TEST_MODULE_ID_REMOTE)?, + Some(to_json_binary(&MockInitMsg {})?), + )], + }, + )?; + + mock_interchain.wait_ibc(JUNO, remote_install_response)?; + + // We get the object for handling the actual module on the remote account + let remote_manager = abstr_remote + .version_control + .account_base(remote_account_id)? + .account_base + .manager; + let manager = Manager::new( + "remote-account-manager", + abstr_remote.version_control.get_chain().clone(), + ); + manager.set_address(&remote_manager); + let module_address = manager.module_info(TEST_MODULE_ID_REMOTE)?.unwrap().address; + let remote_account_app = MockAppRemoteI::new( + "remote-account-app", + abstr_remote.version_control.get_chain().clone(), + ); + remote_account_app.set_address(&module_address); + + // The user on origin chain triggers a module-to-module interaction + let target_module_info = + ModuleInfo::from_id(TEST_MODULE_ID_REMOTE, TEST_VERSION_REMOTE.into())?; + let ibc_action_result = app.do_something_ibc(remote_name, target_module_info.clone())?; + + assert_remote_module_call_status(&remote_account_app, None)?; + assert_callback_status(&app, false)?; + + mock_interchain.wait_ibc(JUNO, ibc_action_result)?; + + assert_remote_module_call_status( + &remote_account_app, + Some(ModuleInfo::from_id(TEST_MODULE_ID, TEST_VERSION.into())?), + )?; + assert_callback_status(&app, true)?; + + Ok(()) + } + + pub const REMOTE_AMOUNT: u128 = 5674309; + pub const REMOTE_DENOM: &str = "remote_denom"; + #[test] + fn queries() -> AnyResult<()> { + logger_test_init(); + let mock_interchain = + MockBech32InterchainEnv::new(vec![(JUNO, "juno"), (STARGAZE, "stargaze")]); + + // We just verified all steps pass + let (abstr_origin, _abstr_remote) = ibc_abstract_setup(&mock_interchain, JUNO, STARGAZE)?; + ibc_connect_polytone_and_abstract(&mock_interchain, STARGAZE, JUNO)?; + + let remote_name = ChainName::from_chain_id(STARGAZE).to_string(); + let remote = mock_interchain.chain(STARGAZE)?; + let remote_address = + remote.addr_make_with_balance("remote-test", coins(REMOTE_AMOUNT, REMOTE_DENOM))?; + + let (origin_account, _remote_account_id) = + create_test_remote_account(&abstr_origin, JUNO, STARGAZE, &mock_interchain, None)?; + + // Install local app + let app = MockAppOriginI::new( + TEST_MODULE_ID, + abstr_origin.version_control.get_chain().clone(), + ); + + abstr_origin + .version_control + .claim_namespace(origin_account.id()?, TEST_NAMESPACE.to_owned())?; + + app.deploy(TEST_VERSION.parse()?, DeployStrategy::Try)?; + + origin_account.install_app(&app, &MockInitMsg {}, None)?; + + let query_response = app.query_something_ibc(remote_address.to_string(), remote_name)?; + + assert_query_callback_status(&app, coins(REMOTE_AMOUNT, REMOTE_DENOM)).unwrap_err(); + mock_interchain.wait_ibc(JUNO, query_response)?; + assert_query_callback_status(&app, coins(REMOTE_AMOUNT, REMOTE_DENOM))?; + + Ok(()) + } + + pub mod security { + use abstract_std::ibc_client::ExecuteMsgFns; + + use crate::module_to_module_interactions::IbcModuleToModuleMsg; + + use super::*; + + #[test] + fn calling_module_should_match() -> AnyResult<()> { + logger_test_init(); + let mock_interchain = + MockBech32InterchainEnv::new(vec![(JUNO, "juno"), (STARGAZE, "stargaze")]); + + // We just verified all steps pass + let (abstr_origin, abstr_remote) = + ibc_abstract_setup(&mock_interchain, JUNO, STARGAZE)?; + ibc_connect_polytone_and_abstract(&mock_interchain, STARGAZE, JUNO)?; + + let remote_name = ChainName::from_chain_id(STARGAZE).to_string(); + + let (origin_account, remote_account_id) = + create_test_remote_account(&abstr_origin, JUNO, STARGAZE, &mock_interchain, None)?; + + let (remote_account, _) = + create_test_remote_account(&abstr_remote, STARGAZE, JUNO, &mock_interchain, None)?; + + // Install local app + let app = MockAppOriginI::new( + TEST_MODULE_ID, + abstr_origin.version_control.get_chain().clone(), + ); + + abstr_origin + .version_control + .claim_namespace(origin_account.id()?, TEST_NAMESPACE.to_owned())?; + + app.deploy(TEST_VERSION.parse()?, DeployStrategy::Try)?; + + origin_account.install_app(&app, &MockInitMsg {}, None)?; + + // Install remote app + let app_remote = MockAppRemoteI::new( + TEST_MODULE_ID_REMOTE, + abstr_remote.version_control.get_chain().clone(), + ); + + abstr_remote + .version_control + .claim_namespace(remote_account.id()?, TEST_NAMESPACE.to_owned())?; + + app_remote.deploy(TEST_VERSION_REMOTE.parse()?, DeployStrategy::Try)?; + + let remote_install_response = origin_account.manager.execute_on_remote( + &remote_name, + manager::ExecuteMsg::InstallModules { + modules: vec![ModuleInstallConfig::new( + ModuleInfo::from_id_latest(TEST_MODULE_ID_REMOTE)?, + Some(to_json_binary(&MockInitMsg {})?), + )], + }, + )?; + + mock_interchain.wait_ibc(JUNO, remote_install_response)?; + + // We get the object for handling the actual module on the remote account + let remote_manager = abstr_remote + .version_control + .account_base(remote_account_id)? + .account_base + .manager; + let manager = Manager::new( + "remote-account-manager", + abstr_remote.version_control.get_chain().clone(), + ); + manager.set_address(&remote_manager); + let module_address = manager.module_info(TEST_MODULE_ID_REMOTE)?.unwrap().address; + let remote_account_app = MockAppRemoteI::new( + "remote-account-app", + abstr_remote.version_control.get_chain().clone(), + ); + remote_account_app.set_address(&module_address); + + // The user on origin chain triggers a module-to-module interaction + let target_module_info = + ModuleInfo::from_id(TEST_MODULE_ID_REMOTE, TEST_VERSION_REMOTE.into())?; + + // The user triggers manually a module-to-module interaction + abstr_origin + .ibc + .client + .module_ibc_action( + remote_name, + to_json_binary(&IbcModuleToModuleMsg { + ibc_msg: "module_to_module:msg".to_string(), + }) + .unwrap(), + target_module_info, + None, + ) + .unwrap_err(); + + Ok(()) + } + } +} diff --git a/interchain/interchain-tests/src/setup.rs b/interchain/interchain-tests/src/setup.rs index c3743b4434..4f75b4aca2 100644 --- a/interchain/interchain-tests/src/setup.rs +++ b/interchain/interchain-tests/src/setup.rs @@ -20,8 +20,27 @@ pub fn ibc_abstract_setup>( Abstract::deploy_on(remote_chain.clone(), remote_chain.sender().to_string())?; // Deploying polytone on both chains - let origin_polytone = Polytone::deploy_on(origin_chain.clone(), None)?; - let remote_polytone = Polytone::deploy_on(remote_chain.clone(), None)?; + Polytone::deploy_on(origin_chain.clone(), None)?; + Polytone::deploy_on(remote_chain.clone(), None)?; + + ibc_connect_polytone_and_abstract(interchain, origin_chain_id, remote_chain_id)?; + + Ok((abstr_origin, abstr_remote)) +} + +pub fn ibc_connect_polytone_and_abstract>( + interchain: &IBC, + origin_chain_id: &str, + remote_chain_id: &str, +) -> AnyResult<()> { + let origin_chain = interchain.chain(origin_chain_id).unwrap(); + let remote_chain = interchain.chain(remote_chain_id).unwrap(); + + let abstr_origin = Abstract::load_from(origin_chain.clone())?; + let abstr_remote = Abstract::load_from(remote_chain.clone())?; + + let origin_polytone = Polytone::load_from(origin_chain.clone())?; + let remote_polytone = Polytone::load_from(remote_chain.clone())?; // Creating a connection between 2 polytone deployments interchain.create_contract_channel( @@ -33,8 +52,7 @@ pub fn ibc_abstract_setup>( // Create the connection between client and host abstract_ibc_connection_with(&abstr_origin, interchain, &abstr_remote, &origin_polytone)?; - - Ok((abstr_origin, abstr_remote)) + Ok(()) } #[cfg(test)] diff --git a/interchain/tests/Cargo.toml b/interchain/tests/Cargo.toml new file mode 100644 index 0000000000..c43ab2961f --- /dev/null +++ b/interchain/tests/Cargo.toml @@ -0,0 +1,61 @@ +[package] +name = "abstract-interface-integration-tests" +version = { workspace = true } +edition = { workspace = true } + +[lib] + + +[dependencies] +cosmwasm-std = { workspace = true } +cosmwasm-schema = { workspace = true } +serde = { workspace = true } +semver = { workspace = true } +cw-controllers = { workspace = true } +thiserror = { workspace = true } +cw-asset = { workspace = true } +cw2 = { workspace = true } +cw20 = { workspace = true } +cw20-base = { workspace = true } + +cw-orch = { workspace = true, features = ["daemon"] } +cw-orch-proto = { workspace = true } +cw-orch-clone-testing = { workspace = true } +abstract-core = { workspace = true, features = ["interface"] } +abstract-sdk = { workspace = true } +abstract-app = { workspace = true, features = ["test-utils"] } +abstract-adapter = { workspace = true, features = ["test-utils"] } +abstract-testing = { workspace = true } + +abstract-interface = { workspace = true } +tokio = { workspace = true } +log = "0.4.14" +anyhow = { workspace = true } +serde_json = "1.0.79" +reqwest = { version = "0.11.9" } +dotenv = "0.15.0" +env_logger = "0.10.0" + +cosmos-sdk-proto = { version = "0.19.0", features = [ + "grpc-transport", + "cosmwasm", +] } +serde-cw-value = "0.7.0" +sha256 = "1.1.1" +clap.workspace = true +async-recursion = "1.0.4" +base64 = "0.21.0" +futures = "0.3.28" + +ibc-chain-registry = "0.25" +ibc-relayer-types = "0.25" + +cosmrs = "0.14.0" +prost = "0.11.9" +cw-orch-polytone = { workspace = true } +polytone = { workspace = true } +abstract-scripts = { path = "../scripts" } +abstract-integration-tests = { path = "../../framework/packages/abstract-integration-tests" } +lazy_static = "1.4.0" +abstract-client = { version = "0.21.0", path = "../../framework/packages/abstract-client" } +cw-storage-plus = "1.2.0" diff --git a/modules/contracts/adapters/cw-staking/src/handlers/execute.rs b/modules/contracts/adapters/cw-staking/src/handlers/execute.rs index f4aab54c36..6a6af4fff5 100644 --- a/modules/contracts/adapters/cw-staking/src/handlers/execute.rs +++ b/modules/contracts/adapters/cw-staking/src/handlers/execute.rs @@ -103,7 +103,6 @@ fn handle_ibc_request( provider: provider_name.clone(), action: action.clone(), })?), - receiver: info.sender.into_string(), }) }; let ibc_action_msg = ibc_client.host_action(host_chain.to_string(), host_action)?; diff --git a/modules/contracts/adapters/dex/src/handlers/execute.rs b/modules/contracts/adapters/dex/src/handlers/execute.rs index 466a1494a2..3eef06c06d 100644 --- a/modules/contracts/adapters/dex/src/handlers/execute.rs +++ b/modules/contracts/adapters/dex/src/handlers/execute.rs @@ -176,7 +176,6 @@ fn handle_ibc_request( dex: dex_name.clone(), action: action.clone(), })?), - receiver: info.sender.into_string(), }) }; let ibc_action_msg = ibc_client.host_action(host_chain.to_string(), host_action)?; diff --git a/modules/contracts/adapters/tendermint-staking/src/error.rs b/modules/contracts/adapters/tendermint-staking/src/error.rs index cf01845453..cfdc370b8e 100644 --- a/modules/contracts/adapters/tendermint-staking/src/error.rs +++ b/modules/contracts/adapters/tendermint-staking/src/error.rs @@ -1,4 +1,5 @@ use abstract_adapter::sdk::AbstractSdkError; +use abstract_adapter::std::AbstractError; use abstract_adapter::AdapterError; use cosmwasm_std::StdError; use thiserror::Error; @@ -11,6 +12,9 @@ pub enum TendermintStakeError { #[error("{0}")] AbstractSdk(#[from] AbstractSdkError), + #[error("{0}")] + Abstract(#[from] AbstractError), + #[error("{0}")] AdapterError(#[from] AdapterError), } diff --git a/modules/contracts/apps/etf/src/handlers/execute.rs b/modules/contracts/apps/etf/src/handlers/execute.rs index 6390a811ff..3fd60a530c 100644 --- a/modules/contracts/apps/etf/src/handlers/execute.rs +++ b/modules/contracts/apps/etf/src/handlers/execute.rs @@ -1,9 +1,11 @@ -use abstract_app::sdk::std::{ - objects::{deposit_info::DepositInfo, fee::Fee}, - proxy::AssetsInfoResponse, -}; use abstract_app::sdk::*; -use abstract_app::state::AppState; +use abstract_app::{ + sdk::std::{ + objects::{deposit_info::DepositInfo, fee::Fee}, + proxy::AssetsInfoResponse, + }, + std::app::AppState, +}; use cosmwasm_std::{ to_json_binary, wasm_execute, Addr, CosmosMsg, Decimal, DepsMut, Env, MessageInfo, QuerierWrapper, StdResult, Uint128, WasmMsg,