Drippie: How OP Mainnet automates Ethereum

Optimism does a lot of stuff on-chain. Managing and monitoring the many on-chain interactions required to keep a system like this running can become a bit of a headache. This isn’t an impossible problem — but it’s enough of nuisance that it’s worth automating.

Drippie: How OP Mainnet automates Ethereum

A very transactional relationship

Optimism does a lot of stuff on-chain. OP Mainnet software is constantly sending transactions to Ethereum for a variety of different reasons. A lot of this activity comes from the OP Mainnet’s Sequencer (aka the block producer) which needs to publish transaction data and transaction results to Ethereum 24/7. We also maintain various other useful tools that require frequent on-chain activity. For example, the Warp Speed collects a significant amount of ETH on Ethereum which needs to be regularly deposited into OP Mainnet to maintain the balance of the Warp Speed disbursement account on L2.

Not only does this mean a lot of transactions on Ethereum, it means a lot of transactions on every Ethereum chain that OP Mainnet is connected to. Optimism currently maintains a mainnet connected to Ethereum (the OP Mainnet you know and love) but also maintains multiple testnets (both public and internal) connected to various other networks like Kovan and Goerli. Managing and monitoring the many onchain interactions required to keep a system like this running can become a bit of a headache. This isn’t an impossible problem — but it’s enough of nuisance that it’s worth automating.

Maintaining balance

Of course, every account that needs to transact frequently must also have enough ETH to be able to carry out those transactions. This means you’ll need some additional software to keep these accounts topped up. Once you realize this, you run into a bit of a problem. You really don’t want a hot wallet holding too much ETH, but you also want all of your ETH management to happen mostly automatically.

You can start to get fancy with multisig wallets or CI secrets or HSMs and whatnot, but that just creates even more overhead for an already complex system. We’d really prefer to use a low-trust solution that limits our maximum potential downside. It’s a good thing we already have a way to do things trustlessly on Ethereum: just use Ethereum!

Introducing Drippie

Drippie is OP Mainnet’s mechanism for (mostly) addressing the problems that come with automating on-chain activity. Drippie is basically an Ethereum-native version of If This Then That (IFTTT), a programmable Web2 service that can combine various triggers (”Kelvin sent a tweet”) with actions (”email me the tweet”).

Like IFTTT, Drippie can be programmed (in Solidity) to react to all sorts of on-chain data and carry out various different actions in response to that data. Each set of checks/actions within the Drippie system is called a “drip”. This relatively simple model turns out to be extremely powerful and can carry out pretty much any of the onchain operations that OP Mainnet needs on a daily basis. Here’s what that looks like in a nutshell:

A vague flowchart for Drippie's operation

Who automates the automation?

Drippie is a system for allowing actions to execute under certain conditions. However, we still need some service to trigger these actions when their requisite conditions are met. Here’s where we integrate services like Gelato, Chainlink Keepers, or OpenZeppelin Defender AutoTasks.

Each of these services is slightly different, but the idea is the same: send Ethereum transactions automatically. Drippie is designed to plug into these services in a flexible and trust-minimized manner. Drippie is built as a layer on top of these automation platforms, meaning we never need trust the correctness of any on or off-chain services run by these providers and we’re never locked into any single provider.

Drippie supports multiple automation backends!

We currently run Drippie on top of Gelato and we’ve been very happy with Gelato’s performance (thanks Gelato! nice work 🙂). Although we don’t expect issues from Gelato any time soon, we’ll likely look to integrate other providers as a backup to guarantee that drips always execute in a timely manner. Either way, we run Drippie alongside a robust monitoring service that tracks drip executions in real-time and alerts us when drips aren’t being executed on time.

If one backend goes down, we can use others as a backup

Some examples

Talk is cheap, code is expensive! We’ve spent a lot of time describing what Drippie is, but not but what it can actually do. Let’s give Drippie some more color by checking out some examples of the various drips that OP Mainnet actually uses in production.

Balance Maintenance Drip

One of our simplest drips is meant for balance maintenance — when the balance of an account decreases below a certain threshold, we can automatically execute an action that sends more ETH to the account. We typically combine this with a drip interval that prevents the drip from executing more than once every X (minutes/hours/days/etc). By restricting the frequency at which the drip can execute, we limit the impact of a compromised recipient wallet to just the current balance of that wallet and the value of a single drip execution (which are both typically relatively low). If a wallet compromise is ever detected, we can pause the drip and prevent ourselves from losing any additional funds.

Flow for the Balance Maintenance drip

Warp Speed Drip

