Twin Documentation
  • Overview
  • Consumer
  • Developer
  • Operations
Arquitectura
Flujos Técnicos
    Minting & RedeemBridge Cross-chainUniswap V4 Liquidity ManagementOracle Price UpdatesAuto-RebalanceRewardsAuthentication (Platform)Circulation ManagementDisperse (Batch Transfer)Market Data PipelineSupply API (CoinGecko)Contract Data CollectionCron Jobs: Flujos Detallados
Base de Datos
Local SetupConventions
powered by Zudoku
Flujos Técnicos

Auto-Rebalance

Cron UNISWAP_AUTO_REBALANCE monitors Uniswap V4 positions and rebalances when the pool price diverges from the oracle price.

Overview

The auto-rebalance cron compares the current Uniswap V4 pool price against the Twin oracle price. When the deviation exceeds a configurable threshold and the oracle price falls outside the position's range, it triggers a rebalance: remove all liquidity, then mint a new position centered on the oracle price.


Bot Parameters

Each Uniswap wallet has configurable bot parameters:

ParameterTypeDescription
enabledbooleanWhether auto-rebalance is active for this wallet
priceBandPercentnumberRange width: oracle price +/- N% (e.g. 5 = +/-5%)
rebalanceTriggerPercentnumberDeviation threshold to trigger rebalance (e.g. 3 = 3%)
maxBudgetToken0stringMax amount of token0 (USDC) to deploy (base units)
maxBudgetToken1stringMax amount of token1 (ARGT) to deploy (base units)

Cron Decision Flowchart

Decision Logic Summary

Rebalance triggers when ALL of these are true:

  1. deviation > rebalanceTriggerPercent (OR liquidity = 0 for recovery)
  2. Oracle price is outside the current position's tick range
  3. No pending transaction exists for this wallet (concurrent guard)

Rebalance Sequence


Six Guards

The auto-rebalance has six protective mechanisms:

#GuardPurpose
1Oracle-in-rangeSkip rebalance if oracle price is still within position's tick range, even if pool price has deviated. Prevents unnecessary churn.
2Liquidity = 0 bypassIf position has zero liquidity (failed remove, manual intervention), force rebalance without the deviation check. Recovery mode.
3Concurrent execution guardCheck for pending TX on this wallet before triggering. Prevents overlapping on-chain operations that would cause nonce conflicts.
4Same-RPC balance readAfter remove TX, read balances from the same confirmed RPC used for the receipt. Prevents reading stale balances from a different RPC that hasn't indexed the block yet.
5maxBudget as capamount = min(walletBalance, maxBudget). The maxBudget is a risk cap, not a fixed amount. If balance < maxBudget, use everything available. If balance > maxBudget, cap at maxBudget. Prevents TRANSFER_FROM_FAILED when maxBudget exceeds actual balance after remove.
6No poolState fallbackUses live getPoolState for sqrtPriceX96 instead of a cached/computed value. The pool state may have changed between remove and mint due to other traders.

Balance Handling Detail

Without this pattern, if maxBudgetToken0 = 1000 USDC but the wallet only has 800 USDC after the remove, the mint TX would revert with TRANSFER_FROM_FAILED.


Tick Calculation

New position ticks are calculated from the oracle price with the configured band:

Code
priceLower = oraclePrice * (1 - priceBandPercent / 100) priceUpper = oraclePrice * (1 + priceBandPercent / 100) tickLower = priceToTick(priceLower) // aligned with Math.floor (extends range down) tickUpper = priceToTick(priceUpper) // aligned with Math.ceil (extends range up)

Example with oracle price = 1466.5 ARGT/USDC, band = 5%:

Code
priceLower = 1466.5 * 0.95 = 1393.175 priceUpper = 1466.5 * 1.05 = 1539.825 tickLower = alignTickToSpacing(priceToTick(1393.175), FLOOR) tickUpper = alignTickToSpacingCeil(priceToTick(1539.825), CEIL)

Troubleshooting

SymptomCauseSolution
Rebalance never triggersrebalanceTriggerPercent too high or enabled: falseLower trigger percent, verify bot is enabled
"Calculated liquidity is zero"Both token balances are 0 after remove, or price completely out of range with insufficient single-side tokenCheck wallet balances, verify remove TX completed
TRANSFER_FROM_FAILED on mintApproval amounts don't include slippage bufferVerify slippage: amount * (10000 + bps) / 10000 on both desired amounts and approvals
Rebalance skipped: "oracle in range"Oracle price is within position ticks despite pool price deviationExpected behavior -- oracle is a better price reference than pool. Wait for oracle to move or adjust position manually
Rebalance skipped: "pending TX"Previous rebalance still in progressWait for pending TX to complete or fail. Check waitForReceipt timeout (20 x 5s = 100s)
Stale balances after removeReading balance from different RPC than receipt confirmationBug -- must use same confirmedRpcUrl. Check waitForReceipt return value
Position has 0 liquidity but no rebalanceWallet missing BitGo fields (bitgoWalletId, bitgoCoin, passphraseEncrypted)Update wallet config with BitGo credentials
Nonce conflict / duplicate TXConcurrent execution guard failedCheck for race condition in DB pending TX query. Ensure markJobAsRunning is set
Wrong tick alignment (~1.7% off)Using floor for both ticksUpper tick must use Math.ceil (alignTickToSpacingCeil)
Asymmetric deposit ratioExpected -- concentrated liquidity ratio depends on price position within rangeNot a bug. The ratio only equals spot price at range midpoint

Testing

To test the auto-rebalance without waiting for natural price divergence:

  1. Temporarily lower rebalanceTriggerPercent to a small value (e.g. 0.1)
  2. Go to Cron Jobs in dashboard
  3. Execute UNISWAP_AUTO_REBALANCE on-demand
  4. Monitor the TX in the Uniswap pools page
  5. Restore rebalanceTriggerPercent to production value

Cron Configuration

FieldValue
KeyUNISWAP_AUTO_REBALANCE
Registered incron-keys.ts, manager.ts, cron-handlers.ts
Wallet filterbot.enabled AND positionNftId AND bitgoWalletId AND bitgoCoin AND passphraseEncrypted
Error behaviorSets lastError on job, auto-clears on next success
Last modified on May 12, 2026
Oracle Price UpdatesRewards
On this page
  • Overview
  • Bot Parameters
  • Cron Decision Flowchart
    • Decision Logic Summary
  • Rebalance Sequence
  • Six Guards
  • Balance Handling Detail
  • Tick Calculation
  • Troubleshooting
  • Testing
  • Cron Configuration