Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added variable-length contract address support #65

Merged
merged 2 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 53 additions & 11 deletions contracts/main/voice/src/contract.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{
from_json, instantiate2_address, to_json_binary, to_json_vec, Binary, CodeInfoResponse,
ContractResult, Deps, DepsMut, Env, MessageInfo, Response, StdResult, SubMsg, SystemResult,
Uint64, WasmMsg,
from_json, instantiate2_address, to_json_binary, to_json_vec, Binary, CanonicalAddr,
CodeInfoResponse, ContractResult, Deps, DepsMut, Env, MessageInfo, Response, StdResult, SubMsg,
SystemResult, Uint64, WasmMsg,
};
use cw2::set_contract_version;

Expand All @@ -13,7 +13,9 @@ use polytone::ibc::{Msg, Packet};
use crate::error::ContractError;
use crate::ibc::{ACK_GAS_NEEDED, REPLY_FORWARD_DATA};
use crate::msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
use crate::state::{BLOCK_MAX_GAS, PROXY_CODE_ID, SENDER_TO_PROXY};
use crate::state::{
SenderInfo, BLOCK_MAX_GAS, CONTRACT_ADDR_LEN, PROXY_CODE_ID, PROXY_TO_SENDER, SENDER_TO_PROXY,
};

const CONTRACT_NAME: &str = "crates.io:polytone-voice";
const CONTRACT_VERSION: &str = env!("CARGO_PKG_VERSION");
Expand All @@ -35,13 +37,23 @@ pub fn instantiate(
return Err(ContractError::GasLimitsMismatch);
}

let contract_addr_len = msg.contract_addr_len.unwrap_or(32);
if contract_addr_len == 0 {
return Err(ContractError::ContractAddrLenCantBeZero);
}
if contract_addr_len > 32 {
return Err(ContractError::ContractAddrLenCantBeGreaterThan32);
}

PROXY_CODE_ID.save(deps.storage, &msg.proxy_code_id.u64())?;
BLOCK_MAX_GAS.save(deps.storage, &msg.block_max_gas.u64())?;
CONTRACT_ADDR_LEN.save(deps.storage, &contract_addr_len)?;

Ok(Response::default()
.add_attribute("method", "instantiate")
.add_attribute("proxy_code_id", msg.proxy_code_id)
.add_attribute("block_max_gas", msg.block_max_gas))
.add_attribute("block_max_gas", msg.block_max_gas)
.add_attribute("contract_addr_len", contract_addr_len.to_string()))
}

