Build Your ERC20
Write, compile, and test a custom ERC20 token. You will need two of these for the AMM pool.
Remix ERC20
ERC20 is the standard interface for fungible tokens on Ethereum. It defines a common list of rules including total supply, balances, transfers, and approvals.
Create the Contract
In Remix, click the + button in the file explorer and name it MyToken.sol. Paste this code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor(
string memory name,
string memory symbol,
uint256 initialSupply
) ERC20(name, symbol) {
_mint(msg.sender, initialSupply * 10 ** decimals());
}
}Remix has OpenZeppelin built-in via its import resolver, so the @openzeppelin import works automatically.
Compile
Go to the Solidity compiler plugin, select compiler version 0.8.19 or later, and click Compile MyToken.sol.
Deploy
Switch to the Deploy & Run Transactions plugin. Make sure the environment is set to Remix VM (Cancun).
Select MyToken from the contract dropdown, fill in the constructor arguments (e.g., "Token A", "TKA", 10000), then click Deploy.
You will see your deployed contract appear in the Deployed Contracts section. Copy its address, you will need it for the AMM.
Repeat the process to deploy a second token (e.g., "Token B", "TKB"). You should now have two token addresses saved.
Foundry ERC20
ERC20 is the standard interface for fungible tokens on Ethereum. It defines a common list of rules that all Ethereum tokens must follow, including:
totalSupply(), how many tokens exist.balanceOf(address), check an account balance.transfer(to, amount), move tokens.approve(spender, amount), let someone else spend your tokens.transferFrom(from, to, amount), spend tokens on behalf of someone else.
The Code
Create a new file at src/MyToken.sol and paste the following:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor(
string memory name,
string memory symbol,
uint256 initialSupply
) ERC20(name, symbol) {
_mint(msg.sender, initialSupply * 10 ** decimals());
}
}This contract:
- Inherits from OpenZeppelin's
ERC20. - Takes a
name,symbol, andinitialSupplyin the constructor. - Mints the full supply to the deployer, adjusted for
decimals()(which defaults to 18).
Compile
Run the build command:
forge buildIf everything is correct, you will see Compiler run successful!
Write a Quick Test
Create test/MyToken.t.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import "../src/MyToken.sol";
contract MyTokenTest is Test {
MyToken token;
function setUp() public {
token = new MyToken("Apple", "APL", 1000);
}
function testMintedToDeployer() public view {
assertEq(token.balanceOf(address(this)), 1000 * 10 ** 18);
}
}Run it:
forge testDeploy Two Tokens
For the AMM we need two different tokens. You can reuse the same contract with different constructor arguments.
We will deploy them in the next chapter directly from a script. For now, make sure forge build compiles cleanly.