Skip to main content

ERC-20 Tokens

This guide covers creating and interacting with ERC-20 tokens on Monolythium.

What is ERC-20?

ERC-20 is the standard interface for fungible tokens on EVM-compatible chains:

interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

Creating an ERC-20 Token

Using OpenZeppelin

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract MyToken is ERC20 {
constructor(uint256 initialSupply) ERC20("MyToken", "MTK") {
_mint(msg.sender, initialSupply);
}
}

With Additional Features

// 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/access/Ownable.sol";

contract MyToken is ERC20, ERC20Burnable, Ownable {
constructor() ERC20("MyToken", "MTK") Ownable(msg.sender) {
_mint(msg.sender, 1000000 * 10 ** decimals());
}

function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
}

Interacting with Tokens

Check Balance

const { ethers } = require('ethers');

const provider = new ethers.JsonRpcProvider('https://rpc.sprintnet.monolythium.com:8545');
const tokenAddress = '0x...';
const abi = ['function balanceOf(address) view returns (uint256)'];
const token = new ethers.Contract(tokenAddress, abi, provider);

const balance = await token.balanceOf('0x...');
console.log('Balance:', ethers.formatEther(balance));

Transfer Tokens

const wallet = new ethers.Wallet(privateKey, provider);
const token = new ethers.Contract(tokenAddress, [
'function transfer(address, uint256) returns (bool)'
], wallet);

const tx = await token.transfer('0x...', ethers.parseEther('100'));
await tx.wait();

Approve and TransferFrom

// Approve spender
await token.approve(spenderAddress, ethers.parseEther('100'));

// Spender transfers on behalf
await tokenAsSpender.transferFrom(ownerAddress, recipientAddress, amount);

Adding Tokens to MetaMask

  1. Open MetaMask
  2. Click Import tokens
  3. Enter:
    • Token contract address
    • Token symbol
    • Decimals (usually 18)
  4. Click Add

Common Patterns

Fixed Supply

constructor() ERC20("Fixed", "FIX") {
_mint(msg.sender, 1000000 * 10 ** 18);
}

Mintable

function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}

Burnable

import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";

contract MyToken is ERC20, ERC20Burnable {
// ...
}

Capped

import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol";

contract MyToken is ERC20Capped {
constructor() ERC20("Capped", "CAP") ERC20Capped(1000000 * 10 ** 18) {}
}

Token Security

Common Vulnerabilities

IssuePrevention
ReentrancyUse ReentrancyGuard
Integer overflowSolidity 0.8+ built-in
Access controlUse Ownable/AccessControl
Front-runningConsider commit-reveal

Audit Checklist

  • Use OpenZeppelin implementations
  • Test all functions
  • Review access controls
  • Check for common vulnerabilities
  • Consider professional audit for production

FAQ

What decimals should I use?

18 is standard, matching ETH/LYTH. Use fewer for tokens that shouldn't be divisible.

Can I change token supply after deployment?

Only if you included mint/burn functions and have appropriate access control.

How do I list my token on DEXes?

Create liquidity pools on AMMs deployed on Monolythium.