abstract_interface/
deployers.rs1use abstract_std::{
2 account::ModuleInstallConfig,
3 objects::{
4 dependency::StaticDependency,
5 module::{ModuleInfo, ModuleVersion},
6 AccountId,
7 },
8};
9use cosmwasm_std::to_json_binary;
10use cw_orch::{
11 environment::Environment,
12 prelude::{CwOrchError::StdErr, *},
13};
14use semver::Version;
15use serde::Serialize;
16
17use crate::Abstract;
18
19pub trait RegisteredModule {
21 type InitMsg: Serialize;
23 fn module_id<'a>() -> &'a str;
25 fn module_version<'a>() -> &'a str;
27 fn installed_module_contract_id(account_id: &AccountId) -> String {
29 format!("{}-{}", Self::module_id(), account_id)
30 }
31 fn dependencies<'a>() -> &'a [StaticDependency];
33}
34
35pub trait DependencyCreation {
37 type DependenciesConfig;
39
40 #[allow(unused_variables)]
42 fn dependency_install_configs(
43 configuration: Self::DependenciesConfig,
44 ) -> Result<Vec<ModuleInstallConfig>, crate::AbstractInterfaceError> {
45 Ok(vec![])
46 }
47}
48
49pub trait InstallConfig: RegisteredModule {
52 fn module_info() -> Result<ModuleInfo, crate::AbstractInterfaceError> {
54 ModuleInfo::from_id(Self::module_id(), Self::module_version().into()).map_err(Into::into)
55 }
56
57 fn install_config(
59 init_msg: &Self::InitMsg,
60 ) -> Result<ModuleInstallConfig, crate::AbstractInterfaceError> {
61 Ok(ModuleInstallConfig::new(
62 Self::module_info()?,
63 Some(to_json_binary(init_msg)?),
64 ))
65 }
66}
67
68impl<T> InstallConfig for T where T: RegisteredModule {}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub enum DeployStrategy {
74 Error,
76 Try,
78 Force,
80}
81
82pub trait AdapterDeployer<Chain: CwEnv, CustomInitMsg: Serialize>: ContractInstance<Chain>
84 + CwOrchInstantiate<Chain, InstantiateMsg = abstract_std::adapter::InstantiateMsg<CustomInitMsg>>
85 + Uploadable
86 + Sized
87 + RegisteredModule
88{
89 fn deploy(
92 &self,
93 version: Version,
94 custom_init_msg: CustomInitMsg,
95 strategy: DeployStrategy,
96 ) -> Result<(), crate::AbstractInterfaceError> {
97 let abstr = Abstract::load_from(self.environment().to_owned())?;
99
100 abstr
101 .registry
102 .assert_dependencies_deployed(Self::dependencies())?;
103
104 let vc_has_module = || {
106 abstr
107 .registry
108 .registered_or_pending_module(
109 ModuleInfo::from_id(&self.id(), ModuleVersion::from(version.to_string()))
110 .unwrap(),
111 )
112 .and_then(|module| module.reference.unwrap_adapter().map_err(Into::into))
113 };
114
115 match strategy {
116 DeployStrategy::Error => {
117 if vc_has_module().is_ok() {
118 return Err(StdErr(format!(
119 "Adapter {} already exists with version {}",
120 self.id(),
121 version
122 ))
123 .into());
124 }
125 }
126 DeployStrategy::Try => {
127 if vc_has_module().is_ok() {
128 return Ok(());
129 }
130 }
131 DeployStrategy::Force => {}
132 }
133
134 self.upload_if_needed()?;
135 let init_msg = abstract_std::adapter::InstantiateMsg {
136 module: custom_init_msg,
137 base: abstract_std::adapter::BaseInstantiateMsg {
138 registry_address: abstr.registry.addr_str()?,
139 },
140 };
141 self.instantiate(&init_msg, None, &[])?;
142
143 abstr
144 .registry
145 .register_adapters(vec![(self.as_instance(), version.to_string())])?;
146
147 Ok(())
148 }
149}
150
151pub trait AppDeployer<Chain: CwEnv>:
153 Sized + Uploadable + ContractInstance<Chain> + RegisteredModule
154{
155 fn deploy(
158 &self,
159 version: Version,
160 strategy: DeployStrategy,
161 ) -> Result<(), crate::AbstractInterfaceError> {
162 let abstr = Abstract::<Chain>::load_from(self.environment().to_owned())?;
164
165 abstr
166 .registry
167 .assert_dependencies_deployed(Self::dependencies())?;
168
169 let vc_has_module = || {
171 abstr
172 .registry
173 .registered_or_pending_module(
174 ModuleInfo::from_id(&self.id(), ModuleVersion::from(version.to_string()))
175 .unwrap(),
176 )
177 .and_then(|module| module.reference.unwrap_app().map_err(Into::into))
178 };
179
180 match strategy {
181 DeployStrategy::Error => {
182 if vc_has_module().is_ok() {
183 return Err(StdErr(format!(
184 "App {} already exists with version {}",
185 self.id(),
186 version
187 ))
188 .into());
189 }
190 }
191 DeployStrategy::Try => {
192 if vc_has_module().is_ok() {
193 return Ok(());
194 }
195 }
196 DeployStrategy::Force => {}
197 }
198
199 self.upload_if_needed()?;
200 abstr
201 .registry
202 .register_apps(vec![(self.as_instance(), version.to_string())])?;
203
204 Ok(())
205 }
206}
207
208pub trait StandaloneDeployer<Chain: CwEnv>:
210 Sized + Uploadable + ContractInstance<Chain> + RegisteredModule
211{
212 fn deploy(
215 &self,
216 version: Version,
217 strategy: DeployStrategy,
218 ) -> Result<(), crate::AbstractInterfaceError> {
219 let abstr = Abstract::<Chain>::load_from(self.environment().to_owned())?;
221
222 abstr
223 .registry
224 .assert_dependencies_deployed(Self::dependencies())?;
225
226 let vc_has_module = || {
228 abstr
229 .registry
230 .registered_or_pending_module(
231 ModuleInfo::from_id(&self.id(), ModuleVersion::from(version.to_string()))
232 .unwrap(),
233 )
234 .and_then(|module| module.reference.unwrap_standalone().map_err(Into::into))
235 };
236
237 match strategy {
238 DeployStrategy::Error => {
239 if vc_has_module().is_ok() {
240 return Err(StdErr(format!(
241 "Standalone {} already exists with version {}",
242 self.id(),
243 version
244 ))
245 .into());
246 }
247 }
248 DeployStrategy::Try => {
249 if vc_has_module().is_ok() {
250 return Ok(());
251 }
252 }
253 DeployStrategy::Force => {}
254 }
255
256 self.upload_if_needed()?;
257 abstr
258 .registry
259 .register_standalones(vec![(self.as_instance(), version.to_string())])?;
260
261 Ok(())
262 }
263}
264
265pub trait ServiceDeployer<Chain: CwEnv>:
267 Sized + Uploadable + ContractInstance<Chain> + CwOrchInstantiate<Chain>
268{
269 fn deploy(
272 &self,
273 version: Version,
274 custom_init_msg: &<Self as InstantiableContract>::InstantiateMsg,
275 strategy: DeployStrategy,
276 ) -> Result<(), crate::AbstractInterfaceError> {
277 let abstr = Abstract::<Chain>::load_from(self.environment().to_owned())?;
279
280 let vc_has_module = || {
282 abstr
283 .registry
284 .registered_or_pending_module(
285 ModuleInfo::from_id(&self.id(), ModuleVersion::from(version.to_string()))
286 .unwrap(),
287 )
288 .and_then(|module| module.reference.unwrap_standalone().map_err(Into::into))
289 };
290
291 match strategy {
292 DeployStrategy::Error => {
293 if vc_has_module().is_ok() {
294 return Err(StdErr(format!(
295 "Service {} already exists with version {}",
296 self.id(),
297 version
298 ))
299 .into());
300 }
301 }
302 DeployStrategy::Try => {
303 if vc_has_module().is_ok() {
304 return Ok(());
305 }
306 }
307 DeployStrategy::Force => {}
308 }
309
310 self.upload_if_needed()?;
311 self.instantiate(custom_init_msg, None, &[])?;
312 abstr
313 .registry
314 .register_services(vec![(self.as_instance(), version.to_string())])?;
315
316 Ok(())
317 }
318}