📝 Writing the contract
Now that your dev environment is all set up, we can get to writing the actual contract for our first NFT set on Frame.
But first, we'll need to install a dependency.
🔃 Installing dependencies
Note: This is an abridged tutorial made to get your contract up and running with ERC721A. You can read more about Foundry's dependency management here (opens in a new tab).
For this tutorial, we will be using the ERC721A (opens in a new tab) library to write our NFT smart contracts. ERC721A is an implementation of ERC721 (opens in a new tab), which is Ethereum's NFT standard. In order for a contract to be a valid NFT, it needs to implement all the functions defined in ERC721. Libraries such as ERC721A and OpenZeppelin (opens in a new tab) implement the required ERC721 functions so developers can focus on building specific features for their NFTs.
To install this dependency, run:
forge install chiru-labs/ERC721A --no-commit
This will add the library to the lib
directory in your project.
In order to use ERC721A in our contracts, we'll have to create a remappings.txt
file in the root of our project. This file allows us to map a shortcut to the actual location of the library.
So once you've created your remappings.txt
file, add the following line to it:
erc721a/=lib/ERC721A/contracts/
Now we can use the ERC721A library in our contracts! 🎉
✏️ The initial contract
You can go ahead and delete Counter.sol
in src/
, Counter.t.sol
in test/
, and Counter.s.sol
in script/
. We won't be needing those anymore.
In src/
, create a new file called MyFirstFrameNFT.sol
. This is where we'll be writing our contract.
First, we'll need to define what solidity version we want to use. For this tutorial, we'll be using 0.8.21
. Add the following line to the top of your file:
pragma solidity ^0.8.21;
Then, we'll need to import the ERC721A library we just installed. Add the following line to your file:
import "erc721a/ERC721A.sol";
This line lets us use in our contract the ERC721A library we added as a dependency. Remember, we added the erc721a/
prefix to the library's path in our remappings.txt
file, so we can use that prefix to import the library.
Your code should look like this:
pragma solidity ^0.8.21;
import "erc721a/ERC721A.sol";
Now let's write the actual contract logic. The first step is to declare a new contract instance called MyFirstFrameNFT
and have it inherit from ERC721A.
You can ignore any errors here as we've haven't implemented any required functions from ERC721A yet.
pragma solidity ^0.8.21;
import "erc721a/ERC721A.sol";
contract MyFirstFrameNFT is ERC721A {}
We can now add a constructor
to our contract. This is a special function that initializes the contract's state.
Because our contract inherits from ERC721A, we need to call ERC721A's constructor to complete the initialization.
We will pass in the name of our token MyFirstFrameNFT
and its symbol FIRST
into the ERC721A constructor.
You'll notice that we don't pass anything specifically into our constructor - this is because we have no additional state variables to initialize.
pragma solidity ^0.8.21;
import "erc721a/ERC721A.sol";
contract MyFirstFrameNFT is ERC721A {
constructor() ERC721A("MyFirstFrameNFT", "FIRST") {}
}
We have a valid NFT contract now, but there's no way for users to mint these tokens.
To enable minting, we need to add an external mint
function that users can call.
In a production-level app, the external mint function will normally take in a payment, validate that the user is on an allowlist, or check that the total supply is limited.
For our test contract, we'll write a basic mint function that's accessible to all without cost and without a supply limit.
pragma solidity ^0.8.21;
import "erc721a/ERC721A.sol";
contract MyFirstFrameNFT is ERC721A {
constructor() ERC721A("MyFirstFrameNFT", "FIRST") {}
function mint(uint256 quantity) external {
_mint(msg.sender, quantity);
}
}
To make sure that the code you wrote is valid, you can run forge build
. Your output should look like this:
[⠢] Compiling...
[⠑] Compiling 3 files with 0.8.21
[⠃] Solc 0.8.21 finished in 428.46ms
Compiler run successful!
Congrats, you just wrote your first NFT contract! Now let's add some metadata to it.