A template for creating compliant ERC-20 tokens on AERE Network with additional features. This template provides a secure foundation for creating your own token with best practices implemented.
Download TemplateMake sure you have the following installed:
# Clone the repository
git clone https://github.com/aere-network/erc20-template.git my-token
# Navigate to the project directory
cd my-token
# Install dependencies
npm install
# or
yarn install
Create a .env
file in the root directory with the following variables:
PRIVATE_KEY=your_wallet_private_key
AERE_RPC_URL=https://api.aere.network/rpc
ETHERSCAN_API_KEY=your_etherscan_api_key
Modify the MyToken.sol
contract in the contracts/
directory to customize your token:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
contract MyToken is ERC20, ERC20Burnable, ERC20Pausable, AccessControl {
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
uint256 public immutable maxSupply;
constructor(
string memory name,
string memory symbol,
uint256 initialSupply,
uint256 _maxSupply
) ERC20(name, symbol) {
require(_maxSupply >= initialSupply, "Max supply must be >= initial supply");
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(MINTER_ROLE, msg.sender);
_grantRole(PAUSER_ROLE, msg.sender);
maxSupply = _maxSupply;
_mint(msg.sender, initialSupply);
}
function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {
require(totalSupply() + amount <= maxSupply, "Exceeds maximum supply");
_mint(to, amount);
}
function pause() public onlyRole(PAUSER_ROLE) {
_pause();
}
function unpause() public onlyRole(PAUSER_ROLE) {
_unpause();
}
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal override(ERC20, ERC20Pausable) {
super._beforeTokenTransfer(from, to, amount);
}
}
Update the deployment script scripts/deploy.js
with your token parameters:
// scripts/deploy.js
async function main() {
const [deployer] = await ethers.getSigners();
console.log("Deploying contracts with the account:", deployer.address);
const MyToken = await ethers.getContractFactory("MyToken");
// Configure your token here
const name = "My Token";
const symbol = "MTK";
const initialSupply = ethers.utils.parseEther("1000000"); // 1 million tokens
const maxSupply = ethers.utils.parseEther("10000000"); // 10 million tokens
const token = await MyToken.deploy(name, symbol, initialSupply, maxSupply);
await token.deployed();
console.log("Token deployed to:", token.address);
}
npx hardhat run scripts/deploy.js --network aere
npx hardhat verify --network aere DEPLOYED_CONTRACT_ADDRESS "My Token" "MTK" "1000000000000000000000000" "10000000000000000000000000"
The template ensures compliance with the ERC-20 standard, which defines the following methods:
Function | Description |
---|---|
totalSupply() | Returns the amount of tokens in existence. |
balanceOf(address) | Returns the amount of tokens owned by a specific address. |
transfer(address, uint256) | Transfers a specified amount of tokens to the recipient address. |
allowance(address, address) | Returns the remaining number of tokens that a spender is allowed to spend on behalf of an owner. |
approve(address, uint256) | Sets the allowance of a spender over the caller's tokens. |
transferFrom(address, address, uint256) | Transfers tokens from one address to another, using the allowance mechanism. |
The template uses OpenZeppelin's AccessControl contract to manage permissions:
You can extend the token contract with additional features:
Run the test suite to ensure your token works as expected:
npx hardhat test
For additional help and resources: