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
- Open MetaMask
- Click Import tokens
- Enter:
- Token contract address
- Token symbol
- Decimals (usually 18)
- 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
| Issue | Prevention |
|---|---|
| Reentrancy | Use ReentrancyGuard |
| Integer overflow | Solidity 0.8+ built-in |
| Access control | Use Ownable/AccessControl |
| Front-running | Consider 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.
Related
- Deploying Contracts - Deployment guide
- EVM Transactions - Transaction basics