Skip to content

Commit fdd5d54

Browse files
committed
Allow for configuration of code IDs
This moves the handling of configured code IDs into the core library instead of the executable. Instead of simply hard-coding them, it uses the same configuration system as other values. This allows us to provide code IDs for custom networks or override the defaults. This also adds CLI options for providing code IDs when generating a new CW3 flex contract.
1 parent 4e5b054 commit fdd5d54

File tree

8 files changed

+148
-37
lines changed

8 files changed

+148
-37
lines changed

packages/cosmos-bin/src/config.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::str::FromStr;
22

33
use anyhow::Result;
4-
use cosmos::{AddressHrp, CosmosConfig, CosmosConfigError};
4+
use cosmos::{AddressHrp, ContractType, CosmosConfig, CosmosConfigError};
55

66
#[derive(clap::Parser)]
77
pub(crate) enum Opt {
@@ -46,6 +46,15 @@ pub(crate) enum Opt {
4646
/// gRPC URL
4747
url: String,
4848
},
49+
/// Add a recognized contract code ID
50+
AddContract {
51+
/// Network name
52+
name: String,
53+
/// Contract type
54+
contract_type: ContractType,
55+
/// Code ID
56+
code_id: u64,
57+
},
4958
}
5059

5160
// Strum would be more approriate, but serde gives better error messages
@@ -128,5 +137,16 @@ pub(crate) fn go(opt: crate::cli::Opt, inner: Opt) -> Result<()> {
128137
println!("Changes saved");
129138
Ok(())
130139
}
140+
Opt::AddContract {
141+
name,
142+
contract_type,
143+
code_id,
144+
} => {
145+
let mut config = load(&opt)?;
146+
config.add_contract(name, contract_type, code_id);
147+
config.save()?;
148+
println!("Changes saved");
149+
Ok(())
150+
}
131151
}
132152
}

packages/cosmos-bin/src/cw3.rs

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use anyhow::{Context, Result};
22
use cosmos::{
3-
proto::cosmos::bank::v1beta1::MsgSend, Address, ContractAdmin, Cosmos, HasAddress,
4-
HasAddressHrp, ParsedCoin, TxBuilder,
3+
proto::cosmos::bank::v1beta1::MsgSend, Address, ContractAdmin, ContractType, Cosmos,
4+
HasAddress, HasAddressHrp, ParsedCoin, TxBuilder,
55
};
66
use cosmwasm_std::{to_json_binary, CosmosMsg, Decimal, Empty, WasmMsg};
77
use cw3::{ProposalListResponse, ProposalResponse};
@@ -10,30 +10,6 @@ use cw_utils::Threshold;
1010

1111
use crate::{cli::TxOpt, my_duration::MyDuration};
1212

