A cross-chain NFT dApp built on ZetaChain that enables users to mint NFTs once and transfer them across multiple blockchain networks seamlessly.
- Universal NFT Minting: Mint AI NFTs with IPFS metadata storage
- Cross-Chain Transfers: Send NFTs between connected chains (Goerli, Base, ZetaChain)
- Universal App Lifecycle: Implements
onCall,onRevert, andonAbortfor robust cross-chain messaging - Automatic Mirroring: NFTs maintain the same tokenId and metadata across chains
- Transaction Tracking: Real-time transaction status and logging
- UniversalNFT.sol: ERC721 token with ZetaChain Universal NFT support
- UniversalNFTBridge.sol: Handles cross-chain transfers with lifecycle functions
- IUniversalApp.sol: Interface for Universal App lifecycle functions
- React 18 with TypeScript
- Ethers.js v6 for blockchain interactions
- Web3Modal for wallet connection
- Tailwind CSS for styling
- Node.js 18+
- MetaMask or compatible Web3 wallet
- ZetaChain testnet funds (get from faucet)
-
Clone the repository ```bash git clone cd zetachain-universal-nft ```
-
Install dependencies ```bash npm install ```
-
Configure environment variables ```bash cp .env.example .env.local
```
-
Compile smart contracts ```bash npm run compile ```
-
Deploy to ZetaChain Testnet ```bash npm run deploy:testnet ```
-
Update environment variables
- Copy the deployed contract addresses to
.env.local - Set
NEXT_PUBLIC_NFT_ADDRESSandNEXT_PUBLIC_BRIDGE_ADDRESS
- Copy the deployed contract addresses to
-
Start the frontend ```bash npm run dev ```
Open http://localhost:3000 in your browser.
- Connect your wallet
- Go to the "Mint NFT" tab
- Enter a metadata URI (IPFS or HTTP)
- Click "Mint NFT"
- Confirm the transaction in MetaMask
- Connect your wallet
- Go to the "Bridge NFT" tab
- Enter the token ID of the NFT to bridge
- Select the destination chain
- Enter the recipient address
- Click "Bridge NFT"
- Confirm the transaction
| Network | Chain ID | RPC |
|---|---|---|
| ZetaChain Testnet | 7001 | https://zetachain-testnet.g.alchemy.com/v2/demo |
| Goerli | 5 | https://goerli.infura.io/v3/YOUR_KEY |
| Base Testnet | 84531 | https://base-testnet.g.alchemy.com/v2/demo |
ZetaChain Testnet:
- Network Name: ZetaChain Testnet
- RPC URL: https://zetachain-testnet.g.alchemy.com/v2/demo
- Chain ID: 7001
- Currency Symbol: ZETA
- Block Explorer: https://zetachain-testnet.blockscout.com
```bash npm run test ```
- Connect wallet successfully
- Mint NFT with valid metadata URI
- View minted NFT in transaction log
- Bridge NFT to another chain
- Verify NFT appears on destination chain
- Test error handling with invalid inputs
- Check transaction status updates
Triggered when a cross-chain message arrives from another chain. Mints the NFT on the destination chain.
Triggered when a cross-chain call fails. Restores the NFT to the original owner on the source chain.
Triggered when a cross-chain call cannot be reverted (insufficient funds). Sends the NFT to the abort address to prevent asset loss.
- Ensure you've deployed the contracts
- Update
.env.localwith the correct contract addresses
- Install MetaMask extension
- Ensure you're on a supported network
- Verify the destination chain is registered in the UniversalNFT contract
- Check that the connected contract address is correct
- Verify the IPFS URI is correct and accessible
- Use a public IPFS gateway if needed
- ZetaChain Documentation
- Universal Apps Guide
- Universal NFT Standard
- ZetaChain Faucet
- Ethers.js Documentation
MIT
For issues and questions:
- Check the ZetaChain Discord
- Review the troubleshooting section
- Open an issue on GitHub