I'm wondering whether I can stop / impair the 'standard' frontrunner / sandwich bots from frontrunning my (pretty standard) ERC20 token contract.

I'm thinking to add a mapping called "lastBuyBlock" for each address that buys (the 'to' address of the called _transfer function, when 'from' == pairAddress), which stores the block.number of an address' last buy tx.


mapping(address => uint256) private lastBuyBlock;
if (from == pairAddress) { lastBuyBlock(to) = block.number; }

Each sell or transfer tx (when 'from' != pairAddress), the current block.number will be compared to the "lastBuyBlock" of the 'from' address in the called _transfer function.

If the current block number equals the lastBuyBlock(from) --> 'from' is a confirmed frontrunner bot and thus action can be taken accordingly (for example revert the tx):

if (from != pairAddress && block.number == lastBuyBlock(from)) { revert(); }

Would this be a good / useful approach? Any arguments as to why I would not implement it this way? I think the 'added gas costs' to perform this frontrunner check on ETH network are fairly low, compared to the benefit of cutting out frontrunner bots. Am I missing something here (as I'm wondering why other tokens haven't implemented a comparable check like this already long time ago) ?

I do realize the bot owners could change their bot code to bypass this check (if they buy -> transfer to different address -> sell from that different address in the same block), but the above example would make that impossible as well.

Any reasons / input as to why I would or would not implement this check, are greatly appreciated!

1 Answer 1


I tested this today on BSC network and was successfully able to guard against frontrunner sandwich bots using this method. Honeypot checker did not flag my token.

I doubt any bots would implement this: "(buy -> transfer to different address -> sell from that different address" logic as it is complicated and makes them vulnerable.

This is basically what I did:

mapping (address => uint256) private _buyBlock; 

function _transfer(address from, address to, uint256 amount) 
    require(_buyBlock[from] != block.number, "Bad bot!");
    _buyBlock[to] = block.number;

My real goal with this testing was to "trap" a frontrunner bot based on comparing the buy/sell block number. I tried various methods such as taxes/blacklisting for wallet addresses that sell in same or next block after buy. I hoped that I could "trap" a bot if their sell TX fell to the next block (which sometimes happens in BSC which has 3 second blocks). But no luck. The bot seems to be able to identify whether TX's will be successful even if sell gets bumped to next block.

In any case the above method seems effective for bot prevention.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.