Remix IDE: Creating Interactive NFTs with IPFS and Remix IDE
Learn how to create an interactive NFT with IPFS and Remix IDE.
Last updated
Learn how to create an interactive NFT with IPFS and Remix IDE.
Last updated
Remix Online IDE is a web browser-based Ethereum smart contract development and deployment tool.
Read below to learn how to create an interactive NFT with IPFS and Remix IDE.
Next to ‘Workspaces’, select the plus sign.
contract.sol
and insert the following content:// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract MyNFT0 is ERC721, ERC721URIStorage, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
constructor() ERC721("MyNFT0", "MNFT0") {}
function _baseURI() internal pure override returns (string memory) {
return "https://ipfs.filebase.io/ipfs/";
}
function supportsInterface(bytes4 interfaceId)
public view virtual override(ERC721)
returns (bool) {
return super.supportsInterface(interfaceId);
}
function mintNFT(address to, string memory uri) public onlyOwner {
_tokenIdCounter.increment();
uint256 tokenId = _tokenIdCounter.current();
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
// The following functions are overrides required by Solidity.
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
}
flip.js
with the following content:function flip () {
return true || false;
}
Select ‘Upload’, then select your flip.js
file and an image file you’d like to use for your NFT.
metadata.json
.In this file, insert the following content:
{
"title": "Interactive NFT",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Interactive NFT 1"
},
"description": {
"type": "string",
"description": "This is an interactive NFT."
},
"image": {
"type": "string",
"description": "IMAGE_IPFS_CID"
},
"js": {
"type": "string",
"description": "JS_IPFS_CID"
}
}
}
Replace the following values:
IMAGE_IPFS_CID
: The IPFS CID for your NFT’s image.
JS_IPFS_CID
: The IPFS CID for your flip.js file.
metadata.json
file to your Filebase bucket.Take note of the IPFS CID that is returned.
This will create a variety of files in the workspace’s file explorer.
Expand the ‘approve’ tab, then insert your cryptowallet address in the ‘to’ field and insert the IPFS CID of your metadata.json file in the ‘tokenId’ field. Then select ‘transact’.
flip.js
and metadata.json
files, create a new file called index.html
. Insert the following content into this file:<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Interactive NFT</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<div class="row">
<div class="col-md-2"></div>
<div class="col-md-8">
<center>
<div class="card" style="width: 18rem;">
<img id="imgSrc" src="..." class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">Interactive NFT</h5>
<p class="card-text">This is an interactive NFT.</p>
<button id="nameBtn" class="btn btn-primary">What is your name?</a>
<button id="storyBtn" class="btn btn-primary">What is your story?</a>
</div>
</div>
</center>
</div>
<div class="col-md-2"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>
<script type="text/javascript">
if (typeof window.ethereum !== 'undefined') {
console.log('MetaMask is installed!');
} else {
alert('Please install Metamask first.');
}
const web3 = new Web3(Web3.givenProvider);
let account = '';
async function connectMetamask() {
ethereum.request({ method: 'eth_requestAccounts' });
const accounts = await ethereum.request({ method: 'eth_requestAccounts' });
account = accounts[0];
}
connectMetamask();
const MyNFT0ABI = [
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "approved",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "Approval",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "ApprovalForAll",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "approve",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "string",
"name": "uri",
"type": "string"
}
],
"name": "mintNFT",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "previousOwner",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnershipTransferred",
"type": "event"
},
{
"inputs": [],
"name": "renounceOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "safeTransferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "safeTransferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "operator",
"type": "address"
},
{
"internalType": "bool",
"name": "approved",
"type": "bool"
}
],
"name": "setApprovalForAll",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "to",
"type": "address"
},
{
"indexed": true,
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "Transfer",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "from",
"type": "address"
},
{
"internalType": "address",
"name": "to",
"type": "address"
},
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "transferOwnership",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "getApproved",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"internalType": "address",
"name": "operator",
"type": "address"
}
],
"name": "isApprovedForAll",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "name",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "ownerOf",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes4",
"name": "interfaceId",
"type": "bytes4"
}
],
"name": "supportsInterface",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "symbol",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "tokenId",
"type": "uint256"
}
],
"name": "tokenURI",
"outputs": [
{
"internalType": "string",
"name": "",
"type": "string"
}
],
"stateMutability": "view",
"type": "function"
}
]
const MyNFT0ContractAddress = "CONTRACT_ADDRESS";
const MyNFT0Contract = new web3.eth.Contract(MyNFT0ABI, MyNFT0ContractAddress);
async function getResult(){
let result = await MyNFT0Contract.methods.tokenURI(2).call();
console.log(result);
fetch(result)
.then(response => response.json())
.then(data => {
console.log(data);
console.log(data.properties.image.description);
console.log(data.properties.js.description);
let imageHash = data.properties.image.description;
let jsCodeHash = data.properties.js.description;
let baseURL = 'https://ipfs.filebase.io/ipfs/';
fetch('http://127.0.0.1:8000/flip.js')
.then(response => response.text())
.then(data => {
eval(data);
console.log(flip());
})
})
}
getResult();
</script>
</body>
</html>
Replace the CONTRACT_ADDRESS
value with your smart contract’s address you copied previously.
python3 -m http.server
https://localhost:8000
and your interactive NFT should look like this: