ERC-20 is the main standard to represent fungibles tokens on Ethereum and EVM blockchain. This ERC defines the functions, events and the behavior of a token implementing this interface.
One of the main libraries used to build ERC-20 is OpenZeppelin. This library provides already all functions which are part of the standard. Nevertheless, OpenZeppelin does not provide a deployable contract, but only an abstract contract which can be used to build other contracts though inheritance but cannot be deployed directly on the blockchain. You can find more information about their implementation in their documentation.
TERC-20 aims to provide a minimal deployable implementation for standalone deployment (immutable) and proxy deployment (upgradeable) which allows the issueur (and only him) to mint and burn tokens.
TERC-20 exists in two different version: standalone and proxy:
TERC20Standalone
for an immutable deployment, without proxy.
TERC20Upgradeable
for an upgradeable deployment, with a compatible proxy (Transparent or Beacon)
In addition to ERC-20, TERC-20 uses the following ERCs:
- ERC-6093: Custom errors for ERC-20 tokens (through OpenZeppelin)
- eip-3643: implements the following functions:
- version()
- mint(), burn()
- batchMint, batchBurn()
- TERC20Upgradeable only:
- implements ERC-7201 to manage the storage location.
These ERC-20 tokens have the following characteristics:
Mint
-
A mint function only accessible with the MINTER role
-
Two mint batch functions only accessible with the MINTER role
Interface defined in ./TERC20ShareMint
Burn
- A burn function only accessible with the BURNER role
- Two burn in batch functions only accessible with the BURNER role
Interface defined in ./TERC20ShareBurn
ERC20
-
At deployment, the issuer can set the name, symbol and decimals.
-
Once deployed, it is no longer possible to modify these values except via an upgrade in the case of the proxy.
Access Control is managed with the OpenZeppelin library AccessControl which implements a role-based access control mechanism.
- Default Admin Role
The most important role is the role DEFAULT_ADMIN_ROLE
. This role manages all other roles.
This role is also its own admin: it has permission to grant and revoke this role.
warning: Extra precautions should be taken to secure accounts that have been granted it.
- Supply management role
Two roles BURNER_ROLE and MINTER_ROLE allow their members to respectively mint or burn tokens.
Contract | Type | Bases | ||
---|---|---|---|---|
β | Function Name | Visibility | Mutability | Modifiers |
TERC20Standalone | Implementation | ERC20, AccessControl, TERC20Share | ||
β | Public βοΈ | π | ERC20 | |
β | decimals | Public βοΈ | NOβοΈ | |
β | version | Public βοΈ | NOβοΈ | |
β | mint | Public βοΈ | π | onlyRole |
β | batchMint | Public βοΈ | π | onlyRole |
β | batchMintSameValue | Public βοΈ | π | onlyRole |
β | burn | Public βοΈ | π | onlyRole |
β | batchBurn | Public βοΈ | π | onlyRole |
β | batchBurnSameValue | Public βοΈ | π | onlyRole |
β | hasRole | Public βοΈ | NOβοΈ |
Contract | Type | Bases | ||
---|---|---|---|---|
β | Function Name | Visibility | Mutability | Modifiers |
TERC20Upgradeable | Implementation | Initializable, ERC20Upgradeable, AccessControlUpgradeable, TERC20Share, TERC20UpgradeableBurn, TERC20UpgradeableMint | ||
β | Public βοΈ | π | NOβοΈ | |
β | initialize | Public βοΈ | π | initializer |
β | __TERC20Upgradeable_init_unchained | Internal π | π | onlyInitializing |
β | decimals | Public βοΈ | NOβοΈ | |
β | version | Public βοΈ | NOβοΈ | |
β | hasRole | Public βοΈ | NOβοΈ | |
β | _getTERC20UpgradeableStorage | Private π |
Contract | Type | Bases | ||
---|---|---|---|---|
β | Function Name | Visibility | Mutability | Modifiers |
TERC20UpgradeableMint | Implementation | ERC20Upgradeable, AccessControlUpgradeable, TERC20ShareMint | ||
β | mint | Public βοΈ | π | onlyRole |
β | batchMint | Public βοΈ | π | onlyRole |
β | batchMintSameValue | Public βοΈ | π | onlyRole |
Contract | Type | Bases | ||
---|---|---|---|---|
β | Function Name | Visibility | Mutability | Modifiers |
TERC20UpgradeableBurn | Implementation | ERC20Upgradeable, AccessControlUpgradeable, TERC20ShareBurn | ||
β | burn | Public βοΈ | π | onlyRole |
β | batchBurn | Public βοΈ | π | onlyRole |
β | batchBurnSameValue | Public βοΈ | π | onlyRole |
Symbol | Meaning |
---|---|
π | Function can modify state |
π΅ | Function is payable |
The toolchain includes the following components, where the versions are the latest ones that we tested:
- Foundry / forge 1.0.0-stable
- Solidity 0.8.28 (via solc-js)
- OpenZeppelin Contracts (submodule) v5.2.0
- OpenZeppelin Contracts upgradeable (submodule) v5.2.0
Please see SECURITY.md.
Report made by SecFault Security
See our comment here report file
See crytic/slither
slither . --checklist --filter-paths "openzeppelin-contracts|test|forge-std" > slither-report.md
myth analyze src/TERC20Standalone.sol --solc-json solc_setting.json
aderyn
See Cyfrin/aderyn
See ./doc/script and Consensys/surya
npx prettier --write --plugin=prettier-plugin-solidity 'src/**/*.sol'
npx prettier --write --plugin=prettier-plugin-solidity 'test/**/*.sol'
Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.
Foundry consists of:
- Forge: Ethereum testing framework (like Truffle, Hardhat and DappTools).
- Cast: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
- Anvil: Local Ethereum node, akin to Ganache, Hardhat Network.
- Chisel: Fast, utilitarian, and verbose solidity REPL.
Explain how it works.
The contracts are developed and tested with Foundry, a smart contract development toolchain.
To install the Foundry suite, please refer to the official instructions in the Foundry book.
You must first initialize the submodules, with
forge install
See also the command's documentation.
Later you can update all the submodules with:
forge update
See also the command's documentation.
The official documentation is available in the Foundry website
forge build
You can run the tests with
forge test
To run a specific test, use
forge test --match-contract <contract name> --match-test <function name>
See also the test framework's official documentation, and that of the test commands.
- Perform a code coverage
forge coverage
- Generate LCOV report
forge coverage --report lcov
- Generate
index.html
forge coverage --ffi --report lcov && genhtml lcov.info --branch-coverage --output-dir coverage
See Solidity Coverage in VS Code with Foundry & Foundry forge coverage
Can we put the smart contract in a pause state ?
No, it is not possible to put the contract in a pause state. However, to desactivate the contract, it is possible to burn all tokens and renounce the control on the smart contract.
If you are interested by this feature, CMTAT could be more suitable.
Is the contracts compatible with ERC-2771 (gasless / MetaTx transaction)/
No, TERC-20 does not implement this ERC. If you are interested by this feature, CMTAT could be more suitable.
Can we change the symbol, name or decimals after deployment ?
In standalone deployment (immutable), all these information can not be changed.
With a proxy deployment, it is still possible to change it by deploying a new implementation which allows to set these information, but it requires extra work.
if you want the possibility to update these information, CMTAT could be more suitable since it allows more flexibility.
The original code is copyright (c) Taurus 2025, and is released under MIT license.