1use cosmwasm_std::{instantiate2_address, Binary, CanonicalAddr, Instantiate2AddressError};
2use cw_blob::interface::{CwBlob, DeterministicInstantiation};
3#[cfg(feature = "daemon")]
4use cw_orch::daemon::DeployedChains;
5
6use cw_orch::prelude::*;
7
8use crate::{
9 get_ibc_contracts, get_native_contracts, AbstractIbc, AbstractInterfaceError, AccountI,
10 AnsHost, ModuleFactory, Registry,
11};
12use abstract_std::{
13 native_addrs,
14 objects::{gov_type::GovernanceDetails, module::ModuleInfo},
15 registry::QueryMsgFns,
16 ACCOUNT, ANS_HOST, MODULE_FACTORY, REGISTRY,
17};
18
19const CW_BLOB: &str = "cw:blob";
20
21#[derive(Clone)]
22pub struct Abstract<Chain: CwEnv> {
23 pub ans_host: AnsHost<Chain>,
24 pub registry: Registry<Chain>,
25 pub module_factory: ModuleFactory<Chain>,
26 pub ibc: AbstractIbc<Chain>,
27 pub(crate) account: AccountI<Chain>,
28 pub(crate) blob: CwBlob<Chain>,
29}
30
31impl<Chain: CwEnv> Deploy<Chain> for Abstract<Chain> {
32 type Error = AbstractInterfaceError;
34 type DeployData = ();
35
36 fn store_on(chain: Chain) -> Result<Self, AbstractInterfaceError> {
37 let blob = CwBlob::new(CW_BLOB, chain.clone());
38
39 let ans_host = AnsHost::new(ANS_HOST, chain.clone());
40 let registry = Registry::new(REGISTRY, chain.clone());
41 let module_factory = ModuleFactory::new(MODULE_FACTORY, chain.clone());
42 let account = AccountI::new(ACCOUNT, chain.clone());
43
44 let ibc_infra = AbstractIbc::new(&chain);
45
46 blob.upload_if_needed()?;
47 ans_host.upload()?;
48 registry.upload()?;
49 module_factory.upload()?;
50 account.upload()?;
51 ibc_infra.upload()?;
52
53 let deployment = Abstract {
54 ans_host,
55 registry,
56 module_factory,
57 account,
58 ibc: ibc_infra,
59 blob,
60 };
61
62 Ok(deployment)
63 }
64
65 fn deploy_on(
68 chain: Chain,
69 _deploy_data: Self::DeployData,
70 ) -> Result<Self, AbstractInterfaceError> {
71 let sender_addr = chain.sender_addr();
72 let admin = sender_addr.to_string();
73 let deployment = Self::store_on(chain.clone())?;
75 let blob_code_id = deployment.blob.code_id()?;
76
77 let creator_account_id: cosmrs::AccountId = admin.as_str().parse().unwrap();
78 let canon_creator = CanonicalAddr::from(creator_account_id.to_bytes());
79
80 let expected_addr = |salt: &[u8]| -> Result<CanonicalAddr, Instantiate2AddressError> {
81 instantiate2_address(&cw_blob::CHECKSUM, &canon_creator, salt)
82 };
83
84 deployment.ans_host.deterministic_instantiate(
85 &abstract_std::ans_host::MigrateMsg::Instantiate(
86 abstract_std::ans_host::InstantiateMsg {
87 admin: admin.to_string(),
88 },
89 ),
90 blob_code_id,
91 expected_addr(native_addrs::ANS_HOST_SALT)?,
92 Binary::from(native_addrs::ANS_HOST_SALT),
93 )?;
94
95 deployment.registry.deterministic_instantiate(
96 &abstract_std::registry::MigrateMsg::Instantiate(
97 abstract_std::registry::InstantiateMsg {
98 admin: admin.to_string(),
99 #[cfg(feature = "testing")]
100 security_enabled: Some(false),
101 #[cfg(not(feature = "testing"))]
102 security_enabled: Some(true),
103 namespace_registration_fee: None,
104 },
105 ),
106 blob_code_id,
107 expected_addr(native_addrs::REGISTRY_SALT)?,
108 Binary::from(native_addrs::REGISTRY_SALT),
109 )?;
110 deployment.module_factory.deterministic_instantiate(
111 &abstract_std::module_factory::MigrateMsg::Instantiate(
112 abstract_std::module_factory::InstantiateMsg {
113 admin: admin.to_string(),
114 },
115 ),
116 blob_code_id,
117 expected_addr(native_addrs::MODULE_FACTORY_SALT)?,
118 Binary::from(native_addrs::MODULE_FACTORY_SALT),
119 )?;
120
121 deployment
123 .ibc
124 .instantiate(&Addr::unchecked(admin.clone()))?;
125
126 deployment.registry.register_base(&deployment.account)?;
127 deployment
128 .registry
129 .register_natives(deployment.contracts())?;
130 deployment.registry.approve_any_abstract_modules()?;
131
132 AccountI::create_default_account(
134 &deployment,
135 GovernanceDetails::Monarchy {
136 monarch: chain.sender_addr().to_string(),
137 },
138 )?;
139
140 Ok(deployment)
141 }
142
143 fn get_contracts_mut(&mut self) -> Vec<Box<&mut dyn ContractInstance<Chain>>> {
144 vec![
145 Box::new(&mut self.ans_host),
146 Box::new(&mut self.registry),
147 Box::new(&mut self.module_factory),
148 Box::new(&mut self.account),
149 Box::new(&mut self.ibc.client),
150 Box::new(&mut self.ibc.host),
151 ]
152 }
153
154 fn load_from(chain: Chain) -> Result<Self, Self::Error> {
155 #[allow(unused_mut)]
156 let mut abstr = Self::new(chain.clone());
157 #[cfg(feature = "daemon")]
158 {
159 let state = crate::AbstractDaemonState::default().state();
161
162 abstr.set_contracts_state(Some(state));
163 }
164 if let Err(CwOrchError::AddrNotInStore(_)) = abstr.registry.address() {
166 return Err(AbstractInterfaceError::NotDeployed(
167 chain
168 .block_info()
169 .map(|b| b.chain_id)
170 .unwrap_or("chain id not available".to_string()),
171 ));
172 } else if abstr.registry.item_query(cw2::CONTRACT).is_err() {
173 return Err(AbstractInterfaceError::NotDeployed(
174 chain
175 .block_info()
176 .map(|b| b.chain_id)
177 .unwrap_or("chain id not available".to_string()),
178 ));
179 }
180 Ok(abstr)
181 }
182}
183
184#[cfg(feature = "daemon")]
185impl<Chain: CwEnv> DeployedChains<Chain> for Abstract<Chain> {
186 fn deployed_state_file_path() -> Option<String> {
187 let crate_path = env!("CARGO_MANIFEST_DIR");
188
189 Some(
190 std::path::PathBuf::from(crate_path)
191 .join("state.json")
192 .display()
193 .to_string(),
194 )
195 }
196}
197
198impl<Chain: CwEnv> Abstract<Chain> {
199 pub fn new(chain: Chain) -> Self {
200 let (ans_host, registry, module_factory) = get_native_contracts(chain.clone());
201 let (ibc_client, ibc_host) = get_ibc_contracts(chain.clone());
202 let account = AccountI::new(ACCOUNT, chain.clone());
203 Self {
204 account,
205 ans_host,
206 registry,
207 module_factory,
208 ibc: AbstractIbc {
209 client: ibc_client,
210 host: ibc_host,
211 },
212 blob: CwBlob::new(CW_BLOB, chain),
213 }
214 }
215
216 pub fn contracts(&self) -> Vec<(&cw_orch::contract::Contract<Chain>, String)> {
217 vec![
218 (
219 self.ans_host.as_instance(),
220 ans_host::contract::CONTRACT_VERSION.to_string(),
221 ),
222 (
223 self.registry.as_instance(),
224 registry::contract::CONTRACT_VERSION.to_string(),
225 ),
226 (
227 self.module_factory.as_instance(),
228 module_factory::contract::CONTRACT_VERSION.to_string(),
229 ),
230 (
231 self.ibc.client.as_instance(),
232 ibc_client::contract::CONTRACT_VERSION.to_string(),
233 ),
234 (
235 self.ibc.host.as_instance(),
236 ibc_host::contract::CONTRACT_VERSION.to_string(),
237 ),
238 ]
239 }
240
241 pub fn call_as(&self, sender: &<Chain as TxHandler>::Sender) -> Self {
242 Self {
243 ans_host: self.ans_host.clone().call_as(sender),
244 registry: self.registry.clone().call_as(sender),
245 module_factory: self.module_factory.clone().call_as(sender),
246 ibc: self.ibc.call_as(sender),
247 account: self.account.call_as(sender),
248 blob: self.blob.clone(),
249 }
250 }
251
252 pub fn account_code_id(&self) -> Result<u64, AbstractInterfaceError> {
253 let account_module_info = &self
254 .registry
255 .modules(vec![ModuleInfo::from_id_latest(ACCOUNT)?])?
256 .modules[0];
257
258 match account_module_info.module.reference {
259 abstract_std::objects::module_reference::ModuleReference::Account(code_id) => Ok(code_id),
260 _ => panic!("Your abstract instance has an account module that is not registered as an account. This is bad"),
261 }
262 }
263}