1use abstract_sdk::{
2 feature_objects::{AnsHost, RegistryContract},
3 std::{objects::ChannelEntry, ICS20},
4 Resolve,
5};
6use abstract_std::{
7 account::{self, ModuleInstallConfig},
8 ibc::PACKET_LIFETIME,
9 native_addrs,
10 objects::{module::ModuleInfo, module_reference::ModuleReference, AccountId, TruncatedChainId},
11 registry::Account,
12 ACCOUNT,
13};
14use cosmwasm_std::{
15 instantiate2_address, to_json_binary, wasm_execute, Coin, CosmosMsg, Deps, DepsMut, Empty, Env,
16 IbcMsg, Response, SubMsg, WasmMsg,
17};
18
19use crate::{
20 contract::{HostResponse, HostResult},
21 endpoints::reply::{INIT_BEFORE_ACTION_REPLY_ID, RESPONSE_REPLY_ID},
22 HostError,
23};
24
25#[allow(clippy::too_many_arguments)]
27pub fn receive_register(
28 deps: DepsMut,
29 env: Env,
30 account_id: AccountId,
31 name: Option<String>,
32 description: Option<String>,
33 link: Option<String>,
34 namespace: Option<String>,
35 install_modules: Vec<ModuleInstallConfig>,
36 with_reply: bool,
37 funds: Vec<Coin>,
38) -> HostResult {
39 let abstract_code_id =
40 native_addrs::abstract_code_id(&deps.querier, env.contract.address.clone())?;
41
42 let registry = RegistryContract::new(deps.as_ref(), abstract_code_id)?;
43 account_id.trace().verify_remote()?;
45 let salt = cosmwasm_std::to_json_binary(&account_id)?;
46
47 let account_module_info = ModuleInfo::from_id_latest(ACCOUNT)?;
48 let ModuleReference::Account(code_id) = registry
49 .query_module(account_module_info.clone(), &deps.querier)?
50 .reference
51 else {
52 return Err(HostError::RegistryError(
53 abstract_std::objects::registry::RegistryError::InvalidReference(account_module_info),
54 ));
55 };
56 let checksum = deps.querier.query_wasm_code_info(code_id)?.checksum;
57 let self_canon_addr = deps.api.addr_canonicalize(env.contract.address.as_str())?;
58
59 let create_account_msg = account::InstantiateMsg::<cosmwasm_std::Empty> {
60 code_id,
61 owner: abstract_std::objects::gov_type::GovernanceDetails::External {
62 governance_address: env.contract.address.into_string(),
63 governance_type: "abstract-ibc".into(), },
65 name,
66 description,
67 link,
68 account_id: Some(account_id.clone()),
70 install_modules,
71 namespace,
72 authenticator: None,
73 };
74
75 let account_canon_addr =
76 instantiate2_address(checksum.as_slice(), &self_canon_addr, salt.as_slice())?;
77 let account_addr = deps.api.addr_humanize(&account_canon_addr)?;
78
79 let account_creation_message = WasmMsg::Instantiate2 {
81 admin: Some(account_addr.to_string()),
82 code_id,
83 label: account_id.to_string(),
84 msg: to_json_binary(&create_account_msg)?,
85 funds,
86 salt,
87 };
88
89 let sub_msg = if with_reply {
91 SubMsg::reply_on_success(account_creation_message, INIT_BEFORE_ACTION_REPLY_ID)
92 } else {
93 SubMsg::new(account_creation_message)
94 };
95
96 Ok(Response::new()
97 .add_submessage(sub_msg)
98 .add_attribute("action", "register"))
99}
100
101pub fn receive_dispatch(
103 _deps: DepsMut,
104 account: Account,
105 account_msgs: Vec<account::ExecuteMsg>,
106) -> HostResult {
107 let msgs = account_msgs
109 .into_iter()
110 .map(|msg| wasm_execute(account.addr(), &msg, vec![]))
111 .collect::<Result<Vec<_>, _>>()?;
112
113 let response = Response::new()
114 .add_attribute("action", "receive_dispatch")
115 .add_submessages(
118 msgs.into_iter()
119 .map(|m| SubMsg::reply_on_success(m.clone(), RESPONSE_REPLY_ID)),
120 );
121
122 Ok(response)
123}
124
125pub fn receive_send_all_back(
127 deps: DepsMut,
128 env: Env,
129 account: Account,
130 client_account_address: String,
131 src_chain: TruncatedChainId,
132) -> HostResult {
133 let wasm_msg = send_all_back(
134 deps.as_ref(),
135 env,
136 account,
137 client_account_address,
138 src_chain,
139 )?;
140
141 Ok(HostResponse::action("receive_dispatch").add_message(wasm_msg))
142}
143
144pub fn send_all_back(
146 deps: Deps,
147 env: Env,
148 account: Account,
149 client_account_address: String,
150 src_chain: TruncatedChainId,
151) -> Result<CosmosMsg, HostError> {
152 let abstract_code_id =
154 native_addrs::abstract_code_id(&deps.querier, env.contract.address.clone())?;
155
156 let ans = AnsHost::new(deps, abstract_code_id)?;
157 let ics20_channel_entry = ChannelEntry {
158 connected_chain: src_chain,
159 protocol: ICS20.to_string(),
160 };
161 let ics20_channel_id = ics20_channel_entry.resolve(&deps.querier, &ans)?;
162 let coins = deps.querier.query_all_balances(account.addr())?;
164 let mut msgs: Vec<CosmosMsg> = vec![];
166 for coin in coins {
167 msgs.push(
168 IbcMsg::Transfer {
169 channel_id: ics20_channel_id.clone(),
170 to_address: client_account_address.to_string(),
171 amount: coin,
172 timeout: env.block.time.plus_seconds(PACKET_LIFETIME).into(),
173 memo: None,
174 }
175 .into(),
176 )
177 }
178 let account_msg = wasm_execute(
180 account.into_addr(),
181 &account::ExecuteMsg::<Empty>::Execute { msgs },
182 vec![],
183 )?;
184 Ok(account_msg.into())
185}
186
187pub fn get_account(deps: Deps, env: &Env, account_id: &AccountId) -> Result<Account, HostError> {
189 let abstract_code_id =
190 native_addrs::abstract_code_id(&deps.querier, env.contract.address.clone())?;
191
192 let registry = RegistryContract::new(deps, abstract_code_id)?;
193 let account = registry.account(account_id, &deps.querier)?;
194 Ok(account)
195}