Skip to content

Commit

Permalink
Merge pull request #97 from arkprotocol/contract_address_length
Browse files Browse the repository at this point in the history
consider contract address length for instantiate2
  • Loading branch information
taitruong authored May 31, 2024
2 parents 3eb6f72 + 482054d commit 1f39e18
Show file tree
Hide file tree
Showing 13 changed files with 180 additions and 30 deletions.
33 changes: 23 additions & 10 deletions contracts/sg-ics721/src/testing/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ impl Test {
outgoing_proxy,
pauser: admin.clone(),
cw721_admin: admin,
contract_addr_length: None,
},
&[],
"sg-ics721",
Expand Down Expand Up @@ -464,6 +465,13 @@ impl Test {
.unwrap()
}

fn query_contract_addr_length(&mut self) -> Option<u32> {
self.app
.wrap()
.query_wasm_smart(self.ics721.clone(), &QueryMsg::ContractAddrLength {})
.unwrap()
}

fn query_nft_contracts(&mut self) -> Vec<(String, Addr)> {
self.app
.wrap()
Expand Down Expand Up @@ -2350,6 +2358,7 @@ fn test_pause() {
outgoing_proxy: None,
cw721_base_code_id: None,
cw721_admin: None,
contract_addr_length: None,
})
.unwrap(),
}
Expand Down Expand Up @@ -2404,6 +2413,7 @@ fn test_migration() {
outgoing_proxy: None,
cw721_base_code_id: Some(12345678),
cw721_admin: Some(admin.to_string()),
contract_addr_length: Some(20), // injective have 20 bytes addresses
})
.unwrap(),
}
Expand All @@ -2417,23 +2427,25 @@ fn test_migration() {
assert!(proxy.is_none());
let cw721_code_id = test.query_cw721_id();
assert_eq!(cw721_code_id, 12345678);
assert_eq!(test.query_cw721_admin(), Some(admin),);
assert_eq!(test.query_cw721_admin(), Some(admin));
assert_eq!(test.query_contract_addr_length(), Some(20),);

// migrate without changing code id
let msg = MigrateMsg::WithUpdate {
pauser: None,
incoming_proxy: None,
outgoing_proxy: None,
cw721_base_code_id: None,
cw721_admin: Some("".to_string()),
contract_addr_length: None,
};
test.app
.execute(
test.app.api().addr_make(ICS721_ADMIN_AND_PAUSER),
WasmMsg::Migrate {
contract_addr: test.ics721.to_string(),
new_code_id: test.ics721_id,
msg: to_json_binary(&MigrateMsg::WithUpdate {
pauser: None,
incoming_proxy: None,
outgoing_proxy: None,
cw721_base_code_id: None,
cw721_admin: Some("".to_string()),
})
.unwrap(),
msg: to_json_binary(&msg).unwrap(),
}
.into(),
)
Expand All @@ -2445,5 +2457,6 @@ fn test_migration() {
assert!(proxy.is_none());
let cw721_code_id = test.query_cw721_id();
assert_eq!(cw721_code_id, 12345678);
assert_eq!(test.query_cw721_admin(), None,);
assert_eq!(test.query_cw721_admin(), None);
assert_eq!(test.query_contract_addr_length(), None,);
}
33 changes: 33 additions & 0 deletions packages/ics721/schema/ics721.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@
"cw721_base_code_id"
],
"properties": {
"contract_addr_length": {
"description": "The optional contract address length being used for instantiate2. In case of None, default length is 32 (standard in cosmwasm).",
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
},
"cw721_admin": {
"description": "The admin address for instantiating new cw721 contracts. In case of None, contract is immutable.",
"type": [
Expand Down Expand Up @@ -1047,6 +1056,20 @@
},
"additionalProperties": false
},
{
"description": "Gets the contract address length being used for instantiate2. In case of None, default length is 32 (standard in cosmwasm).",
"type": "object",
"required": [
"contract_addr_length"
],
"properties": {
"contract_addr_length": {
"type": "object",
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"description": "Gets a list of classID as key (from NonFungibleTokenPacketData) and cw721 contract as value (instantiated for that classID).",
"type": "object",
Expand Down Expand Up @@ -1255,6 +1278,16 @@
}
}
},
"contract_addr_length": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Nullable_uint32",
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
},
"cw721_admin": {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Nullable_Nullable_Addr",
Expand Down
9 changes: 9 additions & 0 deletions packages/ics721/schema/raw/instantiate.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@
"cw721_base_code_id"
],
"properties": {
"contract_addr_length": {
"description": "The optional contract address length being used for instantiate2. In case of None, default length is 32 (standard in cosmwasm).",
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
},
"cw721_admin": {
"description": "The admin address for instantiating new cw721 contracts. In case of None, contract is immutable.",
"type": [
Expand Down
14 changes: 14 additions & 0 deletions packages/ics721/schema/raw/query.json
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,20 @@
},
"additionalProperties": false
},
{
"description": "Gets the contract address length being used for instantiate2. In case of None, default length is 32 (standard in cosmwasm).",
"type": "object",
"required": [
"contract_addr_length"
],
"properties": {
"contract_addr_length": {
"type": "object",
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"description": "Gets a list of classID as key (from NonFungibleTokenPacketData) and cw721 contract as value (instantiated for that classID).",
"type": "object",
Expand Down
10 changes: 10 additions & 0 deletions packages/ics721/schema/raw/response_to_contract_addr_length.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Nullable_uint32",
"type": [
"integer",
"null"
],
"format": "uint32",
"minimum": 0.0
}
25 changes: 24 additions & 1 deletion packages/ics721/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use crate::{
},
state::{
ClassIdInfo, CollectionData, UniversalAllNftInfoResponse, ADMIN_USED_FOR_CW721,
CLASS_ID_AND_NFT_CONTRACT_INFO, CLASS_ID_TO_CLASS, CW721_CODE_ID,
CLASS_ID_AND_NFT_CONTRACT_INFO, CLASS_ID_TO_CLASS, CONTRACT_ADDR_LENGTH, CW721_CODE_ID,
INCOMING_CLASS_TOKEN_TO_CHANNEL, INCOMING_PROXY, OUTGOING_CLASS_TOKEN_TO_CHANNEL,
OUTGOING_PROXY, PO, TOKEN_METADATA,
},
Expand Down Expand Up @@ -76,6 +76,13 @@ where
.transpose()?,
)?;

let contract_addr_length = msg.contract_addr_length;
if let Some(contract_addr_length) = contract_addr_length {
CONTRACT_ADDR_LENGTH.save(deps.storage, &contract_addr_length)?;
} else {
CONTRACT_ADDR_LENGTH.remove(deps.storage);
}

Ok(Response::default()
.add_submessages(proxies_instantiate)
.add_attribute("method", "instantiate")
Expand All @@ -84,6 +91,10 @@ where
"cw721_admin",
msg.cw721_admin
.map_or_else(|| "immutable".to_string(), |or| or),
)
.add_attribute(
"contract_addr_length",
contract_addr_length.map_or_else(|| "none".to_string(), |or| or.to_string()),
))
}

