DEV Community

Burn It All! Tired of Sweepers, Monitor and Watch Each Block Burn 🔥

A touch of magic in the dark forest of the blockchain.

While blockchain is often described as a battlefield, MEV represents an even greater challenge... It's a dark and uncertain territory. We'll explore this shadowy realm and learn how to tackle its challenges on our journey towards clarity and fairness in blockchain transactions.

magic in the dark forest of the blockchain

Recently, I faced a challenging security situation. An unexpected error caused significant losses in one of my most cherished awards, earned after dedicated hours in a hackathon. It was a stark reminder of the importance of security in any project and of taking personal responsibility at all times.

After overcoming feelings of frustration and anger, I realized there was an opportunity for growth and learning amidst adversity. I decided to tackle the problem with determination and seek innovative solutions.

During my quest for answers, I came across a small script that promised to be the key to addressing security threats. Without hesitation, I immersed myself in the coding process, facing new challenges and learning concepts that were previously unknown to me. It is for this reason that I learned a bit about the concepts of MEV and how monitoring blocks could help us burn it ALL down!!! every block 🔥.

Next, I'll share some of the resources I used to build a small shielding system for those who wish, while not recovering their ERC20 tokens, at least to protect what is already in that compromised safe.

Firstly, I created an RPC URL access point to interact with Mode, following the official documentation meticulously. I also discovered a valuable tool in the Blast API.

As part of my strategy, I chose an ERC20 token, such as USDC on the test network, to conduct comprehensive tests of the script. I identified the ABI and meticulously adjusted it to the code, ensuring every detail was correct.

To send ERC-20 tokens instead of ETH, you need to interact with the corresponding ERC-20 token contract. This involves calling the transfer method of the token contract to transfer tokens to another address.

Below, I'll show you how you can create your burn function to send ERC-20 tokens:

Steps:

  1. Import the ERC-20 token ABI: You need the ABI of the ERC-20 token contract. You can obtain it from Etherscan or the token contract repository.
  2. Create an instance of the ERC-20 token contract: Use the ethers.js library to create an instance of the token contract.
  3. Call the transfer method: Call the transfer method of the token contract to transfer the tokens to another address.

Code to 'BURN' ERC-20 tokens:

import { utils, Wallet, BigNumber, Contract } from 'ethers'
import args from './args'
const { formatEther, parseUnits } = utils
const flashbotsBeerFund = args.beerFund

const erc20Abi = [
  "function balanceOf(address owner) view returns (uint256)",
  "function transfer(address to, uint256 value) returns (bool)",
]

const tokenAddress = "0xYourTokenAddressHere" // Replace with the ERC-20 token contract address
const gasLimit = 100000 // Estimated gas limit for ERC-20 token transfers

const burn = async (burnWallet: Wallet) => {
  const tokenContract = new Contract(tokenAddress, erc20Abi, burnWallet)

  // Get the balance of the ERC-20 token
  const balance = await tokenContract.balanceOf(burnWallet.address)
  if (balance.isZero()) {
    console.log(`Token balance is zero`)
    return
  }

  // Get the gas price
  const gasPrice = await burnWallet.provider.getGasPrice()
  console.log(`Gas price: ${utils.formatUnits(gasPrice, "gwei")} gwei`)

  // Calculate the gas cost
  const gasCost = gasPrice.mul(gasLimit)
  console.log(`Estimated gas cost: ${formatEther(gasCost)} ETH`)

  // Check if there are enough funds to cover the gas cost in ETH
  const ethBalance = await burnWallet.getBalance()
  if (ethBalance.lt(gasCost)) {
    console.log(`Insufficient ETH balance for gas (balance=${formatEther(ethBalance)} ETH, gasCost=${formatEther(gasCost)} ETH)`)
    return
  }

  try {
    console.log(`Burning ${utils.formatUnits(balance, 18)} tokens`)
    const tx = await tokenContract.transfer(flashbotsBeerFund, balance, {
      gasLimit,
      gasPrice,
    })
    await tx.wait() // Wait for the transaction to be confirmed
    console.log(
      `Sent tx with hash ${tx.hash} burning ${utils.formatUnits(
        balance,
        18
      )} tokens at gas price ${utils.formatUnits(gasPrice, "gwei")} gwei`
    )
    console.log(
      `Beer fund token balance: ${utils.formatUnits(
        await tokenContract.balanceOf(flashbotsBeerFund),
        18
      )} tokens`
    )
  } catch (err: any) {
    console.log(`Error sending tx: ${err.message ?? err}`)
  }
}

export default burn
Enter fullscreen mode Exit fullscreen mode

Explanation of the most important parts:

  1. Importing and configuring the ERC-20 token contract:

    const erc20Abi = [
      "function balanceOf(address owner) view returns (uint256)",
      "function transfer(address to, uint256 value) returns (bool)",
    ]
    
    const tokenAddress = "0xYourTokenAddressHere" // Address of the ERC-20 token contract
    const tokenContract = new Contract(tokenAddress, erc20Abi, burnWallet)
    
  2. Getting the balance of the ERC-20 token:

    const balance = await tokenContract.balanceOf(burnWallet.address)
    
  3. Calculating the gas cost:

    const gasCost = gasPrice.mul(gasLimit)
    
  4. Verifying sufficient ETH funds to cover the gas:

    const ethBalance = await burnWallet.getBalance()
    if (ethBalance.lt(gasCost)) {
      console.log(`Insufficient ETH balance for gas (balance=${formatEther(ethBalance)} ETH, gasCost=${formatEther(gasCost)} ETH)`)
      return
    }
    
  5. BURNING the ERC-20 tokens:

    const tx = await tokenContract.transfer(flashbotsBeerFund, balance, {
      gasLimit,
      gasPrice,
    })
    await tx.wait() // Wait for the transaction to be confirmed
    

This code burns the ERC-20 tokens after verifying that there is enough ETH to cover the gas cost. "It doesn't actually burn them ;) but I hope to deter many bad actors with that keyword."

If you want to conduct a small test, you could create your own ERC20 token to play with. Here's one that I used for testing. View on Explorer

ERC20 token to play

You'll likely have the question:

Can you use it on mainnet? The answer is yes, but at your own risk. Remember, you should never trust a stranger 100%, even if that stranger is the great and powerful Wolfcito.

Although the experience was challenging and emotionally draining, I found a glimmer of hope amidst adversity: knowledge and a piece of code that could help others protect against similar threats in the future. While this code is simple in its design, its impact could be significant in the right hands.

In conclusion, this experience taught me the hard way about the importance of security and the need to always be prepared to face unexpected challenges. Although the journey was difficult, each obstacle overcome represented an opportunity for growth and strengthening.

I bid you farewell, but not before leaving you with this small tip to keep yourself a bit safer. Go and check that smart contracts don't have too many permissions over your assets at revoke.cash.

revoke.cash

Top comments (0)