diff --git a/CHANGELOG.md b/CHANGELOG.md index 267d88259..c3c171e76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,9 @@ ## Unpublished - - Add methods to set the private key and mnemonic of an existing sender - - Deprecate `authz_granter` and `fee_granter` on `Daemon` struct +- Add methods to set the private key and mnemonic of an existing sender +- Deprecate `authz_granter` and `fee_granter` on `Daemon` struct +- Add a method on `TxHandler` to select instantiation permissions on Wasm upload ### Breaking diff --git a/cw-orch-daemon/src/core.rs b/cw-orch-daemon/src/core.rs index 8e1b882bc..e2164e2a9 100644 --- a/cw-orch-daemon/src/core.rs +++ b/cw-orch-daemon/src/core.rs @@ -17,7 +17,9 @@ use cosmrs::{ use cosmwasm_std::{Addr, Binary, Coin}; use cw_orch_core::{ contract::interface_traits::Uploadable, - environment::{AsyncWasmQuerier, ChainInfoOwned, ChainState, IndexResponse, Querier}, + environment::{ + AccessConfig, AsyncWasmQuerier, ChainInfoOwned, ChainState, IndexResponse, Querier, + }, log::transaction_target, }; use flate2::{write, Compression}; @@ -342,8 +344,17 @@ impl DaemonAsyncBase { /// Upload a contract to the chain. pub async fn upload( + &self, + uploadable: &T, + ) -> Result { + self.upload_with_access_config(uploadable, None).await + } + + /// Upload a contract to the chain and specify the permissions for instantiating + pub async fn upload_with_access_config( &self, _uploadable: &T, + access: Option, ) -> Result { let wasm_path = ::wasm(self.chain_info()); @@ -356,7 +367,7 @@ impl DaemonAsyncBase { let store_msg = cosmrs::cosmwasm::MsgStoreCode { sender: self.sender().account_id(), wasm_byte_code, - instantiate_permission: None, + instantiate_permission: access.map(access_config_to_cosmrs).transpose()?, }; let result = self @@ -378,6 +389,33 @@ impl DaemonAsyncBase { } } +fn access_config_to_cosmrs( + access_config: AccessConfig, +) -> Result { + let response = match access_config { + AccessConfig::Nobody => cosmrs::cosmwasm::AccessConfig { + permission: cosmrs::cosmwasm::AccessType::Nobody, + addresses: vec![], + }, + AccessConfig::Everybody => cosmrs::cosmwasm::AccessConfig { + permission: cosmrs::cosmwasm::AccessType::Everybody, + addresses: vec![], + }, + AccessConfig::AnyOfAddresses(addresses) => cosmrs::cosmwasm::AccessConfig { + permission: cosmrs::cosmwasm::AccessType::AnyOfAddresses, + addresses: addresses + .into_iter() + .map(|a| a.parse()) + .collect::>()?, + }, + AccessConfig::Unspecified => cosmrs::cosmwasm::AccessConfig { + permission: cosmrs::cosmwasm::AccessType::Unspecified, + addresses: vec![], + }, + }; + Ok(response) +} + impl Querier for DaemonAsync { type Error = DaemonError; } diff --git a/cw-orch-daemon/src/senders/query_only.rs b/cw-orch-daemon/src/senders/query_only.rs index c2437547b..7238e1e1e 100644 --- a/cw-orch-daemon/src/senders/query_only.rs +++ b/cw-orch-daemon/src/senders/query_only.rs @@ -46,7 +46,7 @@ impl QuerySender for QueryOnlySender { #[cfg(test)] mod tests { - use cw_orch_networks::networks::{ARCHWAY_1, JUNO_1, VOTA_ASH}; + use cw_orch_networks::networks::{ARCHWAY_1, JUNO_1}; use super::QueryOnlyDaemon; use crate::DaemonBuilder; diff --git a/cw-orch-daemon/src/sync/core.rs b/cw-orch-daemon/src/sync/core.rs index a5af8d147..7eb8615fa 100644 --- a/cw-orch-daemon/src/sync/core.rs +++ b/cw-orch-daemon/src/sync/core.rs @@ -221,6 +221,17 @@ impl TxHandler for DaemonBase { .instantiate2(code_id, init_msg, label, admin, coins, salt), ) } + + fn upload_with_access_config( + &self, + contract_source: &T, + access_config: Option, + ) -> Result { + self.rt_handle.block_on( + self.daemon + .upload_with_access_config(contract_source, access_config), + ) + } } impl Stargate for DaemonBase { diff --git a/packages/clone-testing/src/core.rs b/packages/clone-testing/src/core.rs index bd7781a7d..58772801f 100644 --- a/packages/clone-testing/src/core.rs +++ b/packages/clone-testing/src/core.rs @@ -5,19 +5,19 @@ use clone_cw_multi_test::{ wasm_emulation::{channel::RemoteChannel, storage::analyzer::StorageAnalyzer}, App, AppBuilder, BankKeeper, Contract, Executor, WasmKeeper, }; -use cosmwasm_std::{to_json_binary, WasmMsg}; -use cosmwasm_std::{Addr, Binary, Coin, CosmosMsg, Empty, Event, StdError, StdResult, Uint128}; -use cw_orch_core::contract::interface_traits::ContractInstance; +use cosmwasm_std::{ + to_json_binary, Addr, Binary, Coin, CosmosMsg, Empty, Event, StdError, StdResult, Uint128, + WasmMsg, +}; use cw_orch_core::{ - contract::interface_traits::Uploadable, + contract::interface_traits::{ContractInstance, Uploadable}, environment::{ - BankQuerier, BankSetter, ChainInfoOwned, ChainState, DefaultQueriers, IndexResponse, - StateInterface, TxHandler, + AccessConfig, BankQuerier, BankSetter, ChainInfoOwned, ChainState, DefaultQueriers, + IndexResponse, StateInterface, TxHandler, }, CwEnvError, }; -use cw_orch_daemon::{queriers::Node, RUNTIME}; -use cw_orch_daemon::{read_network_config, DEFAULT_DEPLOYMENT}; +use cw_orch_daemon::{queriers::Node, read_network_config, DEFAULT_DEPLOYMENT, RUNTIME}; use cw_utils::NativeBalance; use serde::Serialize; use tokio::runtime::Runtime; @@ -305,6 +305,15 @@ impl TxHandler for CloneTesting { Ok(resp) } + fn upload_with_access_config( + &self, + contract_source: &T, + _access_config: Option, + ) -> Result { + log::debug!("Uploading with access is not enforced when using Clone Testing"); + self.upload(contract_source) + } + fn execute( &self, exec_msg: &E, diff --git a/packages/cw-orch-core/src/contract/contract_instance.rs b/packages/cw-orch-core/src/contract/contract_instance.rs index b0c7cfe47..1958d45e2 100644 --- a/packages/cw-orch-core/src/contract/contract_instance.rs +++ b/packages/cw-orch-core/src/contract/contract_instance.rs @@ -9,6 +9,7 @@ use crate::{ log::{contract_target, transaction_target}, }; +use crate::environment::AccessConfig; use crate::environment::QueryHandler; use cosmwasm_std::{Addr, Binary, Coin}; use serde::{de::DeserializeOwned, Serialize}; @@ -102,15 +103,22 @@ impl Contract { impl Contract { // Chain interfaces - /// Upload a contract given its source - pub fn upload(&self, source: &impl Uploadable) -> Result, CwEnvError> { + /// Upload a contract given its source and specify the permissions for instantiating + pub fn upload_with_access_config( + &self, + source: &impl Uploadable, + access_config: Option, + ) -> Result, CwEnvError> { log::info!( target: &contract_target(), "[{}][Upload]", self.id, ); - let resp = self.chain.upload(source).map_err(Into::into)?; + let resp = self + .chain + .upload_with_access_config(source, access_config) + .map_err(Into::into)?; let code_id = resp.uploaded_code_id()?; self.set_code_id(code_id); log::info!( @@ -128,6 +136,11 @@ impl Contract { Ok(resp) } + /// Upload a contract given its source + pub fn upload(&self, source: &impl Uploadable) -> Result, CwEnvError> { + self.upload_with_access_config(source, None) + } + /// Executes an operation on the contract pub fn execute( &self, diff --git a/packages/cw-orch-core/src/contract/interface_traits.rs b/packages/cw-orch-core/src/contract/interface_traits.rs index 0b0f2a0e6..e7f527293 100644 --- a/packages/cw-orch-core/src/contract/interface_traits.rs +++ b/packages/cw-orch-core/src/contract/interface_traits.rs @@ -1,4 +1,5 @@ use super::{Contract, WasmPath}; +use crate::environment::AccessConfig; use crate::{ environment::{ AsyncWasmQuerier, ChainInfoOwned, ChainState, CwEnv, Environment, QueryHandler, TxHandler, @@ -262,6 +263,15 @@ pub trait CwOrchUpload: ContractInstance + Uploadable + fn upload(&self) -> Result { self.as_instance().upload(self) } + + /// upload the contract to the configured environment and specify the permissions for instantiating + fn upload_with_access_config( + &self, + access_config: Option, + ) -> Result { + self.as_instance() + .upload_with_access_config(self, access_config) + } } /// enable `.upload()` for contracts that implement `Uploadable` for that environment. diff --git a/packages/cw-orch-core/src/environment/mod.rs b/packages/cw-orch-core/src/environment/mod.rs index faf6bc470..fc1202720 100644 --- a/packages/cw-orch-core/src/environment/mod.rs +++ b/packages/cw-orch-core/src/environment/mod.rs @@ -16,4 +16,4 @@ pub use queriers::{ DefaultQueriers, Querier, QuerierGetter, QueryHandler, }; pub use state::{ChainState, StateInterface}; -pub use tx_handler::{TxHandler, TxResponse}; +pub use tx_handler::{AccessConfig, TxHandler, TxResponse}; diff --git a/packages/cw-orch-core/src/environment/tx_handler.rs b/packages/cw-orch-core/src/environment/tx_handler.rs index edd829e47..d4287350a 100644 --- a/packages/cw-orch-core/src/environment/tx_handler.rs +++ b/packages/cw-orch-core/src/environment/tx_handler.rs @@ -35,6 +35,13 @@ pub trait TxHandler: ChainState + Clone { /// Uploads a contract to the chain. fn upload(&self, contract_source: &T) -> Result; + /// Uploads a contract to the chain and specify the permissions for instantiating + fn upload_with_access_config( + &self, + contract_source: &T, + access_config: Option, + ) -> Result; + /// Send a InstantiateMsg to a contract. fn instantiate( &self, @@ -81,6 +88,39 @@ pub trait TxHandler: ChainState + Clone { } } +pub enum AccessConfig { + Unspecified, + Nobody, + Everybody, + AnyOfAddresses(Vec), +} + +impl From for cosmos_sdk_proto::cosmwasm::wasm::v1::AccessConfig { + fn from(val: AccessConfig) -> Self { + match val { + AccessConfig::Nobody => cosmos_sdk_proto::cosmwasm::wasm::v1::AccessConfig { + permission: cosmos_sdk_proto::cosmwasm::wasm::v1::AccessType::Nobody.into(), + addresses: vec![], + }, + AccessConfig::Everybody => cosmos_sdk_proto::cosmwasm::wasm::v1::AccessConfig { + permission: cosmos_sdk_proto::cosmwasm::wasm::v1::AccessType::Everybody.into(), + addresses: vec![], + }, + AccessConfig::AnyOfAddresses(addresses) => { + cosmos_sdk_proto::cosmwasm::wasm::v1::AccessConfig { + permission: cosmos_sdk_proto::cosmwasm::wasm::v1::AccessType::AnyOfAddresses + .into(), + addresses, + } + } + AccessConfig::Unspecified => cosmos_sdk_proto::cosmwasm::wasm::v1::AccessConfig { + permission: cosmos_sdk_proto::cosmwasm::wasm::v1::AccessType::Unspecified.into(), + addresses: vec![], + }, + } + } +} + // TODO: Perfect test candidate for `trybuild` #[cfg(test)] mod tests { @@ -203,6 +243,14 @@ mod tests { ) -> Result { unimplemented!() } + + fn upload_with_access_config( + &self, + _contract_source: &T, + _access_config: Option, + ) -> Result { + unimplemented!() + } } fn associated_error(t: T) -> anyhow::Result<()> { diff --git a/packages/cw-orch-mock/src/core.rs b/packages/cw-orch-mock/src/core.rs index 7d9313722..9d376a489 100644 --- a/packages/cw-orch-mock/src/core.rs +++ b/packages/cw-orch-mock/src/core.rs @@ -13,7 +13,7 @@ use serde::Serialize; use super::state::MockState; use cw_orch_core::{ contract::interface_traits::Uploadable, - environment::{ChainState, IndexResponse, StateInterface, TxHandler}, + environment::{AccessConfig, ChainState, IndexResponse, StateInterface, TxHandler}, CwEnvError, }; @@ -248,6 +248,15 @@ impl TxHandler for MockBase { ) .map_err(From::from) } + + fn upload_with_access_config( + &self, + contract_source: &T, + _access_config: Option, + ) -> Result { + log::debug!("Uploading with access is not enforced when using Mock testing"); + self.upload(contract_source) + } } #[cfg(test)]