Last active
August 11, 2025 18:56
-
-
Save seanchen1991/acf2ce9c32963f8690c347b8667fb774 to your computer and use it in GitHub Desktop.
Full contract code and test suite for SimpleERC20
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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.