Part 3. Creating a PoolTogether Draw Auction bot

Chuck Bergeron
5 min readSep 19, 2023

Tutorial duration: ~25 minutes

What is the Draw Auction bot?

The hyperstructure — PoolTogether’s latest protocol update introduces a new way to ensure the protocol lasts for generations to come. Built-in to the protocol is the ability for you to make profit by running core functions necessary for PoolTogether to operate day-to-day.

We’ve learned about the Arbitrage Liquidator bot in Part 1, and the Prize Claiming bot in Part 2. This tutorial is about the Draw Auction bot, which does two things:

  1. Requests the RNG (random number generator) to create a random number — used to determine the prizes — every day, and
  2. Bridges the provably fair and verifiable random number obtained in step 1 to the various chain’s prize pools.

Similar to the Prize Claiming in Part 2 of this tutorial series, the Draw Auctions use a gradual dutch auction to ramp up the rewards you can earn in exchange for assisting with the RNG flow over time. More info on how the auction works behind the scenes can be found in the docs here: https://dev.pooltogether.com/protocol/next/design/draw-auction

A gradual dutch auction determines the rewards you can earn from the draw auctions.

This tutorial will go over the steps required to create profitable RNG Request and Relay (bridge) transactions.

Note: We have created a bot (which runs on OpenZeppelin Defender, but you can use whichever cron/relay service you like) which you can use as a reference here: https://github.com/GenerationSoftware/pt-v5-autotasks-monorepo/tree/main/packages/draw-auction

These tutorials expect you have intermediate knowledge of programming concepts and JavaScript/TypeScript. We’ll use ethers.js, but you could write these bots using web3.js, Web3.py, etc.

Also, there is a JavaScript utils library for interacting with the PrizePool and associated contracts here: https://github.com/GenerationSoftware/pt-v5-utils-js

RNG Service

The RNG service used in Step 1 is currently set to Chainlink’s VRF, however any other random number source (such as RANDAO) could be plugged in at a later date.

Steps:

  1. Create a main() function and get setup
  2. Gather information about the state of the RNG and Relay Auctions
  3. Compare RNG service fee and gas costs against the current reward you could earn to determine profitability
  4. Execute transaction (when profitable) to start the RNG request or relay (bridge) the number to other chain’s prize pools

Caveat: The term relay in this tutorial is referencing the RngRelayAuction contract and function, not the OpenZeppelin Defender Relayer unless otherwise stated.

1. Create a main() and do setup

Working with the RNG and Relay contracts requires us to initialize a bunch of ethers.js Contract objects, as well as work across multiple chains.

During the first RngAuctionphase we will need to run startRngRequest to get a random number. The RNG currently uses Chainlink’s VRF on the Ethereum L1 chain. Therefore, the RngAuction, the RngAuctionRelayerRemoteOwnerand the ChainlinkVRFV2DirectRngAuctionHelpercontracts all live on Ethereum.

In the second phase RngRelayAuction, the random number needs to be broadcast from the L1 (Ethereum) to the prize pool on the L2 (currently Optimism, but could be a number of prize pools on various L2 chains). This is also initiated on the L1 using the RngAuctionRelayerRemoteOwner contract.

We will use the following contracts to query data from for finding out the state of the auctions: PrizePoolContract, RngAuctionContract, and RngRelayAuctionContract.

As well, we’ll need these two helper contracts for sending transactions: ChainlinkVRFV2DirectRngAuctionHelper and RngAuctionRelayerRemoteOwner.

These contract objects are all collected in the code below:

2. Gather Contract State

Once we have our main function set up, and the various AuctionContracts collected we can gain intel on the current auction state.

We start with the basic get function getDrawAuctionContext, this will call both getRng and getRelay as well, then combine that data into the contextobject:

getRng will collect all of the info necessary to determine if the startRngRequest function can be run, the fee we need to pay when requesting a random number, and the reward we could earn by requesting it:

getRelay takes information from getRng and determines if relay()(the bridging of the random number) can be run and how much we can earn by running that function:

3. Calculating Profitability

Now that we have all of that information about the state of the auctions and the cost of the RNG fee we can figure out how much could be earned by starting and completing the RNG process.

If the first phase RngAuction#startRngRequest is open, we will need to check if we can afford the RNG Fee (denominated in LINK), and if we have provided enough allowance to the contract to spend our relayer’s LINK. If the allowance is not high enough it will set it to maximum (as we trust the security of this contract. You may not want to set yours to max):

Note: We’ll leave out how to get the gas cost in USD for the chain you’re working on. You can view the reference implementation to see how this is done using eth_gasPrice, gasEstimate on contract calls from ethers.js and the USD value of the native gas token (ie. ETH on Optimism) from a price feed such as Coingecko or Covalent, etc.

Now we can find out if we will make profit on this transaction:

4. Executing Transactions

Last but not least, we need to determine which contract we want to transact with using the DrawAuctionState, and then send the transaction.

The reason we use the ChainlinkVRFV2DirectRngAuctionHelper is that it takes care of transferring the ERC20 RNG fee token, making it easier for bots to interact with the RngAuctioncontract.

The RngAuctionRelayerRemoteOwnerContract is used when the RNG is on one chain and needs to be relayed to a prize pool on another chain. Otherwise we could use the RngAuctionRelayerDirect#relay function directly.

Finishing Up

That wraps up Part 3 and this series of tutorials on the new PoolTogether hyperstructure bots.

Just in case you missed it: in Part 1 we looked at making profit with Liquidation bots — whose job is to liquidate interest-bearing (yield) tokens for POOL to supply the prize pool with.

In Part 2 we looked at Prize Claiming bots — a way to earn POOL while automating the claiming of prizes every day on behalf of winners.

If you have any questions don’t hesitate to ask anyone in the PoolTogether Discord community. The #developers channel is your best bet!

--

--