Chapter 06
TWAP
TWAP. Time-weighted average price. An order split into equal slices on a clock, so the whole size does not hit the pool at once. The average is the prices those slices actually clear. See also Definitions.
The contract is 0xe44d758090f619627bd74625103f10d7E7A65Bfe, version 3. Funds stay in your wallet until each slice. The contract stores the schedule. It does not store your tokens. Version 2, 0x0A1e989456453E17893938fB82dBCE949CBD12a0, has the same swap rules and no take-profit or stop. New orders use version 3.
Create
You approve the TWAP contract for the order total, partSellAmount × n, not an unlimited allowance. Then you call create. The order records:
partSellAmountandn. The interface offers 2, 4, 8, or 12 parts. The contract allows 2 to 24.t0andinterval. Interval is at least 60 seconds.minPartBuy. A slice that returns fewer buy tokens revertsProtection.takeProfitBuyandstopBuy. Leave both at 0 and the order fills only on the clock. A take profit must be above the floor. A stop must be at or above the floor, and below the take profit when both are set.feeBps. The app sets 15. The contract rejects anything above 100 bps.
On create, the contract checks the slice is still positive after the fee: swapIn = partSellAmount − partSellAmount × feeBps / 10_000. A zero result reverts BadOrder.
Execute
execute(id, router, swapData) is permissionless. The keeper is the default caller and pays gas. Any caller can fill a live window, so one offline keeper does not freeze the order. The router address must be on the contract’s allowlist or the call reverts BadRouter.
- The window for part
filledis[t0 + filled × interval, end). Inside it, the slice fills at the floor. Outside it, the call revertsWindowunless a take profit or a stop is set. A take profit fills only when the recipient receives at leasttakeProfitBuy. A stop fills only when the recipient receives at least the floor and no more thanstopBuy, and the swap is a single pool. The full output still goes to the recipient. transferFrompullspartSellAmountfrom the owner.- Fee is
partSellAmount × feeBps / 10_000. If the sell token is 🚀,burn(fee). Otherwise the fee is transferred to the treasury. - The contract approves the router for
swapIn, calls it withswapData, then sets that approval back to 0. swapDatahas to be one Uniswap v2 or v3 swap. The path starts at the sell token and ends at the buy token, the amount is the fullswapIn, and the recipient is the order recipient. Anything else, including Universal Router, revertsBadSwap. That is what stops a filler from keeping the surplus and donating onlyminPartBuy.- The sell tokens actually spent must equal
swapIn. If the recipient’s buy-token balance rises by less thanminPartBuy, the whole fill revertsProtection. - Any leftover sell token on the contract is pushed back to the owner.
filledincrements. The event isPartFilled.
Version 3 enforces BadSwap. The first deployment, 0xe248b64ec6d842827ac01ff24332b9bdde1866d8, does not. Do not approve that address. Cancel any order still open on it.
Cancel
Only owner can call cancel. It sets cancelled. Parts already filled stay filled. A later execute reverts CancelledOrder.
Recurring is not this contract. It is a timer in the tab. Recurring.