13-
#[derive(Clone, Copy, Debug)]
14-
enum ContractType {
15-
Cw3Flex,
16-
Cw4Group,
17-
}
18-
19-
fn get_code_id(chain_id: &str, contract_type: ContractType) -> Result<u64> {
20-
match (chain_id, contract_type) {
21-
("osmo-test-5", ContractType::Cw3Flex) => Ok(1519),
22-
("osmo-test-5", ContractType::Cw4Group) => Ok(1521),
23-
("osmosis-1", ContractType::Cw3Flex) => Ok(100),
24-
("osmosis-1", ContractType::Cw4Group) => Ok(101),
25-
("pacific-1", ContractType::Cw3Flex) => Ok(46),
26-
("pacific-1", ContractType::Cw4Group) => Ok(47),
27-
("injective-1", ContractType::Cw3Flex) => Ok(124),
28-
("injective-1", ContractType::Cw4Group) => Ok(125),
29-
("neutron-1", ContractType::Cw3Flex) => Ok(1189),
30-
("neutron-1", ContractType::Cw4Group) => Ok(1190),
31-
_ => Err(anyhow::anyhow!(
32-
"No code ID found for combo {chain_id}/{contract_type:?}"
33-
)),
34-
}
35-
}
36-
3713
#[derive(clap::Parser)]
3814
pub(crate) struct Opt {
3915
#[clap(subcommand)]
@@ -124,6 +100,12 @@ struct NewFlexOpt {
124100
/// Duration. Accepts s, m, h, and d suffixes for seconds, minutes, hours, and days
125101
#[clap(long)]
126102
duration: MyDuration,
103+
/// Code ID for the CW3 flex contract
104+
#[clap(long)]
105+
cw3_flex_code_id: Option<u64>,
106+
/// Code ID for the CW4 group contract
107+
#[clap(long)]
108+
cw4_group_code_id: Option<u64>,
127109
}
128110

129111
async fn new_flex(
@@ -135,12 +117,17 @@ async fn new_flex(
135117
cw4_label,
136118
weight_needed,
137119
duration,
120+
cw3_flex_code_id,
121+
cw4_group_code_id,
138122
}: NewFlexOpt,
139123
) -> Result<()> {
140-
let chain_id = cosmos.get_cosmos_builder().chain_id();
141124
let wallet = tx_opt.get_wallet(cosmos.get_address_hrp())?;
142-
let cw3 = cosmos.make_code_id(get_code_id(chain_id, ContractType::Cw3Flex)?);
143-
let cw4 = cosmos.make_code_id(get_code_id(chain_id, ContractType::Cw4Group)?);
125+
let cw3 = cosmos.make_code_id(
126+
cw3_flex_code_id.map_or_else(|| cosmos.get_code_id_for(ContractType::Cw3Flex), Ok)?,
127+
);
128+
let cw4 = cosmos.make_code_id(
129+
cw4_group_code_id.map_or_else(|| cosmos.get_code_id_for(ContractType::Cw4Group), Ok)?,
130+
);
144131

145132
anyhow::ensure!(!members.is_empty(), "Must provide at least one member");
146133

packages/cosmos/src/codeid.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,44 @@ impl HasAddressHrp for CodeId {
151151
self.client.get_address_hrp()
152152
}
153153
}
154+
155+
/// A type of contract which is understood by this library.
156+
///
157+
/// This is used to allow configuring generally reusable contracts like CW3 multisigs.
158+
#[derive(
159+
Clone,
160+
Copy,
161+
Debug,
162+
serde::Serialize,
163+
serde::Deserialize,
164+
PartialEq,
165+
Eq,
166+
PartialOrd,
167+
Ord,
168+
Hash,
169+
strum_macros::AsRefStr,
170+
strum_macros::Display,
171+
strum_macros::EnumString,
172+
)]
173+
#[serde(rename_all = "kebab-case")]
174+
#[strum(serialize_all = "kebab-case")]
175+
#[non_exhaustive]
176+
pub enum ContractType {
177+
/// CW3 flex multisig contract
178+
Cw3Flex,
179+
/// CW4 group contract
180+
Cw4Group,
181+
}
182+
183+
impl Cosmos {
184+
/// Get the configured code ID for the given contract type.
185+
///
186+
/// Returns an error if no such contract type is configured.
187+
pub fn get_code_id_for(&self, contract_type: ContractType) -> crate::Result<u64> {
188+
self.get_cosmos_builder()
189+
.code_ids
190+
.get(&contract_type)
191+
.copied()
192+
.ok_or(crate::Error::ContractTypeNotConfigured { contract_type })
193+
}
194+
}

packages/cosmos/src/config.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::{
2-
collections::HashMap,
2+
collections::{BTreeMap, HashMap},
33
path::{Path, PathBuf},
44
str::FromStr,
55
};
@@ -9,7 +9,7 @@ use figment::{
99
Figment,
1010
};
1111

12-
use crate::{AddressHrp, CosmosBuilder, CosmosNetwork};
12+
use crate::{AddressHrp, ContractType, CosmosBuilder, CosmosNetwork};
1313

