I need to create an ERC20 token that will be as simple as possible, with the following properties:
I must be able to burn some
I must be able to mint some
It must not have bugs such as backdoors / reentrance issues / race conditions, etc.
Does this code look good? It works great, I'm just wondering if there are any obvious bugs/issues you guys can see? Thanks in advance! Planning to deploy it on Ethereum mainnet using the Remix online IDE. I apologize if this is the wrong place to post this.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract Token is ERC20, ERC20Burnable, Ownable {
constructor() ERC20("MyToken", "MYTOK") {
_mint(msg.sender, 1000 * (10 ** uint256(decimals())));
}
function decimals() public pure override returns (uint8) {
return 6;
}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
}
Anyone holding liquidity of this token is not safe from the owner of the token contract minting a ton of liquidity for itself, thus reducing the actual worth of all holders but itself to effectively-zero.
Assuming that you are the owner of the token contract, it is financially safe for you, and financially unsafe for each and every one of your users.
Thank you for your reply.
Is there a simple way to set a total maximum supply? Maybe Openzeppelin has some examples?
I don't want to try and improvise and modify the source code myself as I will probably add a bunch of bugs in there.
ERC20Burnable will give token holders the ability to burn their own tokens. It does not give the contract owner the ability to arbitrarily burn tokens. It is not clear if that's what you were asking for.
Inherit ERC20Capped and initialize it with your desired maximum supply.
Adding the following single line in the beginning of the _mint() function seemed to do the trick. require(totalSupply() + amount <= 10_000_000 * 10 ** decimals(), "total supply reached");
What does inheriting ERC20Capped bring on top of that? After thecking the class's source code, it didn't seem like it adds anything really useful, mostly boilerplate (to my noobie eyes, anyway).
Are there any examples of PROPERLY implementing that inheritance? Kinda trying to remain as simple and fool-proof with my contract as possible. The OZ wizard doesn't seem to offer the ERC20Capped class in the options.
Relying on already-existing and thoroughly-verified code base, instead of "inventing the wheel"
Avoiding the additional gas cost of calling decimals() on every transaction, by doing it in the constructor instead (i.e., a single time, upon contract deployment)
The downside is that the check is conducted at the end of the transaction instead of at the beginning, leading to a higher gas consumption for failed transactions (i.e., users will spend more gas whenever their transactions fail).
An additional downside is that this check is conducted for every type of ERC20 transaction, and not just upon mint (i.e., also upon transfer, transfer-from, burn, etc).
TBH, it is not clear to me why it should, because the total supply can grow ONLY as a result of minting.
Perhaps the ERC20Capped is designed to accommodate for anyone choosing to increase the total supply in a non-conventional manner, for example, as a result of entity X transferring to entity Y.