This section describes how to transfer NFTs between different chains. For NFT basic operations, please refer to this doc.
It is important to note that after an NFT has been transfered from its origin chain, the Class ID will change. According to the ICS 721 spec: "An ICS-721 token class is represented in the form {ics721Port}/{ics721Channel}/{classId}, where ics721Port and ics721Channel identify the channel on the current chain from which the tokens arrived.". This can also be thought of as the IBC trace of the token. To learn more about how this changes as an NFT makes multiple hops, see the ICS 721 spec.
As this IBC trace can be unpractical to use, you will see that in certain cases the class is simply represented in the form of ibc/<class-hash>
where <class-hash>
is the hash of the IBC trace. This makes the representation shorter and easier to use.
For the rest of this document we shall refer to the ibc trace representation as <nft-transfer-trace>
and the class hash (without the leading ibc/
) as <class-hash>
As an example, if you had an NFT class with the ID "testclass01" on IRISnet and sent an NFT from it to OmniFlix on port nft-transfer
and channel channel-1
, on OmniFlix the destination port would be nft-transfer
and channel channel-25
. This, in turn, would make <nft-transfer-trace>
be nft-transfer/channel-25/testclass01
.
Another example, if we with the same NFT class sent an NFT to Stargaze from port nft-transfer
and channel channel-22
, on Stargaze the destination port would be wasm.stars1ve46fjrhcrum94c7d8yc2wsdz8cpuw73503e8qn9r44spr6dw0lsvmvtqh
and the channel channel-207
. In this case, the <nft-transfer-trace>
would be wasm.stars1ve46fjrhcrum94c7d8yc2wsdz8cpuw73503e8qn9r44spr6dw0lsvmvtqh/channel-207/testclass01
.
IRISnet, Uptick and OmniFlix use bianjieai/nft-transfer to implement Interchain NFT functionality. These chains share the same instruction in their clients.
Note, whether it is the original chain or the target chain, the portID of cross-chain transfer nft is fixed nft-transfer
For cross-chain transfer nft, please execute the following command:
# `simd` here refers to `iris`, `uptickd` and `omniflixhubd`.
simd tx nft-transfer transfer \
<src-chain-port> \
<src-chain-channel> \
<dst-chain-receiver> \
<classID> \
<nftID>
As mentioned earlier, the NFT class ID changes as you transfer the NFT.
You will first have to find the <class-hash>
using the following command:
simd query nft-transfer class-hash <nft-transfer-trace>
simd
in this case refers to the binary of the destination chain.
(To see how to figure out the <nft-transfer-trace>
see Class representation after IBC transfer)
With the newly collected <class-hash>
in hand, you can query your collection and use the following form as your Class ID/Denom ID: ibc/<class-hash>
.
IRISnet example:
iris query nft colleciton ibc/<class-hash>
OmniFlix example:
omniflixhubd query onft collection ibc/<class-hash>
Uptick example:
uptick query collection collection ibc/<class-hash>
If you want to query the original information of cross-chain nft, you can use the following command
simd query nft-transfer class-trace <class-hash> [flags]
When the nft cross-chain transfer to the destination chain is successful, the nft on the original chain will be hosted at the specified system account address, you can use the following command to query the system account address
simd query nft-transfer escrow-address [port] [src-channel-id]
Stargaze and Juno use public-awesome/ics721 to implement ICS 721 speicification in CosmWasm.
# `simd` here refers to `stard` and `junod`.*
simd tx wasm execute <cw-721-addr> \
{"send_nft": {"contract": "<ics-721-addr>", "token_id": "<token-id>", "msg": \ "<basa64_encoded_msg>"}}
In which the <base64_encoded_msg>
should be the following JSON string encoded with base64.
{
"receiver": "<reciver-addr>",
"channel_id": "<src-channel-id>",
"timeout": {
"block": {
"revision": <chain-revision>,
"height": <timeout-height>
}
}
}
As mentioned earlier, the NFT class ID changes as you transfer the NFT.
Query the CW-721 contract address of the arrived NFT on this chain:
simd q wasm contract-state smart <ics-721-addr> '{"nft_contract": {"class_id" : "<nft-transfer-trace>"}}'
The output from this command is the <cw-721-addr>
(notice the "cw", not "ics" here).
<ics-721-addr>
is the contract that was in the destination port when you sent the NFT. For instance, when transfering from IRISnet to Stargaze, the port on the Stargaze side is wasm.stars1ve46fjrhcrum94c7d8yc2wsdz8cpuw73503e8qn9r44spr6dw0lsvmvtqh
. The address after wasm.
is the <ics-721-addr>
.
(To see how to figure out the <nft-transfer-trace>
see Class representation after IBC transfer)
Query the NFT info of this CW-721 contract address:
simd q wasm contract-state smart <cw-721-addr> '{"all_nft_info":{"token_id": "<token-id>"}}'
The <token-id>
in this case is the actual, original, token ID of the NFT that you sent over.
simd q wasm contract-state smart <cw-721-addr> '{"num_tokens":{}}'