Repository navigation
feat(automation): generic Uniswap v4 liquidity module + OUSD/USDe one-tick Kyber pricing - #3036
Merged
Merged
Conversation
…ne-tick Kyber pricing Add UniswapV4LiquidityModule (deploy 010), a Safe module that burns a Safe position, optionally resets the pool price and mints a new Safe position on any hookless pool the Safe allowed. It holds no pricing logic: per-call and per-day caps (net outflow of each token from the Safe), the pool allowlist and a pause are all set by the Safe, so a pricing change never needs a redeploy. Add the ousdUsdeV4Rebalance Talos action: every 2 minutes it keeps the OUSD/USDe position on one tick just above the KyberSwap bid (+1 bp, divided by the OUSD exit rate), capped at par - 4 bp in ticks, pulls fills before bots can buy them back and follows the market down during a depeg. It replaces ousdV4Rebalance on that pool; the schedule is seeded disabled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y cap Remove what the per-token daily cap already covers: the pool allowlist (a hookless check stays in rebalance), maxPerCall, the pause (the Safe disables the module instead), the inflow credit on the daily counter, the convenience views and the redundant constructor checks. Talos now reads spentOn/maxPerDay and the pool price from the PoolManager itself. The reset in both directions and amount1Max stay, so pricing changes still need no redeploy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… is burned The module burned the OUSD/sUSDe position 457274 on Oct 15 2026, so these fork and smoke tests fail with NOT_MINTED on any recent block. Module 009 is due for a revamp, so they skip instead of tracking the current token id. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uote ousdUsdeV4Rebalance now caps the bid at min(par, Ethena RFQ redeem rate) less --cap-bps instead of par less --cap-bps, so an Ethena fee regime moves the bid down with it. Without a quote the cap falls back to par. The run warns to hold the bought USDe while a redemption costs more than --max-redeem-cost-bps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With the cap now below the Ethena redemption quote, Ethena's ~1 USDC flat fee (0.2 bp on 50k) pushed the calm-market range from tick 4 to tick 5 at a 4 bp margin. 3 bp keeps it on tick 4. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The OUSD/USDe v4 position (
[0, 5], module 008, keeper every 30 min) has made about $0 since launch. The pool is fee 0 and the position stays two-sided between pulls, so bots buy back almost everything it buys at the same price (Oct 13–18: 125k USDe bought, 114k bought back). Its first tick also sits at par, so arbitrageurs fill it with no margin.We are changing the pricing to one tick, re-ranged every 2 minutes on the KyberSwap bid (+1 bp), capped 3 bp below what Ethena pays to redeem USDe, and following the market down during a depeg. Module 008 cannot move its range, so a new module is needed. Design decision: the module holds no pricing logic (no floor, NAV or tick bounds); Talos owns pricing, so future pricing changes (or new tokens) never need a redeploy.
Backtest at the Safe's current capital (~$50k), Safe-only P&L: ≈ $2.1k/yr over 13.5 months (vs $1.0k for a static
[4, 5]and −$1.3k for the current[0, 5]). No difference over the last 60 days (no depeg). Analysis: private page shared separately.What
The pricing model in one picture
We want to buy USDe with OUSD as cheaply as possible, while still being the best bid on the market so sellers come to us.
Every 2 minutes, Talos:
In short, we are the best bid by 1 bp, but never above 3 bp under what we can redeem the USDe for. Two rules make it profitable:
[0, 5]position stays two-sided for 30 minutes, so bots sell us USDe and buy it straight back at the same price.Without a market quote, Talos keeps the current tick and only pulls fills. Without an Ethena quote, the cap is taken from par. When a redemption costs more than 2 bp, the run warns to hold the USDe until the quote is back to normal. Redemption itself is still manual.
UniswapV4LiquidityModule(deploy010): the executorThe module does not price anything. It does what Talos asks in one call,
rebalance(params): burn the Safe's position, optionally swap the pool price back down to the new range, then mint the new Safe position. Its guardrails only protect funds:maxPerDay[token], set by the Safe, bounds the Safe's net outflow of each token per UTC day (200k OUSD initially).Since all pricing lives in Talos, a pricing change never needs a redeploy. The module has no pool allowlist, per-call cap or pause: the daily cap and
disableModulealready cover those. Accepted residual risk: a compromised operator can buy at a bad price, bounded bymaxPerDay.ousdUsdeV4RebalanceTalos action (cron*/2, seeded disabled)Implements the model above. Every number is a flag that can be changed from the Talos UI:
--offset-bps--cap-bps--quote-size/--exit-size--redeem-size--max-redeem-cost-bps--min-token1--max-drift--target-ousdNew shared helper:
tasks/lib/v4Liquidity.ts(position math).Core contracts
No change to the Vault, OTokens, Morpho or the Curve AMO. The module sits on the OUSD v4 liquidity Safe (
0x13eb…eB26). No governance proposal.Deploy and Safe steps (simulated in
010._fork())make deploy-mainnet(010).enableModule,setMaxPerDay(OUSD, 200k). The OUSD → Permit2 → PositionManager approvals already exist from 008/009.ousdUsdeV4Rebalance --dryrun, then disableousd_v4_rebalanceand enableousd_usde_v4_rebalance; then the Safe runsdisableModule(008).457273over (burn + mint at tick 4).Talos impact (CLAUDE.md checklist)
UniswapV4LiquidityModuleonly. The descriptordeployments/mainnet/UniswapV4LiquidityModule.jsonis written bymake deploy-mainnetand read by the new action.ousdV4Rebalance(module 008 descriptor) is to be disabled, not changed.abi/*.jsonchange; no pinned address added.--cap-bps,--offset-bps,--exit-size,--redeem-size,--max-redeem-cost-bps) are whitelisted in oplabs/talos#56.ethena_rfq_price) for the cap only.Tests
FORK_BLOCK_NUMBER_MAINNET=26220000): takeover to[4, 5], fill then pull, follow the market down to[30, 31], daily cap revert. Note: a tiny third-party LP sits in the pool between ticks 0 and 4.tasks/test/ousd-usde-v4-rebalance.js); fullpnpm test:tasks150 passing; full unit suite 2322 passing.vm.skiponce that position is burned (it was on Oct 15; module 009 is due for a revamp).🤖 Generated with Claude Code