Expand Down Expand Up @@ -711,6 +722,7 @@ where
outgoing_proxy,
cw721_base_code_id,
cw721_admin,
contract_addr_length,
} => {
// disables incoming proxy if none is provided!
INCOMING_PROXY.save(
Expand Down Expand Up @@ -741,6 +753,12 @@ where
}
}

if let Some(contract_addr_length) = contract_addr_length {
CONTRACT_ADDR_LENGTH.save(deps.storage, &contract_addr_length)?;
} else {
CONTRACT_ADDR_LENGTH.remove(deps.storage);
}

let response = Response::default()
.add_attribute("method", "migrate")
.add_attribute("pauser", pauser.map_or_else(|| "none".to_string(), |or| or))
Expand Down Expand Up @@ -768,6 +786,11 @@ where
}
},
),
)
.add_attribute(
"contract_addr_length",
contract_addr_length
.map_or_else(|| "none".to_string(), |or| or.to_string()),
);

self.migrate_legacy(deps, response)
Expand Down
16 changes: 13 additions & 3 deletions packages/ics721/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ use cosmwasm_std::{
};
use serde::Deserialize;

use crate::{ibc::ACK_CALLBACK_REPLY_ID, state::INCOMING_PROXY, ContractError};
use crate::{
ibc::ACK_CALLBACK_REPLY_ID,
state::{CONTRACT_ADDR_LENGTH, INCOMING_PROXY},
ContractError,
};
use ics721_types::{
ibc_types::NonFungibleTokenPacketData,
types::{
Expand Down Expand Up @@ -147,8 +151,14 @@ pub fn get_instantiate2_address(
let CodeInfoResponse { checksum, .. } = deps.querier.query_wasm_code_info(code_id)?;

let canonical_cw721_addr = instantiate2_address(&checksum, &canonical_creator, salt)?;

Ok(deps.api.addr_humanize(&canonical_cw721_addr)?)
if let Some(contract_addr_length) = CONTRACT_ADDR_LENGTH.may_load(deps.storage)? {
let contract_addr_length = contract_addr_length as usize;
Ok(deps
.api
.addr_humanize(&canonical_cw721_addr[..contract_addr_length].into())?)
} else {
Ok(deps.api.addr_humanize(&canonical_cw721_addr)?)
}
}

mod test {
Expand Down
8 changes: 8 additions & 0 deletions packages/ics721/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ pub struct InstantiateMsg {
pub pauser: Option<String>,
/// The admin address for instantiating new cw721 contracts. In case of None, contract is immutable.
pub cw721_admin: Option<String>,
/// The optional contract address length being used for instantiate2. In case of None, default length is 32 (standard in cosmwasm).
pub contract_addr_length: Option<u32>,
}

#[cw_serde]
Expand Down Expand Up @@ -162,6 +164,10 @@ pub enum QueryMsg {
#[returns(Option<Option<::cosmwasm_std::Addr>>)]
Cw721Admin {},

/// Gets the contract address length being used for instantiate2. In case of None, default length is 32 (standard in cosmwasm).
#[returns(Option<u32>)]
ContractAddrLength {},

/// Gets a list of classID as key (from
/// NonFungibleTokenPacketData) and cw721 contract as value
/// (instantiated for that classID).
Expand Down Expand Up @@ -212,5 +218,7 @@ pub enum MigrateMsg {
cw721_base_code_id: Option<u64>,
/// The admin address for instantiating new cw721 contracts. In case of "", contract is immutable.
cw721_admin: Option<String>,
/// The optional contract address length being used for instantiate2. In case of None, default length is 32 (standard in cosmwasm).
contract_addr_length: Option<u32>,
},
}
7 changes: 5 additions & 2 deletions packages/ics721/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::{
msg::QueryMsg,
state::{
UniversalAllNftInfoResponse, ADMIN_USED_FOR_CW721, CLASS_ID_AND_NFT_CONTRACT_INFO,
CLASS_ID_TO_CLASS, CW721_CODE_ID, INCOMING_CLASS_TOKEN_TO_CHANNEL, INCOMING_PROXY,
OUTGOING_CLASS_TOKEN_TO_CHANNEL, OUTGOING_PROXY, PO, TOKEN_METADATA,
CLASS_ID_TO_CLASS, CONTRACT_ADDR_LENGTH, CW721_CODE_ID, INCOMING_CLASS_TOKEN_TO_CHANNEL,
INCOMING_PROXY, OUTGOING_CLASS_TOKEN_TO_CHANNEL, OUTGOING_PROXY, PO, TOKEN_METADATA,
},
};
use ics721_types::token_types::{Class, ClassId, ClassToken, Token, TokenId};
Expand Down Expand Up @@ -35,6 +35,9 @@ pub trait Ics721Query {
QueryMsg::IncomingProxy {} => to_json_binary(&INCOMING_PROXY.load(deps.storage)?),
QueryMsg::Cw721CodeId {} => to_json_binary(&query_cw721_code_id(deps)?),
QueryMsg::Cw721Admin {} => to_json_binary(&ADMIN_USED_FOR_CW721.load(deps.storage)?),
QueryMsg::ContractAddrLength {} => {
to_json_binary(&CONTRACT_ADDR_LENGTH.may_load(deps.storage)?)
}
QueryMsg::NftContracts { start_after, limit } => {
to_json_binary(&query_nft_contracts(deps, start_after, limit)?)
}
Expand Down
7 changes: 7 additions & 0 deletions packages/ics721/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,22 @@ pub const CLASS_ID_TO_CLASS: Map<ClassId, Class> = Map::new("g");
pub const OUTGOING_CLASS_TOKEN_TO_CHANNEL: Map<(ClassId, TokenId), String> = Map::new("h");
/// Same as above, but for NFTs arriving at this contract.
pub const INCOMING_CLASS_TOKEN_TO_CHANNEL: Map<(ClassId, TokenId), String> = Map::new("i");

/// Maps (class ID, token ID) -> token metadata. Used to store
/// on-chain metadata for tokens that have arrived from other
/// chains. When a token arrives, it's metadata (regardless of if it
/// is `None`) is stored in this map. When the token is returned to
/// it's source chain, the metadata is removed from the map.
pub const TOKEN_METADATA: Map<(ClassId, TokenId), Option<Binary>> = Map::new("j");

/// The admin address for instantiating new cw721 contracts. In case of None, contract is immutable.
pub const ADMIN_USED_FOR_CW721: Item<Option<Addr>> = Item::new("l");

/// The optional contract address length being used for instantiate2. In case of None, default length is 32 (standard in cosmwasm).
/// So length must be shorter than 32. For example, Injective has 20 length address.
/// Bug: https://github.com/CosmWasm/cosmwasm/issues/2155
pub const CONTRACT_ADDR_LENGTH: Item<u32> = Item::new("n");

#[derive(Deserialize)]
pub struct UniversalAllNftInfoResponse {
pub access: UniversalOwnerOfResponse,
Expand Down
Loading

0 comments on commit 1f39e18

Please sign in to comment.