Skip to content

Commit 0a157fe

Browse files
authored
Merge pull request #59 from fpco/config-cw3-contracts
Allow for configuration of code IDs
2 parents 4e5b054 + fdd5d54 commit 0a157fe

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)