1414
/// Configuration overrides for individual network
1515
#[derive(Debug)]
@@ -34,6 +34,8 @@ struct NetworkConfig {
3434
#[serde(default, skip_serializing_if = "Vec::is_empty")]
3535
grpc_fallbacks: Vec<String>,
3636
gas_multiplier: Option<f64>,
37+
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
38+
code_ids: BTreeMap<ContractType, u64>,
3739
}
3840

3941
impl NetworkConfig {
@@ -50,11 +52,17 @@ impl NetworkConfig {
5052
if let Some(hrp) = self.hrp {
5153
builder.set_hrp(hrp);
5254
}
55+
for (contract_type, code_id) in &self.code_ids {
56+
builder.set_code_id(*contract_type, *code_id);
57+
}
5358
}
5459
fn apply_extra_config(&self, builder: &mut CosmosBuilder) {
5560
for fallback in &self.grpc_fallbacks {
5661
builder.add_grpc_fallback_url(fallback);
5762
}
63+
for (contract_type, code_id) in &self.code_ids {
64+
builder.set_code_id(*contract_type, *code_id);
65+
}
5866
if let Some(gas_multiplier) = self.gas_multiplier {
5967
builder.set_gas_estimate_multiplier(gas_multiplier)
6068
}
@@ -203,6 +211,7 @@ impl CosmosConfig {
203211
hrp,
204212
grpc_fallbacks,
205213
gas_multiplier,
214+
code_ids,
206215
},
207216
) in networks
208217
{
@@ -226,6 +235,9 @@ impl CosmosConfig {
226235
if let Some(gas_multiplier) = gas_multiplier {
227236
println!("Gas multiplier: {gas_multiplier}");
228237
}
238+
for (contract_type, code_id) in code_ids {
239+
println!("Code ID for {contract_type}: {code_id}");
240+
}
229241
}
230242
}
231243

@@ -247,6 +259,7 @@ impl CosmosConfig {
247259
hrp: Some(hrp),
248260
grpc_fallbacks: vec![],
249261
gas_multiplier: None,
262+
code_ids: BTreeMap::new(),
250263
},
251264
);
252265
}
@@ -302,6 +315,16 @@ impl CosmosConfig {
302315
.grpc_fallbacks
303316
.push(url);
304317
}
318+
319+
/// Add a new contract type/code ID mapping.
320+
pub fn add_contract(&mut self, name: String, contract_type: ContractType, code_id: u64) {
321+
self.inner
322+
.network
323+
.entry(name)
324+
.or_default()
325+
.code_ids
326+
.insert(contract_type, code_id);
327+
}
305328
}
306329

