This project demonstrates a basic ERC20 token use case. It comes with a special modifier for the transfer and transferFrom functionality. The modifier "onlyOncePerBlock(address,address)" will make a token sender only be able to send a transfer transaction once per block. A sandwich (front- & backrun within one block) isn't possible anymore. Although a single frontrun or a backrun will still be possible.
mapping(bytes32 => bool) private perBlock;
mapping(address => bool) private exceptions;
...
...
...
modifier onlyOncePerBlock(address _from, address _to) {
if (!exceptions[_from]) {
bytes32 key = keccak256(abi.encodePacked(block.number, _from));
require(!perBlock[key], "ERC20: Only one transfer per block per address");
perBlock[key] = true;
}
if (!exceptions[_to]) {
bytes32 key = keccak256(abi.encodePacked(block.number, _to));
require(!perBlock[key], "ERC20: Only one transfer per block per address");
perBlock[key] = true;
}
_;
}
...
...
...
function _beforeTokenTransfer(address from, address to, uint256 amount) internal whenNotPaused onlyOncePerBlock(from,to) override {
super._beforeTokenTransfer(from, to, amount);
}
- Download NodeJS and install it
- Open terminal and navigate to the project directory
- Run
npm install
- Open .env file and edit ALCHEMY_KEY to your Alchemy API key
- Run
npx hardhat compile
to compile the contract - Run
npx hardhat test
to test the contract
- Create a working ERC20 boiler plate
- Optimize modifier onlyOncePerBlock for gas (currently a transfer costs 103.165)
- Implement a version without the need of modifying the state (removing mapping exceptions)