#[cfg_attr(not(feature = "library"), entry_point)]
Expand Down Expand Up @@ -104,17 +116,33 @@ pub fn execute(
let contract =
deps.api.addr_canonicalize(env.contract.address.as_str())?;
let code_id = PROXY_CODE_ID.load(deps.storage)?;
let addr_len = CONTRACT_ADDR_LEN.load(deps.storage)?;
let CodeInfoResponse { checksum, .. } =
deps.querier.query_wasm_code_info(code_id)?;
let salt = salt(&connection_id, &counterparty_port, &sender);
let proxy = deps.api.addr_humanize(&instantiate2_address(
&checksum, &contract, &salt,
)?)?;
let init2_addr_data: CanonicalAddr =
instantiate2_address(&checksum, &contract, &salt)?.to_vec()
[0..addr_len as usize]
NoahSaso marked this conversation as resolved.
Show resolved Hide resolved
.into();
let proxy = deps.api.addr_humanize(&init2_addr_data)?;
SENDER_TO_PROXY.save(
deps.storage,
(connection_id, counterparty_port, sender.clone()),
(
connection_id.clone(),
counterparty_port.clone(),
sender.clone(),
),
&proxy,
)?;
PROXY_TO_SENDER.save(
deps.storage,
proxy.clone(),
&SenderInfo {
connection_id,
remote_port: counterparty_port,
remote_sender: sender.clone(),
},
)?;
(
Some(WasmMsg::Instantiate2 {
admin: None,
Expand Down Expand Up @@ -171,6 +199,10 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
match msg {
QueryMsg::BlockMaxGas => to_json_binary(&BLOCK_MAX_GAS.load(deps.storage)?),
QueryMsg::ProxyCodeId => to_json_binary(&PROXY_CODE_ID.load(deps.storage)?),
QueryMsg::ContractAddrLen => to_json_binary(&CONTRACT_ADDR_LEN.load(deps.storage)?),
QueryMsg::SenderInfoForProxy { proxy } => {
to_json_binary(&PROXY_TO_SENDER.load(deps.storage, deps.api.addr_validate(&proxy)?)?)
}
}
}

Expand All @@ -180,6 +212,7 @@ pub fn migrate(deps: DepsMut, _env: Env, msg: MigrateMsg) -> Result<Response, Co
MigrateMsg::WithUpdate {
proxy_code_id,
block_max_gas,
contract_addr_len,
} => {
if proxy_code_id.is_zero() {
return Err(ContractError::CodeIdCantBeZero);
Expand All @@ -189,14 +222,23 @@ pub fn migrate(deps: DepsMut, _env: Env, msg: MigrateMsg) -> Result<Response, Co
return Err(ContractError::GasLimitsMismatch);
}

// update the proxy code ID and block max gas
if contract_addr_len == 0 {
return Err(ContractError::ContractAddrLenCantBeZero);
}
if contract_addr_len > 32 {
return Err(ContractError::ContractAddrLenCantBeGreaterThan32);
}

// update the proxy code ID, block max gas, and contract addr len
PROXY_CODE_ID.save(deps.storage, &proxy_code_id.u64())?;
BLOCK_MAX_GAS.save(deps.storage, &block_max_gas.u64())?;
CONTRACT_ADDR_LEN.save(deps.storage, &contract_addr_len)?;

Ok(Response::default()
.add_attribute("method", "migrate_with_update")
.add_attribute("proxy_code_id", proxy_code_id)
.add_attribute("block_max_gas", block_max_gas))
.add_attribute("block_max_gas", block_max_gas)
.add_attribute("contract_addr_len", contract_addr_len.to_string()))
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions contracts/main/voice/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,10 @@ pub enum ContractError {

#[error("ACK_GAS_NEEDED can't be higher then BLOCK_MAX_GAS")]
GasLimitsMismatch,

#[error("Contract address length can't be zero")]
ContractAddrLenCantBeZero,

#[error("Contract address length can't be greater than 32")]
ContractAddrLenCantBeGreaterThan32,
}
13 changes: 13 additions & 0 deletions contracts/main/voice/src/msg.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
use cosmwasm_schema::{cw_serde, QueryResponses};
use cosmwasm_std::{Binary, Uint64};

use crate::state::SenderInfo;

#[cw_serde]
pub struct InstantiateMsg {
/// Code ID to use for instantiating proxy contracts.
pub proxy_code_id: Uint64,
/// The max gas allowed in a single block.
pub block_max_gas: Uint64,
/// The contract address length used by the chain. Defaults to 32. Some
/// chains use other lengths, such as Injective which uses 20.
pub contract_addr_len: Option<u8>,
}

#[cw_serde]
Expand Down Expand Up @@ -35,6 +40,12 @@ pub enum QueryMsg {
/// `"proxy_code_id"`.
#[returns(Uint64)]
ProxyCodeId,
/// Queries the configured contract address length.
#[returns(u8)]
ContractAddrLen,
/// Queries the sender information for a given proxy.
#[returns(SenderInfo)]
SenderInfoForProxy { proxy: String },
}

#[cw_serde]
Expand All @@ -45,5 +56,7 @@ pub enum MigrateMsg {
proxy_code_id: Uint64,
/// The max gas allowed in a single block.
block_max_gas: Uint64,
/// The contract address length used by the chain.
contract_addr_len: u8,
},
}
14 changes: 14 additions & 0 deletions contracts/main/voice/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use cosmwasm_schema::cw_serde;
use cosmwasm_std::Addr;
use cw_storage_plus::{Item, Map};

/// (connection_id, remote_port, remote_sender) -> proxy
pub(crate) const SENDER_TO_PROXY: Map<(String, String, String), Addr> = Map::new("c2p");

/// proxy -> { connection_id, remote_port, remote_sender }
pub(crate) const PROXY_TO_SENDER: Map<Addr, SenderInfo> = Map::new("p2c");

/// (channel_id) -> connection_id
pub(crate) const CHANNEL_TO_CONNECTION: Map<String, String> = Map::new("c2c");

Expand All @@ -12,3 +16,13 @@ pub(crate) const PROXY_CODE_ID: Item<u64> = Item::new("pci");

/// Max gas usable in a single block.
pub(crate) const BLOCK_MAX_GAS: Item<u64> = Item::new("bmg");

/// Contract address length used by the chain.
pub(crate) const CONTRACT_ADDR_LEN: Item<u8> = Item::new("cal");

#[cw_serde]
pub struct SenderInfo {
pub connection_id: String,
pub remote_port: String,
pub remote_sender: String,
}
22 changes: 21 additions & 1 deletion contracts/main/voice/src/suite_tests/suite.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use cosmwasm_std::{Addr, Empty, Uint64};
use cw_multi_test::{App, AppResponse, Contract, ContractWrapper, Executor};

use crate::msg::QueryMsg::{BlockMaxGas, ProxyCodeId};
use crate::msg::QueryMsg::{BlockMaxGas, ContractAddrLen, ProxyCodeId};
use crate::msg::{InstantiateMsg, MigrateMsg};

pub const CREATOR_ADDR: &str = "creator";
Expand Down Expand Up @@ -33,6 +33,7 @@ impl Default for SuiteBuilder {
instantiate: InstantiateMsg {
proxy_code_id: Uint64::new(9999),
block_max_gas: Uint64::new(110_000),
contract_addr_len: None,
},
}
}
Expand Down Expand Up @@ -72,6 +73,11 @@ impl SuiteBuilder {
self.instantiate.proxy_code_id = code_id;
self
}

pub fn with_contract_addr_len(mut self, len: Option<u8>) -> Self {
self.instantiate.contract_addr_len = len;
self
}
}

