OpenZeppelin Preset Contracts
Letās add a simple ERC721 Token Preset.
Why use OpenZeppelin Contracts
From the OpenZeppelin Github Pageā: A library for secure smart contract development. Build on a solid foundation of community-vetted code.
They come with a preset, so we can easily do an ERC721 Contract that is mintable, pausable, burnable and supports all functions we possibly need to be ERC721 compliant.
For this first implementation we will be using https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.solā
Creating the ERC721 Token
Create a new file in /contracts/AisthisiToken.sol
with the following content:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.3;
import "@openzeppelin/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol";
contract AisthisiToken is ERC721PresetMinterPauserAutoId {
constructor() ERC721PresetMinterPauserAutoId("AisthisiToken", "AIS", "https://aisthisi.art/metadata/") {}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
return string(abi.encodePacked(super.tokenURI(tokenId),".json"));
}
}
This is a normal ERC721 Contract based on the preset that OpenZeppelin gives us. It might look overwhelming at this point, but there is nothing special to it - letās look what happens under the hood. If we open the ERC721PresetMinterPauserAutoIdā Contract then you see that it actually does a few things in the constructor (hereā is the documentation of the preset):
- It sets up a new ERC721 Token Contract with the name and the symbol, in this case āAisthisiTokenā and āAISā.
- It sets the tokenURI base url to āhttps://aisthisi.art/metadata/āā
- It will grant the deployer pausing rights and minting rights.
- Additionally, and completely optional, but we decided to add ā.jsonā to the url for the metadata file automatically, hence modified the
tokenURI
function.
constructor(string memory name, string memory symbol, string memory baseTokenURI) ERC721(name, symbol) {
_baseTokenURI = baseTokenURI;
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
_setupRole(MINTER_ROLE, _msgSender());
_setupRole(PAUSER_ROLE, _msgSender());
}
Letās give this a try in Truffle.
Adding Migrations to Truffle
Create a migrations file to migrations/2_token_migration.js
with the following content
const AisthisiToken = artifacts.require("AisthisiToken");
module.exports = function (deployer) {
deployer.deploy(AisthisiToken);
};
It should look like this now:
In the truffle-config.js file, edit the compiler settings to:
// Configure your compilers
compilers: {
solc: {
version: "0.8.3", // Fetch exact version from solc-bin (default: truffle's version)
// docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
//settings: { // See the solidity docs for advice about optimization and evmVersion
// optimizer: {
// enabled: true,
// runs: 200
// },
// evmVersion: "byzantium"
}
}
},
We will later have a look how we can use the optimizer and other techniques to save gas costs.
Deploying the Token to the Truffle Development Network
Then simply run the truffle development console
truffle development
This should open the Truffle Development console:
Now lets just migrate the token and then mint one token:
migrate
will deploy the tokens to this test-chain.
Testing the Token on the Truffle Development Console
Then you can simply type in
let token = await AisthisiToken.deployed();
token.mint(accounts[0]);
This will mint one token to your address.
That also means we can freely send it around!
token.transferFrom(accounts[0], accounts[1], 0);
Will transfer the token from account 0 to account #1.
Letās check the balance:
(await token.balanceOf(accounts[1])).toString()
Should output 1:
Thatās that. But what about that locking functionality?