Skip to content

Commit

Permalink
new CW721_CREATOR store
Browse files Browse the repository at this point in the history
  • Loading branch information
taitruong committed Jun 11, 2024
1 parent d00ae80 commit 4321558
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 72 deletions.
35 changes: 19 additions & 16 deletions contracts/sg-ics721/src/execute.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use cosmwasm_std::{from_json, to_json_binary, Addr, Binary, Deps, DepsMut, Env, StdResult};
use ics721::{execute::Ics721Execute, state::CollectionData, utils::get_collection_data};
use ics721::{
execute::Ics721Execute,
state::{CollectionData, CW721_CREATOR},
utils::get_collection_data,
};
use ics721_types::token_types::Class;

use sg721_base::msg::{CollectionInfoResponse, QueryMsg};
Expand Down Expand Up @@ -32,28 +36,27 @@ impl Ics721Execute for SgIcs721Contract {
}))
}

fn init_msg(
&self,
deps: Deps,
env: &Env,
class: &Class,
_cw721_admin: Option<String>,
) -> StdResult<Binary> {
// ics721 creator is used, in case no source owner in class data is provided (e.g. due to nft-transfer module).
let ics721_contract_info = deps
.querier
.query_wasm_contract_info(env.contract.address.to_string())?;
fn init_msg(&self, deps: Deps, env: &Env, class: &Class) -> StdResult<Binary> {
let cw721_creator =
if let Some(creator) = CW721_CREATOR.load(deps.storage)?.map(|a| a.to_string()) {
creator
} else {
// NOTE: owner in class data comes from other chain and could be: 1. regular wallet, 2. contract, or 3. multisig
// bech32 calculation for 2. and 3. leads to unknown address
// therefore, we use ics721 creator as owner
let ics721_contract_info = deps
.querier
.query_wasm_contract_info(env.contract.address.to_string())?;
ics721_contract_info.creator
};
// use by default ClassId, in case there's no class data with name and symbol
let mut instantiate_msg = sg721::InstantiateMsg {
name: class.id.clone().into(),
symbol: class.id.clone().into(),
minter: env.contract.address.to_string(),
// creator: cw721_admin, // TODO: once sg721 migrates to cw721 v19, use cw721_admin for setting creator
collection_info: sg721::CollectionInfo {
// source owner could be: 1. regular wallet, 2. contract, or 3. multisig
// bech32 calculation for 2. and 3. leads to unknown address
// therefore, we use ics721 creator as owner
creator: ics721_contract_info.creator,
creator: cw721_creator,
description: "".to_string(),
// use Stargaze icon as placeholder
image: STARGAZE_ICON_PLACEHOLDER.to_string(),
Expand Down
29 changes: 23 additions & 6 deletions contracts/sg-ics721/src/testing/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ const CHANNEL_TARGET_CHAIN: &str = "channel-1";
const BECH32_PREFIX_HRP: &str = "stars";
const NFT_OWNER_TARGET_CHAIN: &str = "nft-owner-target-chain";
const ICS721_ADMIN_AND_PAUSER: &str = "ics721-pauser";
const CW721_ADMIN: &str = "cw721-admin";
const CW721_CREATOR: &str = "cw721-creator";

type MockRouter = Router<
BankKeeper,
Expand Down Expand Up @@ -365,6 +367,7 @@ impl Test {
outgoing_proxy,
pauser: admin_and_pauser.clone(),
cw721_admin: admin_and_pauser.clone(),
cw721_creator: admin_and_pauser.clone(),
contract_addr_length: None,
},
&[],
Expand Down Expand Up @@ -478,6 +481,13 @@ impl Test {
.unwrap()
}

fn query_cw721_creator(&mut self) -> Option<Addr> {
self.app
.wrap()
.query_wasm_smart(self.ics721.clone(), &QueryMsg::Cw721Creator {})
.unwrap()
}

fn query_contract_addr_length(&mut self) -> Option<u32> {
self.app
.wrap()
Expand Down Expand Up @@ -2720,6 +2730,7 @@ fn test_pause() {
outgoing_proxy: None,
cw721_base_code_id: None,
cw721_admin: None,
cw721_creator: None,
contract_addr_length: None,
})
.unwrap(),
Expand Down Expand Up @@ -2756,13 +2767,15 @@ fn test_migration() {
pauser,
Some(test.app.api().addr_make(ICS721_ADMIN_AND_PAUSER))
);
let proxy = test.query_outgoing_proxy();
assert!(proxy.is_some());
let outgoing_proxy = test.query_outgoing_proxy();
assert!(outgoing_proxy.is_some());
let cw721_code_id = test.query_cw721_id();
assert_eq!(cw721_code_id, test.source_cw721_id);

// migrate changes
let admin = test.app.api().addr_make(ICS721_ADMIN_AND_PAUSER);
let cw721_admin = test.app.api().addr_make(CW721_ADMIN);
let cw721_creator = test.app.api().addr_make(CW721_CREATOR);
test.app
.execute(
admin.clone(),
Expand All @@ -2774,8 +2787,9 @@ fn test_migration() {
incoming_proxy: None,
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
cw721_admin: Some(cw721_admin.to_string()),
cw721_creator: Some(cw721_creator.to_string()),
contract_addr_length: Some(20),
})
.unwrap(),
}
Expand All @@ -2789,7 +2803,8 @@ 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(cw721_admin));
assert_eq!(test.query_cw721_creator(), Some(cw721_creator));
assert_eq!(test.query_contract_addr_length(), Some(20),);

// migrate without changing code id
Expand All @@ -2799,6 +2814,7 @@ fn test_migration() {
outgoing_proxy: None,
cw721_base_code_id: None,
cw721_admin: Some("".to_string()),
cw721_creator: Some("".to_string()),
contract_addr_length: None,
};
test.app
Expand All @@ -2820,5 +2836,6 @@ fn test_migration() {
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_contract_addr_length(), None,);
assert_eq!(test.query_cw721_creator(), None);
assert_eq!(test.query_contract_addr_length(), None);
}
85 changes: 65 additions & 20 deletions packages/ics721/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ use crate::{
query_nft_contract_for_class_id, query_nft_contracts,
},
state::{
ClassIdInfo, CollectionData, UniversalAllNftInfoResponse, ADMIN_USED_FOR_CW721,
CLASS_ID_AND_NFT_CONTRACT_INFO, CLASS_ID_TO_CLASS, CONTRACT_ADDR_LENGTH, CW721_CODE_ID,
ClassIdInfo, CollectionData, UniversalAllNftInfoResponse, CLASS_ID_AND_NFT_CONTRACT_INFO,
CLASS_ID_TO_CLASS, CONTRACT_ADDR_LENGTH, CW721_ADMIN, CW721_CODE_ID, CW721_CREATOR,
INCOMING_CLASS_TOKEN_TO_CHANNEL, INCOMING_PROXY, OUTGOING_CLASS_TOKEN_TO_CHANNEL,
OUTGOING_PROXY, PO, TOKEN_METADATA,
},
Expand Down Expand Up @@ -72,14 +72,22 @@ where
));
}