impl Suite {
Expand All @@ -95,6 +101,13 @@ impl Suite {
.query_wasm_smart(&self.voice_address, &ProxyCodeId)
.unwrap()
}

pub fn query_contract_addr_len(&self) -> u8 {
self.app
.wrap()
.query_wasm_smart(&self.voice_address, &ContractAddrLen)
.unwrap()
}
}

// migrate
Expand All @@ -104,13 +117,15 @@ impl Suite {
sender: Addr,
contract_code_id: u64,
block_max_gas: u64,
contract_addr_len: u8,
) -> anyhow::Result<AppResponse> {
self.app.migrate_contract(
sender,
self.voice_address.clone(),
&MigrateMsg::WithUpdate {
proxy_code_id: contract_code_id.into(),
block_max_gas: block_max_gas.into(),
contract_addr_len,
},
self.voice_code,
)
Expand All @@ -128,4 +143,9 @@ impl Suite {
let curr = self.query_proxy_code_id();
assert_eq!(curr, val);
}

pub fn assert_contract_addr_len(&self, val: u8) {
let curr = self.query_contract_addr_len();
assert_eq!(curr, val);
}
}
55 changes: 50 additions & 5 deletions contracts/main/voice/src/suite_tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ fn test_update() {
let proxy_code_new = suite.store_voice_contract();

suite
.update(Addr::unchecked(CREATOR_ADDR), proxy_code_new, 111_000)
.update(Addr::unchecked(CREATOR_ADDR), proxy_code_new, 111_000, 32)
.unwrap();

// assert that both fields updated succesfully
Expand All @@ -31,7 +31,7 @@ fn test_query_block_max_gas() {
suite.assert_block_max_gas(110_000);

suite
.update(Addr::unchecked(CREATOR_ADDR), suite.voice_code, 111_000)
.update(Addr::unchecked(CREATOR_ADDR), suite.voice_code, 111_000, 32)
.unwrap();

suite.assert_block_max_gas(111_000);
Expand All @@ -44,12 +44,25 @@ fn test_query_proxy_code_id() {
suite.assert_proxy_code(9999);

suite
.update(Addr::unchecked(CREATOR_ADDR), 1, 110_000)
.update(Addr::unchecked(CREATOR_ADDR), 1, 110_000, 32)
.unwrap();

suite.assert_proxy_code(1);
}

#[test]
fn test_query_contract_addr_len() {
let mut suite = SuiteBuilder::default().build();

suite.assert_contract_addr_len(32);

suite
.update(Addr::unchecked(CREATOR_ADDR), 1, 110_000, 20)
.unwrap();

suite.assert_contract_addr_len(20);
}

#[test]
#[should_panic]
fn test_code_id_validation() {
Expand All @@ -66,23 +79,55 @@ fn test_gas_validation() {
.build();
}

#[test]
#[should_panic]
fn test_contract_addr_len_min_validation() {
SuiteBuilder::default()
.with_contract_addr_len(Some(0))
.build();
}

#[test]
#[should_panic]
fn test_contract_addr_len_max_validation() {
SuiteBuilder::default()
.with_contract_addr_len(Some(33))
.build();
}

#[test]
fn test_migrate_validation() {
let mut suite = SuiteBuilder::default().build();

let err = suite
.update(Addr::unchecked(CREATOR_ADDR), 0, 110_000)
.update(Addr::unchecked(CREATOR_ADDR), 0, 110_000, 32)
.unwrap_err()
.downcast::<ContractError>()
.unwrap();

assert_eq!(err, ContractError::CodeIdCantBeZero);

let err = suite
.update(Addr::unchecked(CREATOR_ADDR), 1, 0)
.update(Addr::unchecked(CREATOR_ADDR), 1, 0, 32)
.unwrap_err()
.downcast::<ContractError>()
.unwrap();

assert_eq!(err, ContractError::GasLimitsMismatch);

let err = suite
.update(Addr::unchecked(CREATOR_ADDR), 1, 110_000, 0)
.unwrap_err()
.downcast::<ContractError>()
.unwrap();

assert_eq!(err, ContractError::ContractAddrLenCantBeZero);

let err = suite
.update(Addr::unchecked(CREATOR_ADDR), 1, 110_000, 33)
.unwrap_err()
.downcast::<ContractError>()
.unwrap();

assert_eq!(err, ContractError::ContractAddrLenCantBeGreaterThan32);
}
1 change: 1 addition & 0 deletions packages/cw-orch-polytone/src/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ impl<Chain: CwEnv> Deploy<Chain> for Polytone<Chain> {
&polytone_voice::msg::InstantiateMsg {
proxy_code_id: deployment.proxy.code_id()?.into(),
block_max_gas: MAX_BLOCK_GAS.into(),
contract_addr_len: None,
},
None,
None,
Expand Down
Loading
Loading