Dutch auctions incentivize solvers to settle swaps for users at an optimal price point. UniswapX uses dutch auctions to let users execute market swaps quickly at a fair price. But what if a user wants to swap repeatedly over the course of hours, days, or weeks?
Executing recurring swaps on a time interval is a strategy that is commonly known as Dollar Cost Averaging (DCA). Brink has created a mechanism to support DCA strategies using intents. Users can sign one intent to run multiple sequential dutch auctions on a time interval, without an up-front deposit, transaction, or gas payment. Each recurring swap results in an Order Flow Auction (OFA) that solvers compete to fill.
The rest of this post dives into the mechanics of dutch auction-based recurring swap intents, describes how solvers are incentivized to settle them, and shows how users can leverage them for their individual strategies. There will be graphs, so buckle up.
Recurring Descending Price Auctions
A descending price auction is a type of dutch auction where a trader initially requires a high price for their trade and reduces their required price over time. The auction starts at a price that is more favorable for the trader, and moves toward a price that is more favorable for the filler. The auction ends when a filler is willing to fill the trade.
Brink’s model allows users to sign one intent for multiple descending price auctions that run sequentially over time. The starting and ending price of each auction is determined by a Uniswap V3 TWAP value.
Solvers monitor these auctions and compete to settle them at an optimal price point. After an auction is settled, the next one is set to start in the future. This process continues until all of the user’s intended swaps are settled.
Dutch Auction-based Recurring Swap Example
A user wants to swap 0.1 ETH for DAI once every 100,000 blocks. They schedule their first auction to start in a future block (19,000,000), and set each auction to run for 10 blocks.
Let’s pretend that block 19,000,000 is about is about to be validated. On current markets, it is possible to swap 0.1 ETH for 75 DAI (ignoring gas). Let’s call this 75 DAI the “market output”. The user’s first auction is set to start at a 200 DAI output requirement for an input of 0.1 ETH. Filling a 0.1 ETH to 200 DAI swap would not make sense for any rational solver based on the current market output, so we would not expect the swap to be settled at the start of the auction. The following graph shows this initial state:
From block 19,000,000 to 19,000,003 the amount of DAI required for settlement of the auction declines from 200 DAI to 100 DAI. In the meantime, the market moves. The market output for 0.1 ETH increases from 75 DAI to exactly 100 DAI. At this point it still does not make sense for rational solvers to fill the swap, because they need to pay for the gas cost of the settlement transaction. In other words, a solver will not pay for the gas to swap 0.1 ETH for exactly 100 DAI only to be required to send the signer 100 DAI because they would be filling at a loss.
At block 19,000,004 the market output increases and the DAI amount required by the auction decreases further. The solvers see their first opportunity for a small profit. Now any solver who sees this opportunity needs to decide whether to wait for a better opportunity as the auction price continues to drop or fill the swap quickly for a small profit before other solvers fill the auction. This is the incentive mechanism that forces each solver to settle swaps faster and better than others.
At block 19,000,005 one of the solvers decides to settle the user's intent. They earn a small profit. The solver pays gas to send a transaction that settles at the Dutch auction’s required amount. Whatever is left over after settlement and gas cost is the solver’s profit.
Now that this auction is settled, the user’s next auction is scheduled to start in 100,000 blocks, at block 19,100,005.
Sequential Dutch Auctions
User’s sign the block when their first auction will start, the number of blocks to wait between auctions, and the maximum duration (in blocks) of each auction. When an auction is settled, part of that settlement transaction must include a state change that starts the waiting period until the next auction. By reading on-chain state, solvers are able to know when the next auction will start.
However, solvers do not know what the auction start price will be until the auction actually starts. That’s because the start price is determined based on a Uniswap V3 TWAP.
Why Use Uniswap V3 TWAP?
When signing recurring swap intents, users don’t know what the market price will be in the future when each of their swaps are scheduled. An on-chain price value needs to be used to set the starting price of the auctions. Uniswap V3 TWAP’s provide a way to obtain an on-chain value that is very close to market spot price.
It is very expensive to manipulate a TWAP. I would cost hundreds of billions in USD to move the WETH/USDC pool by 20% for 2 blocks (as analyzed in this post). Since dutch auctions start significantly higher than the TWAP, it would be irrationally costly for an attacker to manipulate a TWAP for the purpose of moving dutch auction start prices below market. This holds true even at scale. If there were dutch auction recurring swap intents with hundreds of millions of USDC to WETH swaps all scheduled to be auctioned starting in the same block, it would still be irrational for an attacker.
The signature of a Dutch auction-based recurring swap intent includes parameters that define a percentage above the TWAP to start each auction, and a percentage below the TWAP to end each auction. The signer also defines the time interval for the TWAP, and the address of the Uniswap pool to read the TWAP from.
TWAP is a time weighted average price, so it is not equal to the exact spot price of the market. For the purpose of setting a start and end price in a dutch auction TWAP works well because we don’t need the price to be exact. The auction mechanics will work as expected as long as start price is above market, and end price is below market.
Can Solvers Rig the System?
Short answer: no, unless all solvers in the network collude. Similar to miner or validator nodes operating a blockchain, more participants in the network means a lower chance of collusion.
In a descending price auction, there is no subjectivity around solvers providing intent signers with an “optimal price” or providing “best execution”. The auction forces solvers to fill at the auction’s required price. Brink protocol smart contracts require this to happen or else the solver’s transaction will revert. Solvers are strongly incentivized to find the best route they can, for the cheapest gas price to beat other solvers. Only one solver can fill each auction.
Read Powerful Incentives: Part 2 for a deeper dive into solver incentives.
One of the main benefits of intent-centric architectures is MEV resistance. Users who sign intents are requiring exact outcomes (usually an exact amount of tokens to be received) and incentivizing solvers to find optimal routes for these outcomes. This is in contrast to users who sign and submit transactions for AMM swaps, where required outcome can only be set as a maximum “slippage” amount, and revert costs associated with exceeding this slippage amount are paid for by the user.
Asking swappers to set slippage limits on AMM’s equates to asking “how much are you willing to pay MEV bots?”. This is an extremely complex ask. With intent-centric networks, all MEV related decision making is delegated to the solver layer. Solvers who are most adept at navigating complexities around MEV, routing, gas cost, and other EVM interactions, will consistently win dutch auctions thus providing better and faster outcomes for users.
Brink has created the first intent-centric mechanism for Dollar Cost Averaging.