Smart Contracts
Smart contracts are self-executing contracts with the terms of the agreement directly written into code. They serve as the decentralized backend of any DApp, automating and enforcing the business logic within the system.
If coming from traditional web development, smart contracts are meant to replace the backend with important caveats: the user must have the native currency (GLMR, MOVR, DEV, etc.) to make state-changing requests, storing information can be expensive, and no information stored is private.
When you deploy a smart contract onto Moonbeam, you upload a series of instructions that can be understood by the EVM, or the Ethereum Virtual Machine. Whenever someone interacts with a smart contract, these transparent, tamper-proof, and immutable instructions are executed by the EVM to change the blockchain's state. Writing the instructions in a smart contract properly is very important since the blockchain's state defines the most crucial information about your DApp, such as who has what amount of money.
Since the instructions are difficult to write and make sense of at a low (assembly) level, we have smart contract languages such as Solidity to make it easier to write them. To help write, debug, test, and compile these smart contract languages, developers in the Ethereum community have created developer environments such as Hardhat and Foundry. Moonbeam's developer site provides information on a plethora of developer environments.
This tutorial will use Hardhat for managing smart contracts.
Create a Hardhat Project
You can initialize a project with Hardhat using the following command:
When creating a JavaScript or TypeScript Hardhat project, you will be asked if you want to install the sample project's dependencies, which will install Hardhat and the Hardhat Toolbox plugin. You don't need all of the plugins that come wrapped up in the Toolbox, so instead you can install Hardhat, Ethers, and the Hardhat Ethers plugin, which is all you'll need for this tutorial:
Before we start writing the smart contract, let's add a JSON-RPC URL to the config. Set the hardhat.config.js
file with the following code, and replace INSERT_YOUR_PRIVATE_KEY
with your funded account's private key.
Remember
This is for testing purposes, never store your private key in plain text with real funds.
Write Smart Contracts
Recall that we're making a DApp that allows you to mint a token for a price. Let's write a smart contract that reflects this functionality!
Once you've initialized a Hardhat project, you'll be able to write smart contracts in its contracts
folder. This folder will have an initial smart contract, likely called Lock.sol
, but you should delete it and add a new smart file called MintableERC20.sol
.
The standard for tokens is called ERC-20, where ERC stands for "Ethereum Request for Comment". A long time ago, this standard was defined, and now most smart contracts that work with tokens expect tokens to have all of the functionality defined by ERC-20. Fortunately, you don't have to know it from memory since the OpenZeppelin smart contract team provides us with smart contract bases to use.
Install OpenZeppelin smart contracts:
Now, in your MintableERC20.sol
, add the following code:
When writing smart contracts, you're going to have to compile them eventually. Every developer environment for smart contracts will have this functionality. In Hardhat, you can compile with:
Everything should compile well, which should cause two new folders to pop up: artifacts
and cache
. These two folders hold information about the compiled smart contracts.
Let's continue by adding functionality. Add the following constants, errors, event, and function to your Solidity file:
This function will allow a user to send the native Moonbeam currency (like GLMR, MOVR, or DEV) as value because it is a payable function. Let's break down the function section by section.
It will figure out how much of the token to mint based on the value sent
Then it will check to see if the amount minted is 0 or if the total amount minted is over the
MAX_TO_MINT
, giving a descriptive error in both casesThe contract will then forward the value included with the function call to the owner of the contract (by default, the address that deployed the contract, which will be you)
Finally, tokens will be minted to the user, and an event will be emitted to pick up on later
To make sure that this works, let's use Hardhat again:
You've now written the smart contract for your DApp! If this were a production app, we would write tests for it, but that is out of the scope of this tutorial. Let's deploy it next.
Deploy Smart Contracts
Under the hood, Hardhat is a Node project that uses the Ethers.js library to interact with the blockchain. You can also use Ethers.js in conjunction with Hardhat's tool to create scripts to do things like deploy contracts.
Your Hardhat project should already come with a script in the scripts
folder, called deploy.js
. Let's replace it with a similar, albeit simpler, script.
This script uses Hardhat's instance of the Ethers library to get a contract factory of the MintableERC20.sol
smart contract that we wrote earlier. It then deploys it and prints the resultant smart contract's address. Very simple to do with Hardhat and the Ethers.js library, but significantly more difficult using just JSON-RPC!
Let's run the contract on Moonbase Alpha (whose JSON-RPC endpoint we defined in the hardhat.config.js
script earlier):
You should see an output that displays the token address. Make sure to save it for use later!
Challenge
Hardhat has a poor built-in solution for deploying smart contracts. It doesn't automatically save the transactions and addresses related to the deployment! This is why the hardhat-deploy package was created. Can you implement it yourself? Or can you switch to a different developer environment, like Foundry?
Last updated