ADMIN_USED_FOR_CW721.save(
CW721_ADMIN.save(
deps.storage,
&msg.cw721_admin
.as_ref()
.map(|h| deps.api.addr_validate(h))
.transpose()?,
)?;

CW721_CREATOR.save(
deps.storage,
&msg.cw721_creator
.as_ref()
.map(|h| deps.api.addr_validate(h))
.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)?;
Expand All @@ -93,8 +101,29 @@ where
.add_attribute("cw721_code_id", msg.cw721_base_code_id.to_string())
.add_attribute(
"cw721_admin",
msg.cw721_admin
.map_or_else(|| "immutable".to_string(), |or| or),
msg.cw721_admin.map_or_else(
|| "immutable".to_string(),
|or| {
if or.is_empty() {
"immutable".to_string()
} else {
or
}
},
),
)
.add_attribute(
"cw721_creator",
msg.cw721_creator.map_or_else(
|| "none".to_string(),
|or| {
if or.is_empty() {
"none".to_string()
} else {
or
}
},
),
)
.add_attribute(
"contract_addr_length",
Expand Down Expand Up @@ -603,14 +632,12 @@ where
};
CLASS_ID_AND_NFT_CONTRACT_INFO.save(deps.storage, &class.id, &class_id_info)?;

let cw721_admin = ADMIN_USED_FOR_CW721
.load(deps.storage)?
.map(|a| a.to_string());
let cw721_admin = CW721_ADMIN.load(deps.storage)?.map(|a| a.to_string());
let message = SubMsg::<T>::reply_on_success(
WasmMsg::Instantiate2 {
admin: cw721_admin.clone(),
admin: cw721_admin,
code_id: cw721_code_id,
msg: self.init_msg(deps.as_ref(), env, &class, cw721_admin)?,
msg: self.init_msg(deps.as_ref(), env, &class)?,
funds: vec![],
// Attempting to fit the class ID in the label field
// can make this field too long which causes data
Expand All @@ -625,13 +652,8 @@ where
}

/// Default implementation using `cw721_base::msg::InstantiateMsg`
fn init_msg(
&self,
deps: Deps,
env: &Env,
class: &Class,
cw721_admin: Option<String>,
) -> StdResult<Binary> {
fn init_msg(&self, deps: Deps, env: &Env, class: &Class) -> StdResult<Binary> {
let cw721_creator = CW721_CREATOR.load(deps.storage)?.map(|a| a.to_string());
// use ics721 creator for withdraw address
let ContractInfoResponse { creator, .. } = deps
.querier
Expand All @@ -643,7 +665,7 @@ where
name: class.id.clone().into(),
symbol: class.id.clone().into(),
minter: Some(env.contract.address.to_string()),
creator: cw721_admin,
creator: cw721_creator,
collection_info_extension: None,
withdraw_address: Some(creator),
};
Expand Down Expand Up @@ -781,6 +803,7 @@ where
outgoing_proxy,
cw721_base_code_id,
cw721_admin,
cw721_creator,
contract_addr_length,
} => {
// disables incoming proxy if none is provided!
Expand All @@ -805,13 +828,22 @@ where
}
if let Some(cw721_admin) = cw721_admin.clone() {
if cw721_admin.is_empty() {
ADMIN_USED_FOR_CW721.save(deps.storage, &None)?;
CW721_ADMIN.save(deps.storage, &None)?;
} else {
ADMIN_USED_FOR_CW721
CW721_ADMIN
.save(deps.storage, &Some(deps.api.addr_validate(&cw721_admin)?))?;
}
}

if let Some(cw721_creator) = cw721_creator.clone() {
if cw721_creator.is_empty() {
CW721_CREATOR.save(deps.storage, &None)?;
} else {
CW721_CREATOR
.save(deps.storage, &Some(deps.api.addr_validate(&cw721_creator)?))?;
}
}

if let Some(contract_addr_length) = contract_addr_length {
CONTRACT_ADDR_LENGTH.save(deps.storage, &contract_addr_length)?;
} else {
Expand Down Expand Up @@ -846,6 +878,19 @@ where
},
),
)
.add_attribute(
"cw721_creator",
cw721_creator.map_or_else(
|| "none".to_string(),
|or| {
if or.is_empty() {
"none".to_string()
} else {
or
}
},
),
)
.add_attribute(
"contract_addr_length",
contract_addr_length
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 creator address for instantiating new cw721 contracts. In case of None, sender (=ics721) is used.
pub cw721_creator: 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>,
}
Expand Down Expand Up @@ -172,6 +174,10 @@ pub enum QueryMsg {
#[returns(Option<Option<::cosmwasm_std::Addr>>)]
Cw721Admin {},

/// Gets the creators address for instantiating new cw721 contracts. In case of None, sender (creator) is sender.
#[returns(Option<Option<::cosmwasm_std::Addr>>)]
Cw721Creator {},

/// Gets the contract address length being used for instantiate2. In case of None, default length is 32 (standard in cosmwasm).
#[returns(Option<u32>)]
ContractAddrLength {},
Expand Down Expand Up @@ -226,6 +232,8 @@ 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 creator address for instantiating new cw721 contracts. In case of "", None is set, in that case sender (ics721) is creator.
cw721_creator: 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>,
},
Expand Down
12 changes: 6 additions & 6 deletions packages/ics721/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ use crate::{
helpers::get_instantiate2_address,
msg::QueryMsg,
state::{
UniversalAllNftInfoResponse, ADMIN_USED_FOR_CW721, 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,
UniversalAllNftInfoResponse, CLASS_ID_AND_NFT_CONTRACT_INFO, CLASS_ID_TO_CLASS,
CONTRACT_ADDR_LENGTH, CW721_ADMIN, CW721_CODE_ID, CW721_CREATOR,
INCOMING_CLASS_TOKEN_TO_CHANNEL, INCOMING_PROXY, OUTGOING_CLASS_TOKEN_TO_CHANNEL,
OUTGOING_PROXY, PO, TOKEN_METADATA,
},
ContractError,
};
Expand Down Expand Up @@ -49,9 +50,8 @@ pub trait Ics721Query {
QueryMsg::OutgoingProxy {} => Ok(to_json_binary(&OUTGOING_PROXY.load(deps.storage)?)?),
QueryMsg::IncomingProxy {} => Ok(to_json_binary(&INCOMING_PROXY.load(deps.storage)?)?),
QueryMsg::Cw721CodeId {} => Ok(to_json_binary(&query_cw721_code_id(deps)?)?),
QueryMsg::Cw721Admin {} => {
Ok(to_json_binary(&ADMIN_USED_FOR_CW721.load(deps.storage)?)?)
}
QueryMsg::Cw721Admin {} => Ok(to_json_binary(&CW721_ADMIN.load(deps.storage)?)?),
QueryMsg::Cw721Creator {} => Ok(to_json_binary(&CW721_CREATOR.load(deps.storage)?)?),
QueryMsg::ContractAddrLength {} => Ok(to_json_binary(
&CONTRACT_ADDR_LENGTH.may_load(deps.storage)?,
)?),
Expand Down
Loading

0 comments on commit 4321558

Please sign in to comment.