This is a complete implementation of the ERC-721 non-fungible token standard for the Ethereum blockchain. This is an open source project build with Truffle framework.
Purpose of this implementation is to provide a good starting point for anyone who wants to use and develop non-fungible tokens on the Ethereum blockchain. Instead of re-implementing the ERC-721 yourself you can use this code which has gone through multiple audits and we hope it will be extensively used by the community in the future.
If you are looking for a more feature-rich and advanced ERC721 implementation, then check out the Xcert repository.
Since this is a Truffle project, you will find all tokens in contracts/tokens/
directory. There are multiple implementations and you can select between:
NFToken.sol
: This is the base ERC-721 token implementation (with the support for ERC-165).NFTokenEnumerable.sol
: This implements optional ERC-721 support for enumeration. It is useful if you want to know the total supply of tokens, to query a token by index, etc.NFTokenMetadata.sol
: This implements optional ERC-721 meta-data features for the token contract. It implements a token name, a symbol and a distinct URI pointing to a publicly exposed ERC-721 JSON metadata file.
Other files in the directory starting with ERC*.sol
are interfaces and define the respective standards.
- NodeJS 9.0+ recommended.
- Windows, Linux or Mac OS X.
Using Remix? This package uses NPM modules which are supported in the Remix Alpha version only. You can also use the npm run flatten
command to create a build/bundle.sol
file with all package contracts which you can manually copy and then paste into Remix editor.
This is an NPM module for Truffle framework. In order to use it as a dependency in your Javascript project, you must install it through the npm
command:
$ npm install @0xcert/ethereum-erc721
Clone the repository and install the required npm
dependencies:
$ git clone [email protected]:0xcert/ethereum-erc721.git
$ cd ethereum-erc721
$ npm install
Make sure that everything has been set up correctly:
$ npm run test
To interact with package's contracts within JavaScript code, you simply need to require that package's .json files:
const contract = require("@0xcert/ethereum-erc721/build/contracts/NFTokenEnumerable.json");
console.log(contract);
The easiest way to start is to create a new file under contracts/tokens/
(e.g. MyNFToken.sol
):
pragma solidity ^0.4.23;
import "../tokens/NFTokenMetadata.sol";
import "@0xcert/ethereum-utils/contracts/ownership/Ownable.sol";
contract MyNFToken is
NFTokenMetadata,
Ownable
{
constructor(
string _name,
string _symbol
)
public
{
nftName = _name;
nftSymbol = _symbol;
}
function mint(
address _owner,
uint256 _id
)
onlyOwner
external
{
super._mint(_owner, _id);
}
function burn(
address _owner,
uint256 _tokenId
)
onlyOwner
external
{
super._burn(_owner, _tokenId);
}
}
That's it. Let's compile the contract:
$ npm run compile
The easiest way to deploy it locally and start interacting with the contract (minting and transferring tokens) is to deploy it on your personal (local) blockchain using Ganache. Follow the steps in the Truffle documentation which are described here.
Next step is to deploy the contract on the testnet.
Requirements:
- geth
- Wallet with some ether.
Create a new file migrations/2_mytoken_migration.js
and put in:
const MyNFTokenContract = artifacts.require('./tokens/MyNFToken.sol');
module.exports = function(deployer) {
deployer.deploy(MyNFTokenContract, 'MyNFTokenTest', 'MYNFT');
};
Start geth
and sync your client with the testnet (can take a little bit):
$ geth console --testnet --light --rpc --rpcaddr "localhost" --rpcport "8545" --rpccorsdomain "*" --rpcapi="db,eth,net,web3,personal,web3"
Open another terminal and create a new account (your "test" account wallet):
$ geth --testnet account new
NOTE: In this example the wallet address is 0x9062dd79d7e4273889b234f6b0c840ca43280af60x9
(make sure you prepend the returned string with 0x
yourself). Your account address will be different! And don't forget the passphrase otherwise you won't be able to unlock your new account. Now, go and send some ether to it (you can get some here.
Open project's truffle.js
and add the following:
module.exports = {
networks: {
'ropsten': {
host: 'localhost',
port: 8545,
network_id: '3', // Ropsten ID 3
from: '0x9062dd79d7e4273889b234f6b0c840ca43280af60x9', // account address from which to deploy
gas: 4000000,
},
},
};
Next, let's unlock your account:
$ npm run console -- --network ropsten
truffle(ropsten)> web3.personal.unlockAccount("0x9062dd79d7e4273889b234f6b0c840ca43280af6", "<PASSWORD>", 1500)
At last, deploy the contract:
$ npm run migrate -- --network ropsten
You can now interact with the contract. First get the address of the deployed contract:
$ npm run networks
You can also check it on Ropsten etherscan. Then in the truffle console (second terminal):
> const { abi } = require('./build/contracts/MyNFToken.json');
> const account0 = '0x9062dd79d7e4273889b234f6b0c840ca43280af60x9'; // your unlocked account
> const account1 = '0x294a4c90900c0dae6ce8e3329a2b219a1f3d8c22'; // another account (you can create it)
> const MyNFTokenContract = web3.eth.contract(abi);
> const MyNFTokenInstance = MyNFTokenContract.at(<MyNFToken ADDRESS>);
> MyNFTokenInstance.symbol();
'MYNFT'
> MyNFTokenInstance.name();
'MyNFToken'
> MyNFTokenInstance.balanceOf(account0).toString();
'0' <-- we don't have any NFTokens yet
> MyNFTokenInstance.mint(account0, '1234', { from: account0 });
'0xd919e28be93d3a597fe8bf8516457f105d47836001dce3e22df7663dc1c5a6ed'
> MyNFTokenInstance.mint(account0, '5678', { from: account0 });
'0x964d082d88f7f4db91e41430b53d5473249470a6823f14fc8d5c3979adb550aa'
> MyNFTokenInstance.balanceOf(account0).toString();
'2' <-- Now we have 2!
> MyNFTokenInstance.burn(account0, '5678', { from: account0 });
> '0xb2b4eede6793212ac2d085d0d1121ce78da26513dc8c3503dc4faadc2f771f58'
> MyNFTokenInstance.balanceOf(account0).toString();
'1'
> MyNFTokenInstance.safeTransferFrom(account0, account1, '1234', { from: account0 });
'0x81b9b353855c4b8c9b8b4d82c4dc8bbfa2de0dd5e6d6d94831b459b1bf0dc7b3'
> MyNFTokenInstance.balanceOf(account0).toString();
'0'
> MyNFTokenInstance.balanceOf(account1).toString();
'1'
We already deployed some contracts to Ropsten network. You can play with them RIGHT NOW. No need to install software. In this test version of the contract, anybody can mint
or burn
tokens, so don't use it for anything important.
Contract | Token address | Transaction hash |
---|---|---|
NFToken | 0xdf8f576057f2f19f8cae4f7ae155a0ee66c05f24 | 0x665a0dc54b707e6cf354b2521368452ee11c19939b18d60d1df2649ef2a996be |
NFTokenEnumerable | 0xde0fb829c3562ec9ec68cb4fed1015ee81b81feb | 0xb520fceed5284c8d08611dca3768c69f23e5475d3d6b49cfbaa5105b5eeca54a |
NFTokenMetadata | 0xa3cdc8acd916d99104ab5428bc26372d0039cc86 | 0xbe1d72cd7f8e5865b3b6f7f95b72019733d8a2f897ff483b212de0a79f01aa40 |
NFTokenMetadataEnumerable | 0x7cc392789d2c0cc61377a26cf4dd181095b402a5 | 0xe706840e18c43b32a9f33dead9495e961ad91aaaa0ee4f2aa866726ea33c95ea |
See CONTRIBUTING.md for how to help out.
See LICENSE for details.