NFTs have been increasing in popularity since last year, regardless of how the cryptocurrency market is performing. If you follow any crypto news, you must have heard of CryptoPunk, BAYC or the most recent Phantom Bear. In short, an NFT is a smart contract with some meta data, such as an image, video or some other attribute data, to make it unique from other NFTs. And since it’s on a blockchain, it’s easy for anybody to verify the ownership. In this article, I will walk you through the process of how to deploy your own NFT with Python. We will be using a Python-based smart contract development framework called Brownie.
Getting started
This blog is about creating your first NFT collection. We will go through the steps of creating a smart contract, minting a new collection of NFTs, and listing it on an NFT marketplace. By doing this, you will be able to profit from your digital art.
Before we continue
Before writing code, there are a few concepts we should cover. I’ll go over each one quickly, but if you want to learn more about them, I’ve included some external resources below.
The essentials
For the sake of conciseness, I am going to assume that if you are reading this, you already have some working knowledge of what a blockchain is as well as some basic familiarity with programming languages such as Python (that’s what we’ll be using today!). If not, I suggest you take a look at the following resources before going any further as it will greatly reduce your confusion as we proceed today:
Ethereum and smart contracts
If you’re unfamiliar with the term, Ethereum is a blockchain that allows for the execution of smart contracts. These contracts are programs that exist at a unique address on the Ethereum blockchain. They can receive and send funds just like any other account, but they’re controlled by the program logic that was specified when they were deployed to the blockchain.
The native token of the Ethereum blockchain is called ether, and you will need some ether to facilitate transactions.
For more, check out the following:
Intro to Ethereum | ethereum.org
Introduction to smart contracts | ethereum.org
ERC-721: the Non-Fungible Token standard
An NFT, which is defined by the ERC-721 standard, is a unique token that is stored on the blockchain. It is associated with a specific smart contract that adheres to the standard. Each NFT has a unique token ID within its smart contract, which allows it to be distinguished from other tokens in the same collection. An NFT can be linked to additional data beyond its contract address and token ID. In this case, the data will be a reference to digital artwork (which will be discussed later), but it could also be other types of data.
Prerequisite
You will need to install the Brownie package. Below is the pip command to install Brownie:
#run in your venv
pip install eth-brownie
In order to test your code locally, Brownie will automatically install ganache cli, which launches a local Ethereum blockchain allowing you to execute your smart contracts. If you would prefer to install it manually, you can follow the ganache cli documentation.
Get Started with Brownie
Let’s create an empty folder and then run the below command to initiate a new Brownie project:
With the above command, brownie will create a project structure for you under your current folder. The majority of your work shall be done in the following folders:
- contracts – for solidity smart contract source code
- interfaces – for the interface files that referenced by the smart contract
- scripts – for deployment scripts or interacting with deployed contracts
- tests – for test scripts
This article will use Solidity-style smart contracts as an example.
Getting started with some test currency
When we’re learning about Ethereum, it can be expensive to experiment with real ETH. Even on Ethereum layer-2 networks like Polygon, which are designed to reduce transaction fees, we need to spend real tokens each time we want to change the state of the blockchain. However, Ethereum also has some test networks that only require test tokens.
First, open MetaMask and click the account icon. Then, click settings, and Advanced. Toggle “Show test networks” to on. This will allow us to see the test networks. We will be using the Rinkeby test network.
Visit the website https://faucets.chain.link/rinkeby to get some test currency for your account. You may need to connect your MetaMask to the site; just follow the steps provided. Make sure the network is set to Ethereum Rinkeby, select 10 test LINK, 0.1 test ETH, and confirm you are not a robot. Then, send the request and you should see the funds in your account soon. Use this test currency to change the state of the blockchain!
Create NFT Smart Contract
A smart contract that implements the ERC721 token standard is needed to create NFTs. The purpose of this article is to provide guidance on the process rather than go into depth about coding the smart contract, so a sample smart contract has been shared. The LegendNFT.sol smart contract file and the libraries folder can be downloaded and placed in the **contracts **folder.
Here is a quick explanation of what this smart contract does:
- an ERC721 contract with name *Codeforests Legend, token symbol CFL *and total supply of 1,000,000
- 3 lists of words to generate a “random” word phrase
- a SVG xml template to create a picture of the above word phrase
- a list of color codes to provide “random” background color to the SVG
- a mint function for minting the NFT tokens
- finally a function to return how many tokens have minted
The source code I used includes two external contracts from OpenZeppelin. In order to compile the contract, I need to specify this dependency in the *brownie-config.yaml *file. This file allows you to specify configurations, and is not created automatically when initiating the project. All settings are optional, and you will only need the file when necessary.
To specify the dependencies, you can manually create this yaml file under your project root folder. And add the below configurations:
It’s telling the Brownie package manager to automatically download the package and let the compiler find the correct path for it when using the ‘import @openzeppelin/…’ shortcut.
Compile Smart Contract
Once you have saved your contract and the config file, you can run below compile command on your terminal:
The output Json files will be placed in the build/contracts folder. The next step is to try and deploy the contract locally.
Deploy Smart Contract Locally
We need to use ganache to deploy our contract locally, as I mentioned at the beginning. By default, brownie will start the ganache local network and deploy the contract to it whenever you want to deploy a contract. Brownie provides a console window where you can use commands to deploy the contract, but since we might need to do the deployment multiple times for testing or in different networks, let’s create a re-usable Python script called deploy.py under the scripts folder for the deployment purpose.
The contract class object is automatically added to the brownie runtime environment upon compilation, so it can be imported from brownie.
Below is the Python code for deploying my LegendNFT contract:
from brownie import LegendNFT, network, config, accounts
def deploy_contract():
account = accounts[0]
legend_contract = LegendNFT.deploy({"from" : account})
print("contract has been deployed successfully to :", legend_contract.address)
return legend_contract
def main():
deploy_contract()
The ‘accounts’ variable refers to a list of pre-generated accounts that come with the Ganache client, which we’re using to run a local Ethereum network. We just need to specify which account we want to use as the contract creator, so we’ll use the first account in the list.
The main function for this script is __main__. Add the following code to the end of your script. if __name__ == “__main__”: main() This will ensure that the main function is run when the script is executed.
Next, let’s run the below command in the terminal:
brownie run .scriptsdeploy.py
Great job on getting your contract deployed to your local network. You may not be sure if it’s working correctly, but don’t worry. We’ll explore how to deploy to a public network and come back to unit testing later.
Deploy Smart Contract to Public Network
To make it easier, we’ve created an Infura client, which you can use Infura to deploy your contract to the popular public blockchains. The public network typically refers to public, accessible, and persistent blockchain networks such as Ethereum mainnet, rinkeby, kovan, and popsten. To access the public network, you’ll need to connect to a node. However, it would be impractical to run your own node just for deploying a contract. So, to make it easier, we’ve created an Infura client. With Infura, you can deploy your contract to popular public blockchains.
Luckily, there are some service providers like Infura, Alchemy, and Pocket Network that allow you to use their API to connect to the public network nodes. If you run below command in your terminal:
brownie networks list true
You can see it is using Infura’s API:
After you have completed these steps, you need to create a environment variable called WEB3_INFURA_PROJECT_ID and assign your API token to it. I would recommend putting this information into a .env file and loading it into the Brownie config file.
What else do you need? A real wallet account with some funds. Deploying always costs something to confirm the transaction. You can create a wallet with Metamask. For testnet, like rinkeby, you can get some testing ether token from chainlink rinkeby faucet. You can also find faucets for the rest of the testnets.
So let’s put below info in the .env file:
PRIVATE_KEY = 0x{your wallet private key}
WEB3_INFURA_PROJECT_ID = {your infrua project ID}
ETHERSCAN_TOKEN = {etherscan API token; to submit your contract source code to etherscan (optional)}
0xBefore you can interact with your contract on etherscan, you need to sign up and get an API token.
And add below lines in the brownie-config.yaml file:
dotenv: .env
wallets:
from_key: ${PRIVATE_KEY}
# optional for verifying the contract source code
networks:
development:
verify : false
rinkeby:
verify : true
You should add .env to your .gitignore so you don’t accidentally push sensitive info to Github. Your wallet private key is the same for testnet and mainnet, so be careful not to expose it to anyone.
Change the deployment script to use the new account for deploying the contract to public network.
def deploy_contract():
if(network.show_active() == "development"):
account = accounts[0]
else:
account = accounts.add(config["wallets"]["from_key"])
legend_contract = LegendNFT.deploy(
{"from" : account},
publish_source=config["networks"][network.show_active()].get("verify")
)
print("contract has been deployed successfully to :", legend_contract.address)
return legend_contract
We have added a condition to check whether we are working on a local/development network. If it’s not a local network, we will load our account by the private key and use it to sign the transaction for deployment.
Now we have everything ready, let’s run the deploy.py again and specify the target network with the –network option, e.g. :
brownie run .scriptsdeploy.py --network rinkeby
It would take slightly longer time since it requires the transaction to be written on the blockchain. You can copy the contract address or transaction hash and then search it on etherscan for the rinkeby network.
My contract address and source code can be found here and here respectively.
Great job! Your contract is now visible to everyone on the public network. Since you haven’t minted any NFTs from your contract yet, you won’t see anything visually at the moment. To give you an idea of what your NFTs will look like, I’ve created a website for minting the *LegendNFT*. You can try it out and see the minting process, and then view the NFT from Opeasea. It currently supports the Rinkeby, Matic, and Matic Mumbai networks.
Conclusion
such as Ropsten. I will write more articles that cover how to create your own NFT, testing your contract, and how to deploy it to other networks. This subject is too complex to cover in one post.
Leave a Reply