Skip to content

Instantly share code, notes, and snippets.

@seanchen1991
Last active August 11, 2025 18:56
Show Gist options
  • Select an option

  • Save seanchen1991/acf2ce9c32963f8690c347b8667fb774 to your computer and use it in GitHub Desktop.

Select an option

Save seanchen1991/acf2ce9c32963f8690c347b8667fb774 to your computer and use it in GitHub Desktop.
Full contract code and test suite for SimpleERC20
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SimpleERC20 {
// Mappings
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
// State variables
uint256 private _totalSupply;
string private _name = "SimpleToken";
string private _symbol = "STK";
uint8 private _decimals = 18;
// Events
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
// Constructor
constructor(uint256 initialSupply) {
_totalSupply = initialSupply * 10**_decimals;
_balances[msg.sender] = _totalSupply;
emit Transfer(address(0), msg.sender, initialSupply);
}
// Transfer tokens
function transfer(address to, uint256 amount) public returns (bool) {
require(_balances[msg.sender] >= amount, "Insufficient balance");
require(to != address(0), "Cannot transfer to zero address");
_balances[msg.sender] -= amount;
_balances[to] += amount;
emit Transfer(msg.sender, to, amount);
return true;
}
// Approve spender
function approve(address spender, uint256 amount) public returns (bool) {
require(spender != address(0), "Cannot approve zero address");
_allowances[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
// Transfer on behalf of
function transferFrom(address from, address to, uint256 amount) public returns (bool) {
require(_allowances[from][msg.sender] >= amount, "Allowance exceeded");
require(_balances[from] >= amount, "Insufficient balance");
require(to != address(0), "Cannot transfer to zero address");
_balances[from] -= amount;
_balances[to] += amount;
_allowances[from][msg.sender] -= amount;
emit Transfer(from, to, amount);
return true;
}
// Get balance
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
// Get allowance
function allowance(address owner, address spender) public view returns (uint256) {
return _allowances[owner][spender];
}
// Get the total supply
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
// Get the name of the token
function name() public view returns (string memory) {
return _name;
}
// Get the symbol of the token
function symbol() public view returns (string memory) {
return _symbol;
}
}
const { expect } = require("chai");
describe("SimpleERC20", function() {
let token;
let owner;
let addr1;
let addr2;
beforeEach(async function() {
[owner, addr1, addr2] = await ethers.getSigners();
const Token = await ethers.getContractFactory("SimpleERC20");
token = await Token.deploy(1000); // initial supply of 1000 tokens
await token.waitForDeployment();
});
it("Should assign total supply to owner", async function() {
const ownerBalance = await token.balanceOf(owner.address);
expect(await token.totalSupply()).to.equal(ownerBalance);
});
it("Should transfer tokens between accounts", async function() {
await token.transfer(addr1.address, ethers.parseEther("50"));
expect(await token.balanceOf(addr1.address)).to.equal(ethers.parseEther("50"));
});
it("Should fail if sender does not have enough tokens", async function() {
const ownerBalance = await token.balanceOf(owner.address);
await expect(
token.connect(addr1).transfer(owner.address, 1)
).to.be.revertedWith("Insufficient balance");
expect(await token.balanceOf(owner.address)).to.equal(
ownerBalance
);
});
it("Should update allowances", async function() {
await token.approve(addr1.address, ethers.parseEther("100"));
const allowance = await token.allowance(owner.address, addr1.address);
expect(allowance).to.equal(ethers.parseEther("100"));
});
it("Should transfer tokens from one account to another with allowance", async function() {
await token.approve(addr1.address, ethers.parseEther("100"));
await token.connect(addr1).transferFrom(
owner.address,
addr2.address,
ethers.parseEther("50")
);
expect(await token.balanceOf(addr2.address)).to.equal(
ethers.parseEther("50")
);
expect(await token.allowance(owner.address, addr1.address)).to.equal(
ethers.parseEther("50")
);
});
}

Comments are disabled for this gist.