NOTE: interchain contracts on testnets have rate limits disabled - so there is no need to WL collections and channels!
For ease-of-use checkout these testnet env files [here]((https://gist.github.com/taitruong):
- osmosis_testnet.env
- stargaze_testnet.env
- juno_testnet.env
- terra2_testnet.env
- aura_testnet.env
First create a collection for this contract: https://github.com/CosmWasm/cw-nfts/tree/main/contracts/cw721-base
$CLI tx wasm instantiate $CODE_ID_CW721 '{"name":"Ark Test", "symbol":"ark-test", "minter":"MINTER_ADDR"}' --from WALLET_KEY --label 'Ark Test' --admin WALLET_KEY --gas-prices $CLI_GAS_PRICES --gas $CLI_GAS --gas-adjustment $CLI_GAS_ADJUSTMENT -b $CLI_BROADCAST_MODE --yes --node $CHAIN_NODE --chain-id $CHAIN_ID --output $CLI_OUTPUT
Then mint a few NFTs:
$CLI tx wasm execute $CW721_ADDR '{"mint": {"token_id":"1", "owner":"OWNER_ADDR" , "token_uri": "ipfs://foo.bar"}}' --from $MINTER_ADDR --gas-prices $CLI_GAS_PRICES --gas $CLI_GAS --gas-adjustment $CLI_GAS_ADJUSTMENT -b $CLI_BROADCAST_MODE --node $CHAIN_NODE --chain-id $CHAIN_ID --yes --output json
NOTE: On Stargaze only contracts can instantiate sg721-base. You can use this for creating one: https://studio.publicawesome.dev/collections/create/
source osmosis_testnet.env
# query for all tokens
$CLI query wasm contract-state smart $ADDR_CW721_TEST '{"all_tokens":{"limit": 100}}' --chain-id $CHAIN_ID --node $CHAIN_NODE --output json
# make sure you are the owner. output: {"data":{"owner":"YOUR_WALLET_ADDY","approvals":[]}}
$CLI query wasm contract-state smart $ADDR_CW721_TEST '{"owner_of": {"token_id":"1"}}' --node $CHAIN_NODE --chain-id $CHAIN_ID
cosmwasm-based ICS721 contract uses an outgoing proxy, so NFTs are sent to the proxy - and not to ICS721.
Call send_nft
to proxy will trigger ics721 transfer. As part of send_nft
a msg is passed to ICS721:
# create ICS721 message with:
# - recipient of NFT on target chain (Osmosis)
# - source channel: Stargaze channel referencing ICS721 contracts/ports on both chains
# - timeout: expiration in case relayer doesnt relay on time
TIMESTAMP=`date -d "+30 minutes" +%s%N` # time in nano seconds, other options: "+1 day"
printf -v RAW_MSG '{
"receiver": "%s",
"channel_id": "%s",
"timeout": { "timestamp": "%s" } }' \
"$RECIPIENT" \
"$ICS721_CHANNEL_1_OSMOSIS_TO_STARGAZE" \
"$TIMESTAMP"
# Base64 encode msg
MSG=`echo "$RAW_MSG" | base64 | xargs | sed 's/ //g'` # xargs concats multiple lines into one (with spaces), sed removes spaces
# send nft msg for $TOKEN
printf -v EXECUTE_MSG '{"send_nft": {
"contract": "%s",
"token_id": "%s",
"msg": "%s"}}' \
"$ADDR_OUTGOING_PROXY" \
"$TOKEN" \
"$MSG"
# execute transfer
CMD="$CLI tx wasm execute '$ADDR_CW721_TEST' '$EXECUTE_MSG' \
--from "$MY_WALLET" \
--gas-prices "$CLI_GAS_PRICES" \
--gas "$CLI_GAS" \
--gas-adjustment "$CLI_GAS_ADJUSTMENT" \
-b "$CLI_BROADCAST_MODE" \
--chain-id $CHAIN_ID --node $CHAIN_NODE \
--yes"
eval $CMD
Once transfer is started. Relayer needs to pickup packets. These relayer configs can be used here:
rly vs hermes:
- rly doesnt need gRPC: on mainnet there are public gRPCs, on testnet it is not guaranteed
- hermes: allows relayer specific channels (
clear packet
)
# NOTE: no matter from what chain you transfer (e.g. osmosis -> stargaze or stargaze -> osmosis)
# relayers make sure all packets (receive/acknowledge)) are relayed.
# so like for `hermes clear packet --chain elgafar-1 ...` may start looking on Stargaze testnet (elgafar-1), but it will also relay packets on Osmosis side.
hermes --config ./relayer/hermes/testnet/config.toml clear packets --chain $CHAIN_ID --channel $ICS721_CHANNEL_1_STARGAZE_TO_OSMOSIS --port wasm.$ADDR_ICS721
# switch to osmosis and check whether NFT has been transferred and owned by recipient
source osmosis_testnet.env
# query for all tokens
$CLI query wasm contract-state smart $ADDR_CW721_TEST '{"all_tokens":{"limit": 100}}' --chain-id $CHAIN_ID --node $CHAIN_NODE --output json
# make sure you are the owner. output: {"data":{"owner":"YOUR_WALLET_ADDY","approvals":[]}}
$CLI query wasm contract-state smart $ADDR_CW721_TEST '{"owner_of": {"token_id":"1"}}' --node $CHAIN_NODE --chain-id $CHAIN_ID
For callbacks pls check README.md