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: Some(
62 abstract_std::objects::gov_type::GovernanceDetails::External {
63 governance_address: env.contract.address.into_string(),
64 governance_type: "abstract-ibc".into(), },
66 ),
67 name,
68 description,
69 link,
70 account_id: Some(account_id.clone()),
72 install_modules,
73 namespace,
74 authenticator: None,
75 };
76
77 let account_canon_addr =
78 instantiate2_address(checksum.as_slice(), &self_canon_addr, salt.as_slice())?;
79 let account_addr = deps.api.addr_humanize(&account_canon_addr)?;
80
81 let account_creation_message = WasmMsg::Instantiate2 {
83 admin: Some(account_addr.to_string()),
84 code_id,
85 label: account_id.to_string(),
86 msg: to_json_binary(&create_account_msg)?,
87 funds,
88 salt,
89 };
90
91 let sub_msg = if with_reply {
93 SubMsg::reply_on_success(account_creation_message, INIT_BEFORE_ACTION_REPLY_ID)
94 } else {
95 SubMsg::new(account_creation_message)
96 };
97
98 Ok(Response::new()
99 .add_submessage(sub_msg)
100 .add_attribute("action", "register"))
101}
102
103pub fn receive_dispatch(
105 _deps: DepsMut,
106 account: Account,
107 account_msgs: Vec<account::ExecuteMsg>,
108) -> HostResult {
109 let msgs = account_msgs
111 .into_iter()
112 .map(|msg| wasm_execute(account.addr(), &msg, vec![]))
113 .collect::<Result<Vec<_>, _>>()?;
114
115 let response = Response::new()
116 .add_attribute("action", "receive_dispatch")
117 .add_submessages(
120 msgs.into_iter()
121 .map(|m| SubMsg::reply_on_success(m.clone(), RESPONSE_REPLY_ID)),
122 );
123
124 Ok(response)
125}
126
127pub fn receive_send_all_back(
129 deps: DepsMut,
130 env: Env,
131 account: Account,
132 client_account_address: String,
133 src_chain: TruncatedChainId,
134) -> HostResult {
135 let wasm_msg = send_all_back(
136 deps.as_ref(),
137 env,
138 account,
139 client_account_address,
140 src_chain,
141 )?;
142
143 Ok(HostResponse::action("receive_dispatch").add_message(wasm_msg))
144}
145
146pub fn send_all_back(
148 deps: Deps,
149 env: Env,
150 account: Account,
151 client_account_address: String,
152 src_chain: TruncatedChainId,
153) -> Result<CosmosMsg, HostError> {
154 let abstract_code_id =
156 native_addrs::abstract_code_id(&deps.querier, env.contract.address.clone())?;
157
158 let ans = AnsHost::new(deps, abstract_code_id)?;
159 let ics20_channel_entry = ChannelEntry {
160 connected_chain: src_chain,
161 protocol: ICS20.to_string(),
162 };
163 let ics20_channel_id = ics20_channel_entry.resolve(&deps.querier, &ans)?;
164 let coins = deps.querier.query_all_balances(account.addr())?;
166 let mut msgs: Vec<CosmosMsg> = vec![];
168 for coin in coins {
169 msgs.push(
170 IbcMsg::Transfer {
171 channel_id: ics20_channel_id.clone(),
172 to_address: client_account_address.to_string(),
173 amount: coin,
174 timeout: env.block.time.plus_seconds(PACKET_LIFETIME).into(),
175 memo: None,
176 }
177 .into(),
178 )
179 }
180 let account_msg = wasm_execute(
182 account.into_addr(),
183 &account::ExecuteMsg::<Empty>::Execute { msgs },
184 vec![],
185 )?;
186 Ok(account_msg.into())
187}
188
189pub fn get_account(deps: Deps, env: &Env, account_id: &AccountId) -> Result<Account, HostError> {
191 let abstract_code_id =
192 native_addrs::abstract_code_id(&deps.querier, env.contract.address.clone())?;
193
194 let registry = RegistryContract::new(deps, abstract_code_id)?;
195 let account = registry.account(account_id, &deps.querier)?;
196 Ok(account)
197}