James Bachini

Automate Solidity With MEV

Automate Solidity

There are no cron jobs in Solidity or native to the Ethereum blockchain. To automate Solidity code we can either use an external service/oracle or we can incentivise MEV searchers to complete tasks efficiently on our behalf.

This type of Solidity automation is very common and used widely across liquidation systems which require reliable, fast, efficient execution.

The Challenge

The idea is quite simple, a user submits a bet that they can do some specific task or reach some measurable goal. They nominate a charity wallet address that the funds go to if the challenge is not completed by a specified deadline.

Imagine some crypto twitter debate occurs between some big egos where someone says they can trade a $10k account to $100k in one month. The trader agrees to stake 5 ETH in the contract and if they fail it will go to a charity of their choice.

Automate Solidity Tutorial

There’s a non-trivial issue here. What happens if the user doesn’t update the bet, gas fees are high enough that no one else wants to pay a tx fee and the charity wont get involved because they think it’s a scam. Do the funds remain in the contract forever?

We need a way to incentivise a 3rd party to close the bet, pay the transaction fee and finalise the bet once the deadline has passed, if the original bettor hasn’t claimed.

The Solidity Automation Code

Here is a smart contract implementation in solidity for this concept:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract BetMyself {
    
    struct Bet{
        address user;
        address charity;
        string task;
        uint amount;
        uint deadline;
        bool betWon;
        bool completed;
    }

    Bet[] public bets;

    mapping(address => uint) public balanceOf;

    function createBet(string memory _task, uint _secondsToDeadline, address _charity) public payable {
        Bet memory newBet;
        newBet.user = msg.sender;
        newBet.charity = _charity;
        newBet.task = _task;
        newBet.amount = msg.value;
        newBet.deadline = block.timestamp + _secondsToDeadline;
        newBet.betWon = false;
        newBet.completed = false;
        bets.push(newBet);
    }

    function completeBet(uint _betId) public {
        require(bets[_betId].user == msg.sender, "This is not your bet");
        require(bets[_betId].completed == false, "Bet is completed");
        bets[_betId].completed = true;
        payable(bets[_betId].user).transfer(bets[_betId].amount);
    }

    function failedBet(uint _betId) public {
        // Note anyone can liquidate a failedBet and take 5% fee
        require(bets[_betId].completed == false, "Bet is completed");
        require(bets[_betId].deadline < block.timestamp, "Bet is ongoing");
        bets[_betId].completed = true;
        uint fee = bets[_betId].amount * 5 / 100;
        payable(msg.sender).transfer(fee);
        payable(bets[_betId].charity).transfer(bets[_betId].amount - fee);
    }

}

The Explainer

Here’s a quick walkthrough of the contract

  1. createBet Enables a user to create a bet by specifying the task, deadline, and charity. The user defines the bet amount by sending ETH during the function execution.
  2. completeBet Allows the user to complete their bet. This function checks that it’s the same user who created the bet and that the bet is not completed yet. Upon completion, the bet amount is sent back to the user.
  3. failedBet Allows any user to liquidate a failed bet. A bet is considered failed if it surpasses its deadline without being marked as completed. The person liquidating the bet takes a 5% fee and the remaining amount is sent to the specified charity.

The fee incentivises searchers to monitor, claim and automate the process on our behalf. In reality we would need to advertise this to searchers so they are aware of the opportunity. A post in the flashbots discord would probably do the trick.

By creating financial incentives for searchers the function would likely be called on the exact block that the deadline passes and the reward fee becomes available. The competitive nature of the MEV market works in our favour to make this system very efficient.

You could take this further by curating an array of bets that have passed their deadline and providing a failAll() function for searchers. This would mean bets would stack up until the cumulative value of the fees exceeds the transaction cost. Potentially this would allow us to reduce the fee percentage and/or cap it to a limited amount making the system more cost efficient at the cost of a potential time delay.

Note that the code is for demonstration purposes only, is not tested and is not suitable for deployment anywhere near mainnet.


Get The Blockchain Sector Newsletter, binge the YouTube channel and connect with me on Twitter

The Blockchain Sector newsletter goes out a few times a month when there is breaking news or interesting developments to discuss. All the content I produce is free, if you’d like to help please share this content on social media.

Thank you.

James Bachini

Disclaimer: Not a financial advisor, not financial advice. The content I create is to document my journey and for educational and entertainment purposes only. It is not under any circumstances investment advice. I am not an investment or trading professional and am learning myself while still making plenty of mistakes along the way. Any code published is experimental and not production ready to be used for financial transactions. Do your own research and do not play with funds you do not want to lose.