use abstract_app::{gen_app_mock, mock, mock::MockError}; use abstract_integration_tests::{create_default_account, AResult}; use abstract_interface::*; use abstract_manager::error::ManagerError; use abstract_std::{ manager::ModuleInstallConfig, objects::{ gov_type::TopLevelOwnerResponse, module::{ModuleInfo, ModuleStatus, ModuleVersion}, AccountId, }, version_control::ModuleFilter, PROXY, }; use abstract_testing::prelude::*; use cosmwasm_std::{coin, CosmosMsg}; use cw_controllers::{AdminError, AdminResponse}; use cw_orch::prelude::*; use speculoos::prelude::*; const APP_ID: &str = "tester:app"; const APP_VERSION: &str = "1.0.0"; gen_app_mock!(MockApp, APP_ID, APP_VERSION, &[]); #[test] fn execute_on_proxy_through_manager() -> AResult { let chain = MockBech32::new("mock"); let sender = chain.sender_addr(); let deployment = Abstract::deploy_on(chain.clone(), sender.to_string())?; let account = create_default_account(&deployment.account_factory)?; // mint coins to proxy address chain.set_balance(&account.proxy.address()?, vec![Coin::new(100_000, TTOKEN)])?; // mint other coins to owner chain.set_balance(&sender, vec![Coin::new(100, "other_coin")])?; // burn coins from proxy let proxy_balance = chain .app .borrow() .wrap() .query_all_balances(account.proxy.address()?)?; assert_that!(proxy_balance).is_equal_to(vec![Coin::new(100_000, TTOKEN)]); let burn_amount: Vec = vec![Coin::new(10_000, TTOKEN)]; let forwarded_coin: Coin = coin(100, "other_coin"); account.manager.exec_on_module( cosmwasm_std::to_json_binary(&abstract_std::proxy::ExecuteMsg::ModuleAction { msgs: vec![CosmosMsg::Bank(cosmwasm_std::BankMsg::Burn { amount: burn_amount, })], })?, PROXY.to_string(), &[forwarded_coin.clone()], )?; let proxy_balance = chain .app .borrow() .wrap() .query_all_balances(account.proxy.address()?)?; assert_that!(proxy_balance) .is_equal_to(vec![forwarded_coin, Coin::new(100_000 - 10_000, TTOKEN)]); take_storage_snapshot!(chain, "execute_on_proxy_through_manager"); Ok(()) } #[test] fn account_install_app() -> AResult { let chain = MockBech32::new("mock"); let sender = chain.sender_addr(); Abstract::deploy_on(chain.clone(), sender.to_string())?; abstract_integration_tests::manager::account_install_app(chain.clone())?; take_storage_snapshot!(chain, "account_install_app"); Ok(()) } #[test] fn account_app_ownership() -> AResult { let chain = MockBech32::new("mock"); let sender = chain.sender_addr(); let deployment = Abstract::deploy_on(chain.clone(), sender.to_string())?; let account = create_default_account(&deployment.account_factory)?; deployment .version_control .claim_namespace(TEST_ACCOUNT_ID, "tester".to_owned())?; let app = MockApp::new_test(chain.clone()); app.deploy(APP_VERSION.parse().unwrap(), DeployStrategy::Try)?; account.install_app(&app, &MockInitMsg {}, None)?; let admin_res: AdminResponse = app.query(&mock::QueryMsg::Base(app::BaseQueryMsg::BaseAdmin {}))?; assert_eq!(admin_res.admin.unwrap(), account.manager.address()?); // Can call either by account owner or manager app.call_as(&sender).execute( &mock::ExecuteMsg::Module(MockExecMsg::DoSomethingAdmin {}), None, )?; app.call_as(&account.manager.address()?).execute( &mock::ExecuteMsg::Module(MockExecMsg::DoSomethingAdmin {}), None, )?; // Not admin or manager let err: MockError = app .call_as(&Addr::unchecked("who")) .execute( &mock::ExecuteMsg::Module(MockExecMsg::DoSomethingAdmin {}), None, ) .unwrap_err() .downcast() .unwrap(); assert_eq!(err, MockError::Admin(AdminError::NotAdmin {})); Ok(()) } #[test] fn subaccount_app_ownership() -> AResult { let chain = MockBech32::new("mock"); let sender = chain.sender_addr(); let deployment = Abstract::deploy_on(chain.clone(), sender.to_string())?; let account = create_default_account(&deployment.account_factory)?; deployment .version_control .claim_namespace(TEST_ACCOUNT_ID, "tester".to_owned())?; let app = MockApp::new_test(chain.clone()); app.deploy(APP_VERSION.parse().unwrap(), DeployStrategy::Try)?; account.manager.create_sub_account( vec![ModuleInstallConfig::new( ModuleInfo::from_id_latest(APP_ID).unwrap(), Some(to_json_binary(&MockInitMsg {}).unwrap()), )], "My subaccount".to_string(), None, None, None, None, None, &[], )?; let sub_account = AbstractAccount::new(&deployment, AccountId::local(2)); let module = sub_account.manager.module_info(APP_ID)?.unwrap(); app.set_address(&module.address); // Check query gives us right Top Level Owner let top_level_owner_res: TopLevelOwnerResponse = app.query(&mock::QueryMsg::Base(app::BaseQueryMsg::TopLevelOwner {}))?; assert_eq!(top_level_owner_res.address, sender); let admin_res: AdminResponse = app.query(&mock::QueryMsg::Base(app::BaseQueryMsg::BaseAdmin {}))?; assert_eq!(admin_res.admin.unwrap(), sub_account.manager.address()?); app.call_as(&sender).execute( &mock::ExecuteMsg::Module(MockExecMsg::DoSomethingAdmin {}), None, )?; Ok(()) } #[test] fn cant_reinstall_app_after_uninstall() -> AResult { let chain = MockBech32::new("mock"); let sender = chain.sender_addr(); let deployment = Abstract::deploy_on(chain.clone(), sender.to_string())?; let account = create_default_account(&deployment.account_factory)?; deployment .version_control .claim_namespace(TEST_ACCOUNT_ID, "tester".to_owned())?; let app = MockApp::new_test(chain.clone()); app.deploy(APP_VERSION.parse().unwrap(), DeployStrategy::Try)?; account.install_app(&app, &MockInitMsg {}, None)?; // Reinstall account.manager.uninstall_module(APP_ID.to_owned())?; let Err(AbstractInterfaceError::Orch(err)) = account.install_app(&app, &MockInitMsg {}, None) else { panic!("Expected error"); }; let manager_err: ManagerError = err.downcast().unwrap(); assert_eq!(manager_err, ManagerError::ProhibitedReinstall {}); Ok(()) } #[test] fn deploy_strategy_uploaded() -> AResult { let chain = MockBech32::new("mock"); let sender = chain.sender_addr(); let deployment = Abstract::deploy_on(chain.clone(), sender.to_string())?; let _account = create_default_account(&deployment.account_factory)?; deployment .version_control .claim_namespace(TEST_ACCOUNT_ID, "tester".to_owned())?; deployment .version_control .update_config(None, None, Some(false))?; let app = MockApp::new_test(chain.clone()); app.upload()?; // Deploy try app.deploy(APP_VERSION.parse().unwrap(), DeployStrategy::Try)?; let module_list = deployment.version_control.module_list( Some(ModuleFilter { status: Some(ModuleStatus::Pending), ..Default::default() }), None, None, )?; assert!(module_list.modules[0].module.info.name == "app"); // Clean module deployment.version_control.approve_or_reject_modules( vec![], vec![ModuleInfo::from_id( APP_ID, ModuleVersion::Version(APP_VERSION.to_owned()), )?], )?; // Deploy Error app.deploy(APP_VERSION.parse().unwrap(), DeployStrategy::Error)?; let module_list = deployment.version_control.module_list( Some(ModuleFilter { status: Some(ModuleStatus::Pending), ..Default::default() }), None, None, )?; assert!(module_list.modules[0].module.info.name == "app"); // Clean module deployment.version_control.approve_or_reject_modules( vec![], vec![ModuleInfo::from_id( APP_ID, ModuleVersion::Version(APP_VERSION.to_owned()), )?], )?; app.deploy(APP_VERSION.parse().unwrap(), DeployStrategy::Force)?; let module_list = deployment.version_control.module_list( Some(ModuleFilter { status: Some(ModuleStatus::Pending), ..Default::default() }), None, None, )?; assert!(module_list.modules[0].module.info.name == "app"); Ok(()) } #[test] fn deploy_strategy_deployed() -> AResult { let chain = MockBech32::new("mock"); let sender = chain.sender_addr(); let deployment = Abstract::deploy_on(chain.clone(), sender.to_string())?; let _account = create_default_account(&deployment.account_factory)?; deployment .version_control .claim_namespace(TEST_ACCOUNT_ID, "tester".to_owned())?; deployment .version_control .update_config(None, None, Some(false))?; let app = MockApp::new_test(chain.clone()); // deploy (not approved) app.deploy(APP_VERSION.parse().unwrap(), DeployStrategy::Try)?; // Deploy try let try_res = app.deploy(APP_VERSION.parse().unwrap(), DeployStrategy::Try); assert!(try_res.is_ok()); // Deploy Error let error_res = app.deploy(APP_VERSION.parse().unwrap(), DeployStrategy::Error); assert!(error_res.is_err()); // Deploy Force let force_res = app.deploy(APP_VERSION.parse().unwrap(), DeployStrategy::Force); // App not updatable assert!(force_res.is_err()); Ok(()) }