Skip to content

Commit 508327e

Browse files
committed
build(make): add portable abstract deployment info task
1 parent cdffeee commit 508327e

5 files changed

Lines changed: 233 additions & 0 deletions

File tree

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Makefile.toml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,31 @@ echo "🚀 Deploying Abstract infrastructure to networks: ${networks}"
501501
cargo run --bin deploy_abstract --package axone-scripts -- --network-ids ${networks}
502502
'''
503503

504+
[tasks.deploy-abstract-info]
505+
category = "Deployment"
506+
description = "List Abstract deployment info for specified networks. Usage: cargo make deploy-abstract-info <network-ids...>"
507+
script = '''
508+
if [ -z "$1" ]
509+
then
510+
echo "❌ Please provide at least one network id (e.g., local, testnet, mainnet)"
511+
exit 1
512+
fi
513+
514+
networks="$@"
515+
516+
for network in "$@"
517+
do
518+
case "$network" in
519+
local|axone-localnet)
520+
cargo make chain-start
521+
;;
522+
esac
523+
done
524+
525+
echo "🔎 Listing Abstract deployment info for networks: ${networks}"
526+
cargo run --bin deploy_abstract_info --package axone-scripts -- --network-ids ${networks}
527+
'''
528+
504529
[tasks.deploy-install]
505530
category = "Deployment"
506531
description = "Install a module on an Abstract Account. Usage: cargo make deploy-install <contract-name> <network-ids...>"

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ contract-query - Query a specific contract. The contract must be already deploye
200200
Deployment
201201
----------
202202
deploy-abstract - Deploy Abstract infrastructure to specified networks. Usage: cargo make deploy-abstract <network-ids...>
203+
deploy-abstract-info - List Abstract deployment info for specified networks. Usage: cargo make deploy-abstract-info <network-ids...>
203204
deploy-contract - Publish a contract to Abstract on specified networks. Usage: cargo make deploy-contract <contract-name> <network-ids...>
204205
deploy-install - Install a module on an Abstract Account. Usage: cargo make deploy-install <contract-name> <network-ids...>
205206
deploy-script - Run a contract deployment script. Usage: cargo make deploy-script <script> <package> <network-ids...>
@@ -328,6 +329,24 @@ This command deploys the entire Abstract infrastructure to the specified network
328329

329330
**Supported networks:** `local`, `testnet`, `mainnet`, `axone-localnet`, `axone-dendrite-2`, `axone-1`.
330331

332+
#### 1b️⃣ Inspect Abstract Infrastructure
333+
334+
To display the main addresses and identifiers of an existing Abstract deployment on a target network:
335+
336+
```sh
337+
cargo make deploy-abstract-info local
338+
```
339+
340+
Example output:
341+
342+
```text
343+
NETWORK: local
344+
CHAIN_ID: axone-localnet
345+
ACCOUNT_CODE_ID: 5
346+
MODULE_FACTORY_ADDR: axone1...
347+
REGISTRY_ADDR: axone1...
348+
```
349+
331350
#### 2️⃣ Publish Your Contracts
332351

333352
Once the infrastructure is deployed, publish your smart contracts to Abstract's on-chain registry:

scripts/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,18 @@ version = "0.1.0"
88
name = "deploy_abstract"
99
path = "src/bin/deploy_abstract.rs"
1010

11+
[[bin]]
12+
name = "deploy_abstract_info"
13+
path = "src/bin/deploy_abstract_info.rs"
14+
1115
[dependencies]
1216
abstract-interface.workspace = true
17+
abstract-std.workspace = true
1318
anyhow = { workspace = true }
1419
axone-networks = { path = "../packages/axone-networks" }
1520
clap = { workspace = true, features = ["derive"] }
21+
cosmrs = "0.19.0"
22+
cosmwasm-std.workspace = true
1623
cw-orch = { workspace = true, features = ["daemon"] }
1724
dotenv = { workspace = true }
1825
env_logger = { workspace = true }
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
//! List Abstract deployment information for one or more networks.
2+
3+
use abstract_std::{
4+
native_addrs::{BLOB_CHECKSUM, MODULE_FACTORY_SALT, REGISTRY_SALT},
5+
objects::{module::ModuleInfo, module_reference::ModuleReference},
6+
registry::{ModulesResponse, QueryMsg},
7+
ACCOUNT, MODULE_FACTORY, REGISTRY,
8+
};
9+
use axone_networks::parse_network as parse_axone_network;
10+
use clap::Parser;
11+
use cosmrs::{
12+
proto::{
13+
cosmos::base::query::v1beta1::PageRequest,
14+
cosmwasm::wasm::v1::{query_client::QueryClient, QueryCodesRequest},
15+
},
16+
AccountId,
17+
};
18+
use cosmwasm_std::{instantiate2_address, Addr, CanonicalAddr};
19+
use cw_orch::{
20+
anyhow,
21+
daemon::{networks::ChainInfo, senders::QueryOnlyDaemon},
22+
prelude::*,
23+
tokio::runtime::Runtime,
24+
};
25+
use std::{collections::BTreeSet, str::FromStr};
26+
27+
#[derive(Debug)]
28+
struct AbstractDeploymentInfo {
29+
account_code_id: u64,
30+
module_factory_addr: Addr,
31+
registry_addr: Addr,
32+
}
33+
34+
fn addr_from_instantiate2(creator_addr: &str, salt: &[u8]) -> anyhow::Result<Addr> {
35+
let creator_account_id =
36+
AccountId::from_str(creator_addr).map_err(|err| anyhow::Error::msg(err.to_string()))?;
37+
let creator_canon = CanonicalAddr::from(creator_account_id.to_bytes());
38+
let contract_canon = instantiate2_address(&BLOB_CHECKSUM, &creator_canon, salt)?;
39+
let contract_addr = AccountId::new(creator_account_id.prefix(), contract_canon.as_slice())
40+
.map_err(|err| anyhow::Error::msg(err.to_string()))?;
41+
Ok(Addr::unchecked(contract_addr.to_string()))
42+
}
43+
44+
fn discover_blob_creators(chain: &QueryOnlyDaemon) -> anyhow::Result<BTreeSet<String>> {
45+
let mut client = QueryClient::new(chain.channel());
46+
let mut pagination = Some(PageRequest {
47+
key: vec![],
48+
offset: 0,
49+
limit: 200,
50+
count_total: false,
51+
reverse: false,
52+
});
53+
let mut creators = BTreeSet::new();
54+
55+
loop {
56+
let response = chain.rt_handle.block_on(client.codes(QueryCodesRequest {
57+
pagination: pagination.clone(),
58+
}))?;
59+
let response = response.into_inner();
60+
61+
for code_info in response.code_infos {
62+
if code_info.data_hash.as_slice() == BLOB_CHECKSUM {
63+
creators.insert(code_info.creator);
64+
}
65+
}
66+
67+
let next_key = response
68+
.pagination
69+
.map(|page| page.next_key)
70+
.unwrap_or_default();
71+
if next_key.is_empty() {
72+
break;
73+
}
74+
75+
pagination = Some(PageRequest {
76+
key: next_key,
77+
offset: 0,
78+
limit: 200,
79+
count_total: false,
80+
reverse: false,
81+
});
82+
}
83+
84+
Ok(creators)
85+
}
86+
87+
fn discover_abstract_deployment(chain: &QueryOnlyDaemon) -> anyhow::Result<AbstractDeploymentInfo> {
88+
let wasm = chain.wasm_querier();
89+
90+
for creator_addr in discover_blob_creators(chain)? {
91+
let registry_addr = addr_from_instantiate2(&creator_addr, REGISTRY_SALT)?;
92+
let module_factory_addr = addr_from_instantiate2(&creator_addr, MODULE_FACTORY_SALT)?;
93+
94+
let account_module = wasm.smart_query::<_, ModulesResponse>(
95+
&registry_addr,
96+
&QueryMsg::Modules {
97+
infos: vec![ModuleInfo::from_id_latest(ACCOUNT)?],
98+
},
99+
);
100+
101+
let Ok(account_module) = account_module else {
102+
continue;
103+
};
104+
105+
let Some(module_response) = account_module.modules.first() else {
106+
continue;
107+
};
108+
109+
let account_code_id = match module_response.module.reference {
110+
ModuleReference::Account(code_id) => code_id,
111+
ref reference => {
112+
anyhow::bail!("unexpected account module reference: {reference:?}");
113+
}
114+
};
115+
116+
return Ok(AbstractDeploymentInfo {
117+
account_code_id,
118+
module_factory_addr,
119+
registry_addr,
120+
});
121+
}
122+
123+
anyhow::bail!(
124+
"no Abstract deployment found on-chain for {} / {}",
125+
REGISTRY,
126+
MODULE_FACTORY
127+
);
128+
}
129+
130+
fn print_abstract_info(networks: Vec<(String, ChainInfo)>) -> anyhow::Result<()> {
131+
for (index, (network_id, network)) in networks.into_iter().enumerate() {
132+
let rt = Runtime::new()?;
133+
let chain = DaemonBuilder::new(network.clone())
134+
.handle(rt.handle())
135+
.is_test(true)
136+
.build_sender(())?;
137+
let deployment = discover_abstract_deployment(&chain)?;
138+
139+
if index > 0 {
140+
println!();
141+
}
142+
143+
println!("NETWORK: {network_id}");
144+
println!("CHAIN_ID: {}", network.chain_id);
145+
println!("ACCOUNT_CODE_ID: {}", deployment.account_code_id);
146+
println!("MODULE_FACTORY_ADDR: {}", deployment.module_factory_addr);
147+
println!("REGISTRY_ADDR: {}", deployment.registry_addr);
148+
}
149+
150+
Ok(())
151+
}
152+
153+
#[derive(Debug, Parser)]
154+
#[command(author, version, about, long_about = None)]
155+
struct Arguments {
156+
/// Network IDs to inspect (e.g., local, testnet, mainnet)
157+
#[arg(short, long, value_delimiter = ' ', num_args = 1..)]
158+
network_ids: Vec<String>,
159+
}
160+
161+
fn main() -> anyhow::Result<()> {
162+
dotenv::dotenv().ok();
163+
let _ = env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn"))
164+
.try_init();
165+
166+
let args = Arguments::parse();
167+
let networks = args
168+
.network_ids
169+
.iter()
170+
.map(|network_id| {
171+
parse_axone_network(network_id)
172+
.or_else(|_| networks::parse_network(network_id))
173+
.map(|network| (network_id.clone(), network))
174+
.map_err(anyhow::Error::msg)
175+
})
176+
.collect::<Result<Vec<_>, _>>()?;
177+
178+
print_abstract_info(networks)
179+
}

0 commit comments

Comments
 (0)