Warp Speed is the name for the operational mode on the OP Mainnet gateway that allows users to send ETH to L2 via a custom bridge. Warp Speed is relatively straightforward — users send small amounts of ETH to a contract on L1 and then an off-chain service detects this deposit and triggers a transaction to transfer the deposited amount to the user on L2. Low-tech, but highly impactful for users trying to bridge small amounts of ETH to OP Mainnet.

A big problem with Warp Speed is that ETH builds up in a smart contract on L1, but deposits are being disbursed on L2. We regularly need to transfer the ETH from the L1 contract to the L2 disbursement address to keep the money flowing. Drippie makes this process a breeze. We’ve set up a simple drip on mainnet that triggers whenever the balance of the Warp Speed deposit contract exceeds a certain threshold. This drip will then withdraw funds out of the Warp Speed contract and deposit them (through OP Mainnet’s Standard Bridge) directly into the account of the disbursement wallet on L2. Nifty!

Flow for the Warp Speed drip

Perpetual Gelato Motion Drip

We previously mentioned that Drippie currently runs on top of Gelato, a fantastic Ethereum transaction automation service. Gelato requires that we somehow pay for the transactions that it executes. Gelato currently offers two methods of payment: transactions can either pay for themselves or users can deposit funds into an account that can be debited to pay for executed transactions. In an effort to minimize the complexity of each drip and to minimize vendor lock-in, we make use of the second method and fund an account that pays for Gelato transactions.

Of course, this means that the Gelato account needs enough of a balance to continue to pay for transactions! Just like we have a drip for funding other accounts, we also maintain a drip that keeps the balance of our Gelato account topped up. Whenever the balance of our execution account drops below a certain threshold (as reported by the Gelato treasury contract), we automatically deposit another few ETH into Gelato. This ends up looking like a slightly more advanced balance maintenance drip that shows off the flexibility of Drippie by querying and executing arbitrary smart contract functions.

Flow for the Gelato Deposit drip

As a result of this meta-automation, we can effectively run Drippie forever as long as the Drippie contract holds enough ETH. As we gain more confidence in the Drippie contract, we’ll aim to store more and more ETH until it can effectively be (trustlessly) self-sufficient for months at a time. Wild stuff!

Anatomy of a drip

We tried to make the process of defining new drips as easy as possible. Here's the configuration for one of our production drips, the TeleportrWithdrawal drip:

  TeleportrWithdrawal: {
    interval: 60 * 60 * 24,
    dripcheck: 'CheckBalanceHigh',
    checkparams: {
      target: '0x52ec2f3d7c5977a8e558c8d9c6000b615098e8fc',
      threshold: ethers.utils.parseEther('1'),
    },
    actions: [
      {
        target: '0x78A25524D90E3D0596558fb43789bD800a5c3007',
        data: {
          fn: 'withdrawFromTeleportr',
          args: [],
        },
      },
    ],
  },

Every drip has an interval, the minimum amount of time that must elapse between two executions of the drip. Drips also refer to a dripcheck, a simple Solidity contract that takes input parameters (the checkparams) and figures out whether the drip should be executable or not. Here, the TeleportrWithdrawal drip is using the CheckBalanceHigh check:

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import { IDripCheck } from "../IDripCheck.sol";

/**
 * @title CheckBalanceHigh
 * @notice DripCheck for checking if an account's balance is above a given threshold.
 */
contract CheckBalanceHigh is IDripCheck {
    event _EventToExposeStructInABI__Params(Params params);
    struct Params {
        address target;
        uint256 threshold;
    }

    function check(bytes memory _params) external view returns (bool) {
        Params memory params = abi.decode(_params, (Params));

        // Check target balance is above threshold.
        return params.target.balance > params.threshold;
    }
}

Finally, the drip also specifies an array of actions. Actions have a target, some data, and optionally also some ETH value. We've also integrated some simple Etherscan tooling to pull down the ABI for any verified contracts so that we can specify data as function names and parameters (instead of having to encode the function data manually).

Wrapping up

I had a blast building Drippie, and hope others find it as useful as I do. Drippie, drippie-mon (the Drippie monitoring service), and all related Drippie tooling is fully open-source and MIT licensed. If you’d like to use it in your own project, please feel free to do so! If there’s enough interest in Drippie, we might spin it out into a separate repository and try to make it more accessible for projects outside of OP Mainnet.

Hit us up on Discord, GitHub, or directly on Twitter (try DMing me at @kelvinfichter) if you do end up trying to use Drippie. Thanks for reading, and have a wonderful day!

Obligatory: we’re hiring!

As ever, OP Labs is hiring across the board. If you enjoyed reading about Drippie and you’d like to work with amazing people on the future of Ethereum, you might might be particularly interested in our openings for Senior Software Engineer, Developer Tools or Senior Infrastructure Engineer, DevOps. Cya on the internet! ❤️