通用 NFT 是完全互操作的 ERC-721 代币,可在任意已连接链上铸造与转移,无需包装或跨链桥。每个 NFT 拥有跨链保持一致的持久 Token ID,元数据显示在跨链转移中始终保留。这为跨链游戏、市场与身份等场景带来真正的链无关所有权与交互体验。
ZetaChain 上的通用 NFT 基于标准的 OpenZeppelin ERC-721 (opens in a new tab) 实现,并采用 UUPS 可升级 (opens in a new tab) 代理模式,使开发者能够在保证安全的前提下扩展与升级 NFT 逻辑。
方案一:创建新的通用 NFT
新建通用 NFT 项目:
npx zetachain@latest new --project nft安装依赖:
cd nft
yarn
forge soldeer update编译合约:
forge build方案二:升级现有 ERC-721 项目
你可以在现有的 ERC-721 项目中集成通用 NFT 能力,只需安装官方标准合约包:
yarn add @zetachain/standard-contracts随后参考 示例实现 (opens in a new tab),按照注释加入专为通用 NFT 设计的 ZetaChain 集成逻辑。
这样即可在 ZetaChain 与所有已连接的 EVM 链上支持跨链铸造、转移与持久 Token ID。
部署到测试网
RPC_ETHEREUM=$(zetachain q chains show --chain-id 11155111 -f rpc)
RPC_BASE=$(zetachain q chains show --chain-id 84532 -f rpc)
RPC_ZETACHAIN=$(zetachain q chains show --chain-id 7001 -f rpc)
ZRC20_ETHEREUM=$(zetachain q tokens show -s ETH.ETHSEP -f zrc20)
ZRC20_BASE=$(zetachain q tokens show -s ETH.BASESEP -f zrc20)
GATEWAY_ETHEREUM=0x0c487a766110c85d301d96e33579c5b317fa4995
GATEWAY_BASE=0x0c487a766110c85d301d96e33579c5b317fa4995
GATEWAY_ZETACHAIN=0x6c533f7fe93fae114d0954697069df33c9b74fd7
GAS_LIMIT=1000000PRIVATE_KEY=...在 ZetaChain、Base 与 Ethereum 上部署合约。
NFT_ZETACHAIN=$(npx tsx commands deploy \
--rpc $RPC_ZETACHAIN \
--private-key $PRIVATE_KEY \
--name ZetaChainUniversalNFT \
--gas-limit $GAS_LIMIT | jq -r .contractAddress) && echo $NFT_ZETACHAIN0x6335bAB2eF31B79eE01dCFDB656a1eEf5ACd0840NFT_BASE=$(npx tsx commands deploy \
--rpc $RPC_BASE \
--private-key $PRIVATE_KEY \
--name EVMUniversalNFT \
--gateway $GATEWAY_BASE \
--gas-limit $GAS_LIMIT | jq -r .contractAddress) && echo $NFT_BASE0xB7c73Ee9B4E65458C972d64bbfAe653d0E6F389ANFT_ETHEREUM=$(npx tsx commands deploy \
--rpc $RPC_ETHEREUM \
--private-key $PRIVATE_KEY \
--name EVMUniversalNFT \
--gateway $GATEWAY_ETHEREUM \
--gas-limit $GAS_LIMIT | jq -r .contractAddress) && echo $NFT_ETHEREUM0x166d406a3049C04bF884a4C8cfe99c5bdCebC928连接合约
部署完成后,需要将各合约互信,使其能进行跨链通信。在 ZetaChain 上调用 setConnected,按链对应的 ZRC-20 Gas 代币注册 Connected 合约:
cast send $NFT_ZETACHAIN 'setConnected(address,bytes)' $ZRC20_BASE $NFT_BASE --rpc-url $RPC_ZETACHAIN --private-key $PRIVATE_KEYcast send $NFT_ZETACHAIN 'setConnected(address,bytes)' $ZRC20_ETHEREUM $NFT_ETHEREUM --rpc-url $RPC_ZETACHAIN --private-key $PRIVATE_KEY随后在每条已连接链上,调用 setUniversal 将 Universal 合约地址指回 ZetaChain:
cast send $NFT_BASE 'setUniversal(address)' $NFT_ZETACHAIN --rpc-url $RPC_BASE --private-key $PRIVATE_KEYcast send $NFT_ETHEREUM 'setUniversal(address)' $NFT_ZETACHAIN --rpc-url $RPC_ETHEREUM --private-key $PRIVATE_KEY这样即可确保只有经过授权的合约可以跨链发送与接收 NFT。
在 ZetaChain 铸造
TOKEN_ID=$(npx tsx commands mint \
--rpc $RPC_ZETACHAIN \
--private-key $PRIVATE_KEY \
--contract $NFT_ZETACHAIN \
--token-uri https://example.com/nft/metadata/1 | jq -r .tokenId) && echo $TOKEN_ID从 ZetaChain 转移至 Base
将该 NFT 从 ZetaChain 转移到 Base。Gas 金额(以 ZETA 指定)为估算值,剩余部分会退回用户。
使用 ZRC-20 Base ETH 作为目标地址,用于指明目标链。
npx tsx commands transfer \
--rpc $RPC_ZETACHAIN \
--private-key $PRIVATE_KEY \
--contract $NFT_ZETACHAIN \
--token-id $TOKEN_ID \
--destination $ZRC20_BASE \
--gas-amount 5 | jq -r .transferTransactionHash0xc1d363c8fddd21add48580c52550248f969a9a3b65d1377440cefe7fa8631db8zetachain q cctx --hash 0xc1d363c8fddd21add48580c52550248f969a9a3b65d1377440cefe7fa8631db87001 → 84532 ✅ OutboundMined
CCTX: 0x8066aaf467afb79d5c969b3389f958d566637ad690410b7538706d20d6eeceac
Tx Hash: 0xc1d363c8fddd21add48580c52550248f969a9a3b65d1377440cefe7fa8631db8 (on chain 7001)
Tx Hash: 0xe2c966b67fdc6759669cebc021466c408449f5c2c19954ffdb6e73d714ec29bc (on chain 84532)
Sender: 0x6335bAB2eF31B79eE01dCFDB656a1eEf5ACd0840
Receiver: 0xB7c73Ee9B4E65458C972d64bbfAe653d0E6F389A
Message: 0000000000000000000000004955a3f38ff86ae92a914445099caa8ea2b9ba32000000000000000000000000a6ca386bc8dc2baad9c67208f0129de2244bda1b00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004955a3f38ff86ae92a914445099caa8ea2b9ba320000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000002268747470733a2f2f6578616d706c652e636f6d2f6e66742f6d657461646174612f310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000从 Base 转移至 Ethereum
再将 NFT 从 Base 转移到 Ethereum。Token ID 保持不变。
npx tsx commands transfer \
--rpc $RPC_BASE \
--private-key $PRIVATE_KEY \
--contract $NFT_BASE \
--token-id $TOKEN_ID \
--destination $ZRC20_ETHEREUM \
--gas-amount 0.05 | jq -r .transferTransactionHash0x4aa957b2678232fb3f09557e8fcee22d5503272b6d6b8001677f32cbcdfa30dczetachain q cctx --hash 0x4aa957b2678232fb3f09557e8fcee22d5503272b6d6b8001677f32cbcdfa30dc84532 → 7001 ✅ OutboundMined
CCTX: 0xa54aea97073e6f76bf28c46290b0544b80aa1e85702284aacbedf03d5f59c322
Tx Hash: 0x4aa957b2678232fb3f09557e8fcee22d5503272b6d6b8001677f32cbcdfa30dc (on chain 84532)
Tx Hash: 0xe8d8432917cc0cb98f60285c711608003859924f3dc962c648db23232a36dcbb (on chain 7001)
Sender: 0xB7c73Ee9B4E65458C972d64bbfAe653d0E6F389A
Receiver: 0x6335bAB2eF31B79eE01dCFDB656a1eEf5ACd0840
Message: 00000000000000000000000005ba149a7bd6dc1f937fa9046a9e05c05f3b18b00000000000000000000000004955a3f38ff86ae92a914445099caa8ea2b9ba32000000000000000000000000a6ca386bc8dc2baad9c67208f0129de2244bda1b00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000004955a3f38ff86ae92a914445099caa8ea2b9ba320000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000002268747470733a2f2f6578616d706c652e636f6d2f6e66742f6d657461646174612f310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Amount: 50000000000000000 Gas tokens
7001 → 11155111 ✅ OutboundMined
CCTX: 0x34656cbd3210f3e33edb6d261bfdbc800476baa85f40fc15b75f934efbbd30c9
Tx Hash: 0xa54aea97073e6f76bf28c46290b0544b80aa1e85702284aacbedf03d5f59c322 (on chain 7001)
Tx Hash: 0xe7c0d400bd94e5c84cb44752d1e9e05e05f73f0433f6e915e77cc7fdde47d8fd (on chain 11155111)
Sender: 0x6335bAB2eF31B79eE01dCFDB656a1eEf5ACd0840
Receiver: 0x166d406a3049C04bF884a4C8cfe99c5bdCebC928
Message: 0000000000000000000000004955a3f38ff86ae92a914445099caa8ea2b9ba32000000000000000000000000a6ca386bc8dc2baad9c67208f0129de2244bda1b00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000e22dfad4b38420000000000000000000000004955a3f38ff86ae92a914445099caa8ea2b9ba320000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000002268747470733a2f2f6578616d706c652e636f6d2f6e66742f6d657461646174612f310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Amount: 3978993754388546 Gas tokens源码
https://github.com/zeta-chain/example-contracts/tree/main/examples/nft (opens in a new tab)