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

Update README with quick start, lint tests #72

Merged
merged 3 commits into from
Nov 17, 2023
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
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,26 @@ This implementation
rate limiting of outgoing NFTs;
4. is well tested.

To enable ICS721 contracts to function correctly, the app chain needs to have at least `wasmd v0.31.0` installed, with the `cosmwasm_1_2` feature enabled. This requirement arises from the fact that the ICS721 contract uses `instantiate2` for creating predicted cw721 addresses. For more detailed information, please refer to the [CHANGELOG.md](https://github.com/CosmWasm/wasmd/blob/main/CHANGELOG.md#v0310-2023-03-13) in the `wasmd` repository.

## Getting Started

Follow these steps to set up contracts and channels:

1. Clone the [`cw-ics721`](https://github.com/public-awesome/cw-ics721) repository.
2. Build the contracts using the [`ts-relayer-tests/build.sh`](https://github.com/public-awesome/cw-ics721/blob/main/ts-relayer-tests/build.sh) script.
3. Upload and instantiate the `ics721-base` contract (refer to the [CosmWasm book](https://book.cosmwasm.com/) for details) on at least 2 CosmWasm-based app chains.
4. Set up relayers, such as [Cosmos/IBC Go](https://github.com/cosmos/relayer/) or [Hermes](https://hermes.informal.systems/).

To gain a better understanding of how ICS721 (interchain) workflows function, consider running the integration tests. You can find more information in the [ts-relayer-tests/README.md](./ts-relayer-tests/README.md) file. The integration tests perform the following actions:

- Set up 2 local chains.
- Upload interchain contracts.
- Create an IBC channel between both contracts.
- Create a collection contract (cw721).
- Mint an NFT.
- Transfer the NFT from one chain to another.

## From a thousand feet up

This contract deals in debt-vouchers.
Expand Down
64 changes: 30 additions & 34 deletions contracts/sg-ics721/src/testing/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,27 @@ const BECH32_PREFIX_HRP: &str = "stars";
const NFT_OWNER_TARGET_CHAIN: &str = "nft-owner-target-chain";
const ICS721_ADMIN_AND_PAUSER: &str = "ics721-pauser";

type MockRouter = Router<
BankKeeper,
FailingModule<Empty, Empty, Empty>,
WasmKeeper<Empty, Empty>,
StakeKeeper,
DistributionKeeper,
IbcAcceptingModule,
FailingModule<GovMsg, Empty, Empty>,
>;

type MockApp = App<
BankKeeper,
MockApiBech32,
MemoryStorage,
FailingModule<Empty, Empty, Empty>,
WasmKeeper<Empty, Empty>,
StakeKeeper,
DistributionKeeper,
IbcAcceptingModule,
>;

// copy of cosmwasm_std::ContractInfoResponse (marked as non-exhaustive)
#[cw_serde]
pub struct ContractInfoResponse {
Expand Down Expand Up @@ -82,20 +103,7 @@ fn migrate(deps: DepsMut, env: Env, msg: MigrateMsg) -> Result<Response, Contrac
SgIcs721Contract::default().migrate(deps, env, msg)
}

fn no_init(
_router: &mut Router<
BankKeeper,
FailingModule<Empty, Empty, Empty>,
WasmKeeper<Empty, Empty>,
StakeKeeper,
DistributionKeeper,
IbcAcceptingModule,
FailingModule<GovMsg, Empty, Empty>,
>,
_api: &dyn Api,
_storage: &mut dyn Storage,
) {
}
fn no_init(_router: &mut MockRouter, _api: &dyn Api, _storage: &mut dyn Storage) {}

#[derive(Default)]
pub struct MockAddressGenerator;
Expand Down Expand Up @@ -136,13 +144,12 @@ impl MockAddressGenerator {
key.extend_from_slice(&code_id.to_be_bytes());
key.extend_from_slice(&instance_id.to_be_bytes());
let module = Sha256::digest("module".as_bytes());
let result = Sha256::new()
Sha256::new()
.chain(module)
.chain(key)
.finalize()
.to_vec()
.into();
return result;
.into()
}
}
pub struct MockApiBech32 {
Expand Down Expand Up @@ -250,16 +257,7 @@ pub struct CustomClassData {
}

struct Test {
app: App<
BankKeeper,
MockApiBech32,
MemoryStorage,
FailingModule<Empty, Empty, Empty>,
WasmKeeper<Empty, Empty>,
StakeKeeper,
DistributionKeeper,
IbcAcceptingModule,
>,
app: MockApp,
// origin cw721 contract on source chain for interchain transfers to other target chains
source_cw721_owner: Addr,
source_cw721_id: u64,
Expand Down Expand Up @@ -313,13 +311,13 @@ impl Test {
proxy: proxy.clone(),
pauser: admin_and_pauser
.clone()
.and_then(|p| Some(app.api().addr_make(&p).to_string())),
.map(|p| app.api().addr_make(&p).to_string()),
},
&[],
"sg-ics721",
admin_and_pauser
.clone()
.and_then(|p| Some(app.api().addr_make(&p).to_string())),
.map(|p| app.api().addr_make(&p).to_string()),
)
.unwrap();

Expand Down Expand Up @@ -480,17 +478,15 @@ fn sg721_base_contract() -> Box<dyn Contract<Empty>> {
info: MessageInfo,
msg: sg721::ExecuteMsg<Option<Empty>, Empty>,
) -> Result<Response, sg721_base::ContractError> {
sg721_base::entry::execute(deps, env, info, msg)
.and_then(|_| Ok::<Response, sg721_base::ContractError>(Response::default()))
sg721_base::entry::execute(deps, env, info, msg).map(|_| Response::default())
}
fn instantiate_fn(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: sg721::InstantiateMsg,
) -> Result<Response, sg721_base::ContractError> {
sg721_base::entry::instantiate(deps, env, info, msg)
.and_then(|_| Ok::<Response, sg721_base::ContractError>(Response::default()))
sg721_base::entry::instantiate(deps, env, info, msg).map(|_| Response::default())
}
let contract = ContractWrapper::new(exececute_fn, instantiate_fn, sg721_base::entry::query);
Box::new(contract)
Expand Down Expand Up @@ -1773,7 +1769,7 @@ fn test_receive_nft() {
let expected_contract_info: cosmwasm_std::ContractInfoResponse =
// workaround using from_json/to_json_binary since ContractInfoResponse is non-exhaustive, can't be created directly
from_json(
&to_json_binary(&ContractInfoResponse {
to_json_binary(&ContractInfoResponse {
code_id: test.source_cw721_id,
creator: test.source_cw721_owner.to_string(),
admin: None,
Expand Down
2 changes: 1 addition & 1 deletion packages/ics721/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ mod tests {
},
};
let start = to_json_binary(&start).unwrap();
let end: UniversalAllNftInfoResponse = from_json(&start).unwrap();
let end: UniversalAllNftInfoResponse = from_json(start).unwrap();
assert_eq!(end.access.owner, "foo".to_string());
assert_eq!(end.access.approvals, vec![]);
assert_eq!(end.info.token_uri, None);
Expand Down
7 changes: 2 additions & 5 deletions packages/ics721/src/testing/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ fn mock_querier_v016(query: &WasmQuery) -> QuerierResult {
fn test_receive_nft() {
// test case: receive nft from cw721-base
let expected_contract_info: cosmwasm_std::ContractInfoResponse = from_json(
&to_json_binary(&ContractInfoResponse {
to_json_binary(&ContractInfoResponse {
code_id: 0,
creator: "creator".to_string(),
admin: None,
Expand Down Expand Up @@ -253,7 +253,6 @@ fn test_receive_nft() {
// check outgoing classID and tokenID
let keys = OUTGOING_CLASS_TOKEN_TO_CHANNEL
.keys(deps.as_mut().storage, None, None, Order::Ascending)
.into_iter()
.collect::<StdResult<Vec<(String, String)>>>()
.unwrap();
assert_eq!(keys, [(NFT_ADDR.to_string(), token_id.to_string())]);
Expand Down Expand Up @@ -335,7 +334,6 @@ fn test_receive_nft() {
// check outgoing classID and tokenID
let keys = OUTGOING_CLASS_TOKEN_TO_CHANNEL
.keys(deps.as_mut().storage, None, None, Order::Ascending)
.into_iter()
.collect::<StdResult<Vec<(String, String)>>>()
.unwrap();
assert_eq!(keys, [(NFT_ADDR.to_string(), token_id.to_string())]);
Expand Down Expand Up @@ -408,7 +406,6 @@ fn test_receive_nft() {
// check outgoing classID and tokenID
let keys = OUTGOING_CLASS_TOKEN_TO_CHANNEL
.keys(deps.as_mut().storage, None, None, Order::Ascending)
.into_iter()
.collect::<StdResult<Vec<(String, String)>>>()
.unwrap();
assert_eq!(keys, [(NFT_ADDR.to_string(), token_id.to_string())]);
Expand Down Expand Up @@ -456,7 +453,7 @@ fn test_receive_sets_uri() {
.unwrap();
assert_eq!(class.uri, None);
let expected_contract_info: cosmwasm_std::ContractInfoResponse = from_json(
&to_json_binary(&ContractInfoResponse {
to_json_binary(&ContractInfoResponse {
code_id: 0,
creator: "creator".to_string(),
admin: None,
Expand Down
1 change: 0 additions & 1 deletion packages/ics721/src/testing/ibc_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,6 @@ fn test_ibc_packet_receive() {
// check incoming classID and tokenID
let keys = INCOMING_CLASS_TOKEN_TO_CHANNEL
.keys(deps.as_mut().storage, None, None, Order::Ascending)
.into_iter()
.collect::<StdResult<Vec<(String, String)>>>()
.unwrap();
let class_id = format!(
Expand Down
60 changes: 29 additions & 31 deletions packages/ics721/src/testing/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,27 @@ const BECH32_PREFIX_HRP: &str = "stars";
const NFT_OWNER_TARGET_CHAIN: &str = "nft-owner-target-chain";
const ICS721_ADMIN_AND_PAUSER: &str = "ics721-pauser";

type MockRouter = Router<
BankKeeper,
FailingModule<Empty, Empty, Empty>,
WasmKeeper<Empty, Empty>,
StakeKeeper,
DistributionKeeper,
IbcAcceptingModule,
FailingModule<GovMsg, Empty, Empty>,
>;

type MockApp = App<
BankKeeper,
MockApiBech32,
MemoryStorage,
FailingModule<Empty, Empty, Empty>,
WasmKeeper<Empty, Empty>,
StakeKeeper,
DistributionKeeper,
IbcAcceptingModule,
>;

// copy of cosmwasm_std::ContractInfoResponse (marked as non-exhaustive)
#[cw_serde]
pub struct ContractInfoResponse {
Expand Down Expand Up @@ -82,20 +103,7 @@ fn migrate(deps: DepsMut, env: Env, msg: MigrateMsg) -> Result<Response, Contrac
Ics721Contract::default().migrate(deps, env, msg)
}

fn no_init(
_router: &mut Router<
BankKeeper,
FailingModule<Empty, Empty, Empty>,
WasmKeeper<Empty, Empty>,
StakeKeeper,
DistributionKeeper,
IbcAcceptingModule,
FailingModule<GovMsg, Empty, Empty>,
>,
_api: &dyn Api,
_storage: &mut dyn Storage,
) {
}
fn no_init(_router: &mut MockRouter, _api: &dyn Api, _storage: &mut dyn Storage) {}

#[derive(Default)]
pub struct MockAddressGenerator;
Expand Down Expand Up @@ -136,13 +144,12 @@ impl MockAddressGenerator {
key.extend_from_slice(&code_id.to_be_bytes());
key.extend_from_slice(&instance_id.to_be_bytes());
let module = Sha256::digest("module".as_bytes());
let result = Sha256::new()
Sha256::new()
.chain(module)
.chain(key)
.finalize()
.to_vec()
.into();
return result;
.into()
}
}
pub struct MockApiBech32 {
Expand Down Expand Up @@ -250,16 +257,7 @@ pub struct CustomClassData {
}

struct Test {
app: App<
BankKeeper,
MockApiBech32,
MemoryStorage,
FailingModule<Empty, Empty, Empty>,
WasmKeeper<Empty, Empty>,
StakeKeeper,
DistributionKeeper,
IbcAcceptingModule,
>,
app: MockApp,
// origin cw721 contract on source chain for interchain transfers to other target chains
source_cw721_owner: Addr,
source_cw721_id: u64,
Expand Down Expand Up @@ -313,13 +311,13 @@ impl Test {
proxy: proxy.clone(),
pauser: admin_and_pauser
.clone()
.and_then(|p| Some(app.api().addr_make(&p).to_string())),
.map(|p| app.api().addr_make(&p).to_string()),
},
&[],
"ics721-base",
admin_and_pauser
.clone()
.and_then(|p| Some(app.api().addr_make(&p).to_string())),
.map(|p| app.api().addr_make(&p).to_string()),
)
.unwrap();

Expand Down Expand Up @@ -1599,7 +1597,7 @@ fn test_receive_nft() {
let expected_contract_info: cosmwasm_std::ContractInfoResponse =
// workaround using from_json/to_json_binary since ContractInfoResponse is non-exhaustive, can't be created directly
from_json(
&to_json_binary(&ContractInfoResponse {
to_json_binary(&ContractInfoResponse {
code_id: test.source_cw721_id,
creator: test.source_cw721_owner.to_string(),
admin: None,
Expand Down Expand Up @@ -1667,7 +1665,7 @@ fn test_receive_nft() {
let expected_contract_info: cosmwasm_std::ContractInfoResponse =
// workaround using from_json/to_json_binary since ContractInfoResponse is non-exhaustive, can't be created directly
from_json(
&to_json_binary(&ContractInfoResponse {
to_json_binary(&ContractInfoResponse {
code_id: test.source_cw721_id,
creator: test.source_cw721_owner.to_string(),
admin: None,
Expand Down