307330
impl CosmosNetwork {

packages/cosmos/src/cosmos_builder.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use std::{sync::Arc, time::Duration};
1+
use std::{collections::BTreeMap, sync::Arc, time::Duration};
22

33
use crate::{
44
gas_multiplier::{GasMultiplier, GasMultiplierConfig},
55
gas_price::GasPriceMethod,
6-
AddressHrp, DynamicGasMultiplier,
6+
AddressHrp, ContractType, DynamicGasMultiplier,
77
};
88

99
#[derive(Clone, Copy, Debug)]
@@ -50,6 +50,7 @@ pub struct CosmosBuilder {
5050
keep_alive_while_idle: Option<bool>,
5151
simulate_with_gas_coin: bool,
5252
delay_before_fallback: Option<tokio::time::Duration>,
53+
pub(crate) code_ids: BTreeMap<ContractType, u64>,
5354
}
5455

5556
impl CosmosBuilder {
@@ -96,6 +97,7 @@ impl CosmosBuilder {
9697
keep_alive_while_idle: None,
9798
simulate_with_gas_coin,
9899
delay_before_fallback: None,
100+
code_ids: BTreeMap::new(),
99101
}
100102
}
101103

@@ -155,6 +157,11 @@ impl CosmosBuilder {
155157
self.hrp = hrp;
156158
}
157159

160+
/// Set a code ID for the given contract type.
161+
pub fn set_code_id(&mut self, contract_type: ContractType, code_id: u64) {
162+
self.code_ids.insert(contract_type, code_id);
163+
}
164+
158165
/// Revert to the default gas multiplier value (static value of 1.3).
159166
///
160167
/// This value comes from CosmJS and OsmoJS:

packages/cosmos/src/cosmos_network.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use std::{collections::HashMap, str::FromStr};
33
use serde::de::Visitor;
44
use strum_macros::{EnumString, IntoStaticStr};
55

6-
use crate::{error::BuilderError, gas_price::GasPriceMethod, Cosmos, CosmosBuilder, HasAddressHrp};
6+
use crate::{
7+
error::BuilderError, gas_price::GasPriceMethod, ContractType, Cosmos, CosmosBuilder,
8+
HasAddressHrp,
9+
};
710

811
/// A set of known networks.
912
///
@@ -210,6 +213,30 @@ impl CosmosNetwork {
210213
builder.set_gas_price(500000000.0, 900000000.0);
211214
}
212215
}
216+
217+
match self {
218+
CosmosNetwork::OsmosisMainnet => {
219+
builder.set_code_id(ContractType::Cw3Flex, 100);
220+
builder.set_code_id(ContractType::Cw4Group, 101);
221+
}
222+
CosmosNetwork::OsmosisTestnet => {
223+
builder.set_code_id(ContractType::Cw3Flex, 1519);
224+
builder.set_code_id(ContractType::Cw4Group, 1521);
225+
}
226+
CosmosNetwork::SeiMainnet => {
227+
builder.set_code_id(ContractType::Cw3Flex, 46);
228+
builder.set_code_id(ContractType::Cw4Group, 47);
229+
}
230+
CosmosNetwork::InjectiveMainnet => {
231+
builder.set_code_id(ContractType::Cw3Flex, 124);
232+
builder.set_code_id(ContractType::Cw4Group, 125);
233+
}
234+
CosmosNetwork::NeutronMainnet => {
235+
builder.set_code_id(ContractType::Cw3Flex, 1189);
236+
builder.set_code_id(ContractType::Cw4Group, 1190);
237+
}
238+
_ => (),
239+
}
213240
}
214241

215242
/// Load settings, like gas fees, from the internet.

packages/cosmos/src/error.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use chrono::{DateTime, Utc};
99
use cosmos_sdk_proto::cosmos::tx::v1beta1::OrderBy;
1010
use http::uri::InvalidUri;
1111

12-
use crate::{Address, AddressHrp, CosmosBuilder, TxBuilder};
12+
use crate::{Address, AddressHrp, ContractType, CosmosBuilder, TxBuilder};
1313

1414
/// Errors that can occur with token factory
1515
#[derive(thiserror::Error, Debug, Clone)]
@@ -344,6 +344,9 @@ pub enum Error {
344344
WasmGzipFailed {
345345
source: std::io::Error,
346346
},
347+
ContractTypeNotConfigured {
348+
contract_type: ContractType,
349+
},
347350
}
348351

349352
impl Display for Error {
@@ -411,6 +414,9 @@ impl Error {
411414
Error::WasmGzipFailed { source } => {
412415
write!(f, "Error during wasm Gzip compression: {source}")
413416
}
417+
Error::ContractTypeNotConfigured { contract_type } => {
418+
write!(f, "Contract type not configured: {contract_type}")
419+
}
414420
}
415421
}
416422

packages/cosmos/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//! Library for communicating with Cosmos blockchains over gRPC
33
pub use address::{Address, AddressHrp, HasAddress, HasAddressHrp, PublicKeyMethod, RawAddress};
44
pub use client::{BlockInfo, Cosmos, CosmosTxResponse, HasCosmos};
5-
pub use codeid::CodeId;
5+
pub use codeid::{CodeId, ContractType};
66
#[cfg(feature = "config")]
77
pub use config::{CosmosConfig, CosmosConfigError};
88
pub use contract::{Contract, ContractAdmin, HasContract};

0 commit comments

Comments
 (0)