Skip to content

Comments

add support for Algebra Integral v1.2/v1.2.1#43

Open
rouzwelt wants to merge 6 commits intorain-forkfrom
2026-02-13-algebra-integral-v1-2
Open

add support for Algebra Integral v1.2/v1.2.1#43
rouzwelt wants to merge 6 commits intorain-forkfrom
2026-02-13-algebra-integral-v1-2

Conversation

@rouzwelt
Copy link
Collaborator

@rouzwelt rouzwelt commented Feb 13, 2026

Motivation

This PR adds support for Algebra Integral v1.2 and v1.2.1 which are the same as Algebra Integral v1 and v1.1 but differ in 2 of its events with 1 item.
Hydrex is v1.2/v1.2.1 which is fixed in the PR.

Solution

Checks

By submitting this for review, I'm confirming I've done the following:

  • made this PR as small as possible
  • unit-tested any new functionality
  • linked any relevant issues or PRs
  • included screenshots (if this involves a front-end change)

Summary by CodeRabbit

  • New Features

    • Added support for Algebra Integral v1 and v1.2 protocols across multiple liquidity providers.
    • Pool objects expose tick and activeTick for more accurate routing.
  • Improvements

    • Smarter pool event processing with targeted tick/reserve refreshes after swaps (handles plugin-fee cases).
    • Adjusted log-fetching boundaries for more reliable incremental updates.
  • Tests

    • Updated and added tests covering Algebra Integral v1 and v1.2 variants.

@rouzwelt rouzwelt self-assigned this Feb 13, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 13, 2026

Warning

Rate limit exceeded

@rouzwelt has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 4 minutes and 47 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

Walkthrough

Renames the Algebra V2 base to AlgebraIntegralV1BaseProvider, adds AlgebraIntegralV1_2BaseProvider with ABI-driven event parsing and post-log reserve/tick refetch logic, migrates multiple liquidity providers to the new bases, and threads tick/activeTick through pool models and constructors.

Changes

Cohort / File(s) Summary
Base providers
packages/sushi/src/router/liquidity-providers/AlgebraIntegralV1Base.ts, packages/sushi/src/router/liquidity-providers/AlgebraIntegralV1_2Base.ts
Rename exported base to AlgebraIntegralV1BaseProvider; add AlgebraIntegralV1_2BaseProvider and AlgebraIntegralV1_2EventsAbi. v1.2 base includes ABI-driven event parsing, queuing of plugin-fee-affected pools, and post-log batch refetch of reserves/ticks.
Provider inheritance updates
packages/sushi/src/router/liquidity-providers/BladeSwap.ts, .../Fenix.ts, .../GlyphV4.ts, .../Horizon.ts, .../KimV4.ts, .../Scribe.ts, .../Swapsicle.ts
Update imports and change classes to extend AlgebraIntegralV1BaseProvider (previously AlgebraV2BaseProvider); no other logic changes.
Hydrex provider
packages/sushi/src/router/liquidity-providers/Hydrex.ts
Switch import and inheritance to AlgebraIntegralV1_2BaseProvider to opt into v1.2 event parsing and post-log refresh behavior.
Pool data model additions
packages/sushi/src/router/liquidity-providers/UniswapV3Base.ts, packages/sushi/src/router/rain/AlgebraV1Base.ts, packages/sushi/src/router/rain/UniswapV3Base.ts, packages/sushi/src/router/rain/VelodromeSlipstreamBase.ts
Add tick property to pool objects (populated from slot0/globalState) and pass it into downstream constructors where applicable.
Core pool classes
packages/sushi/src/tines/RPool.ts, packages/sushi/src/tines/UniV3Pool.ts
RPool: add optional tick and activeTick fields and constructor params. UniV3Pool: constructor now requires activeTick and accepts optional tick; assigns both and uses activeTick when computing nearestTick.
Rain data fetcher and tests
packages/sushi/src/router/rain/RainDataFetcher.ts, packages/sushi/src/router/rain/RainDataFetcher.test.ts
Adjust log-slice boundary handling to use an exclusive upper bound for fetchLogs; rename protocol key algebraalgebraV1 and add algebraV1_2 test case.

Sequence Diagram(s)

sequenceDiagram
    participant Logs as Logs (incoming)
    participant Provider as AlgebraIntegralV1_2BaseProvider
    participant RPC as RPC / Multicall
    participant Pools as Pool Store

    rect rgba(200,200,255,0.5)
    Logs->>Provider: deliver logs (Swap/Mint/Burn/Flash/...)
    end

    rect rgba(200,255,200,0.5)
    Provider->>Provider: parse logs -> identify affected pools & plugin-fee-updated pools
    Provider->>RPC: batch fetch reserves + ticks for affected pools
    RPC-->>Provider: return reserves + ticks
    Provider->>Pools: update pool objects (reserves, ticks, liquidity, sqrtPriceX96, activeTick)
    Provider->>Provider: enqueue/process pending tick updates as needed
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

  • indexer extension #32: Touches Algebra base provider definitions and provider inheritance/imports; overlaps with renames and provider migrations in this PR.
  • Hydrex #42: Modifies Hydrex provider; related due to Hydrex migration to the v1.2 base in this PR.

Suggested labels

new feature

Suggested reviewers

  • hardyjosh
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'add support for Algebra Integral v1.2/v1.2.1' clearly and concisely describes the main objective of the PR, which is to add support for these new Algebra Integral versions.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 2026-02-13-algebra-integral-v1-2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@rouzwelt rouzwelt requested a review from hardyjosh February 13, 2026 00:58
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/sushi/src/router/liquidity-providers/UniswapV3Base.ts (1)

383-394: 🧹 Nitpick | 🔵 Trivial

Consider passing pool.tick to the UniV3Pool constructor for consistency with the Rain path.

The Rain UniswapV3Base.ts (line 231–232) passes undefined, pool.tick as the last two args to UniV3Pool, but this non-Rain call site omits them. Since tick is optional on the constructor, this compiles fine and this.tick will be undefined on the resulting pool instance.

If no downstream code in the non-Rain path reads UniV3Pool.tick, this is acceptable. Otherwise, consider passing it:

♻️ Optional: pass tick for consistency
       const v3Pool = new UniV3Pool(
         pool.address,
         pool.token0 as RToken,
         pool.token1 as RToken,
         pool.fee / 1_000_000,
         balance0,
         balance1,
         pool.activeTick,
         liquidity,
         pool.sqrtPriceX96,
         poolTicks,
+        undefined,
+        pool.tick,
       )
packages/sushi/src/router/rain/UniswapV3Base.ts (1)

633-658: ⚠️ Potential issue | 🟡 Minor

pool.tick is not updated in the Swap event handler, causing staleness.

When a Swap event is processed, pool.activeTick is recalculated from the event's tick (line 645–646), but pool.tick (the raw tick) is never updated. After a swap, pool.tick retains its initial value from fetchPoolData.

Since getCurrentPoolList (line 232) passes pool.tick to the UniV3Pool constructor, subsequent pool list constructions will use a stale raw tick. While this.tick isn't used in UniV3Pool's swap calculations (only nearestTick and activeTick matter), it's a data consistency gap.

🔧 Suggested fix
             if (tick !== undefined) {
+              pool.tick = tick
               pool.activeTick =
                 Math.floor(tick / pool.tickSpacing) * pool.tickSpacing
🤖 Fix all issues with AI agents
In `@packages/sushi/src/tines/RPool.ts`:
- Around line 55-56: The parameter types for tick and activeTick are
inconsistent: change the signature that declares activeTick?: number | undefined
to use the same optional shorthand activeTick?: number for consistency; locate
the function/constructor in RPool (symbol names around tick and activeTick) and
replace the verbose union type with the concise optional number type.
- Around line 43-44: The RPool base type defines tick?: number | undefined and
activeTick?: number | undefined which are specific to concentrated-liquidity
pools; move these properties out of RPool into the concentrated pool subtype
(e.g., the Concentrated or ConcentratedRPool class/interface) so only
concentrated pools carry them, or if you intentionally want them on every RPool
add a clarifying comment explaining that decision; also simplify the types by
removing the redundant "| undefined" since the optional marker already implies
undefined (change definitions like tick?: number).

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/sushi/src/router/rain/RainDataFetcher.ts (1)

344-358: ⚠️ Potential issue | 🟡 Minor

Intermediate slice overlap fix is correct, but same-block re-call now throws instead of returning false, and a one-block processing lag is introduced.

The +1n / -1n pairing correctly converts the exclusive upper bound to an inclusive RPC argument. For intermediate slices this fixes a pre-existing overlap bug: before, consecutive slices covered [S, S+5n] and [S+5n, S+10n] (6 blocks each, overlapping at the boundary); now they cover [S, S+4n] and [S+5n, S+9n] (5 non-overlapping blocks each) ✓.

However, storing untilBlock + 1n in blockNumberSlices propagates forward: when all slice promises settle, the result-processing loop at line 379 reassigns untilBlock = blockNumberSlices[last] = original_untilBlock + 1n, and line 418 then sets pool.blockNumber = original_untilBlock + 1n.

This creates two issues:

  1. Throw regression — After a successful updatePools(N), a subsequent call with the same argument has fromBlock = N + 1n > N = untilBlock, which falls through to the throw guard at line 327. Previously fromBlock === N === untilBlock was caught by the graceful early return at line 326. While this may not occur in typical sequential usage (where blocks always increment), it's a semantic regression for edge cases.

  2. One-block processing lag — Calling updatePools(N + 1n) immediately after results in fromBlock = N + 1n = untilBlock, hitting the early-return on line 326 (and while condition N+1n < N+1n is also false). Block N+1's events are not processed until updatePools(N + 2n) is called. If this lag is intentional per the "fix reserve sync" commit message, it should be documented; otherwise, the boundary logic needs adjustment.

For issue 1, the equality check should widen to handle re-processed case:

-    if (fromBlock === untilBlock) return false
+    if (fromBlock >= untilBlock) return false

For issue 2, clarify whether the one-block lag is intentional given the commit message context.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/sushi/src/router/rain/RainDataFetcher.ts` around lines 344 - 358,
blockNumberSlices is storing the exclusive upper bound (toBlock = untilBlock +
1n) which later causes pool.blockNumber to be bumped by +1 and triggers the
"fromBlock > untilBlock" throw in updatePools; fix this by pushing the inclusive
upper bound into blockNumberSlices (push toBlock - 1n instead of toBlock) so
later result-processing and pool.blockNumber use the original untilBlock, and
also relax the early-return/throw logic in updatePools (the guard around
fromBlock/ untilBlock) to treat fromBlock === untilBlock as a no-op/non-throw
case (i.e. return false or handle gracefully) to avoid the regression when the
same block is re-requested.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/sushi/src/router/liquidity-providers/AlgebraIntegralV1_2Base.ts`:
- Around line 189-191: The loop variable in the for...of over newTicks shadows
the outer variable tick (from event.args); rename the inner loop variable (e.g.,
newTick or candidateTick) in the block that pushes into queue[1] to avoid
shadowing and update any references inside that loop (see the for (const tick of
newTicks) block in AlgebraIntegralV1_2Base.ts).
- Around line 179-180: The code compares overrideFee and pluginFee to 0n without
undefined guards, which can throw if either is undefined; update the event
handler that destructures event.args so you first check overrideFee !==
undefined and pluginFee !== undefined (or coerce undefined to 0n) before doing
any BigInt comparison, and only call this.onSwapPluginFeeUpdatePools.push(pool)
when the guarded comparison confirms a value > 0n; reference the overrideFee and
pluginFee variables and the this.onSwapPluginFeeUpdatePools.push(pool) call when
making the change.
- Around line 160-198: The Swap branch currently skips updating pool.activeTick
when a plugin fee is present; always update pool.activeTick whenever tick !==
undefined regardless of overrideFee/pluginFee, then keep the onPoolTickChange()
call and newTicksQueue logic gated only to the no-plugin-fee path (so the lazy
tick loading remains unchanged); modify the Swap case in AlgebraIntegralV1_2Base
(referencing pool.activeTick, onPoolTickChange, onSwapPluginFeeUpdatePools, and
newTicksQueue) to set pool.activeTick = Math.floor(tick / pool.tickSpacing) *
pool.tickSpacing whenever tick is defined, and only push to
onSwapPluginFeeUpdatePools or run onPoolTickChange/newTicksQueue per the
existing fee check.
- Around line 5-29: The override for the eventsAbi property in
AlgebraIntegralV1_2BaseProvider should match the parent class' typing
pattern—change the assignment to use the AlgebraIntegralV1_2EventsAbi value cast
to any (i.e., set eventsAbi = AlgebraIntegralV1_2EventsAbi as any) so it aligns
with AlgebraIntegralV1BaseProvider and other providers; update the eventsAbi
override in the AlgebraIntegralV1_2BaseProvider class to use the as any cast
referencing AlgebraIntegralV1_2EventsAbi.

---

Outside diff comments:
In `@packages/sushi/src/router/rain/RainDataFetcher.ts`:
- Around line 344-358: blockNumberSlices is storing the exclusive upper bound
(toBlock = untilBlock + 1n) which later causes pool.blockNumber to be bumped by
+1 and triggers the "fromBlock > untilBlock" throw in updatePools; fix this by
pushing the inclusive upper bound into blockNumberSlices (push toBlock - 1n
instead of toBlock) so later result-processing and pool.blockNumber use the
original untilBlock, and also relax the early-return/throw logic in updatePools
(the guard around fromBlock/ untilBlock) to treat fromBlock === untilBlock as a
no-op/non-throw case (i.e. return false or handle gracefully) to avoid the
regression when the same block is re-requested.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/sushi/src/router/liquidity-providers/AlgebraIntegralV1_2Base.ts`:
- Around line 34-71: The bug is that this.onSwapPluginFeeUpdatePools is not
snapshotted before awaiting async fetches, so pools pushed during the awaits are
lost when the array is later cleared; fix by creating a local snapshot (e.g.,
const poolsSnapshot = [...this.onSwapPluginFeeUpdatePools.splice(0)] or
slice(0)) at the top of the flow and use poolsSnapshot when calling
getReserves/getTicks and iterating/assigning results (replace references to
this.onSwapPluginFeeUpdatePools in the getReserves/getTicks calls and the result
loop with poolsSnapshot), then clear only any remaining items from the original
this.onSwapPluginFeeUpdatePools or push back items that failed to fetch,
mirroring the newTicksQueue pattern used with getTicksInner.

In `@packages/sushi/src/router/rain/UniswapV3Base.ts`:
- Around line 231-232: The call passing a positional undefined into the
UniV3Pool constructor (the argument immediately before pool.tick) is unclear;
update the call site to clarify that this is the optional nearestTick parameter
— e.g., replace the bare undefined with an inline comment "undefined, //
nearestTick" or refactor the UniV3Pool constructor to accept an options object
and pass { nearestTick: undefined } (or the actual value) so the intent is
explicit; locate the invocation where pool.tick is passed and adjust the
argument there or change the UniV3Pool signature and all call sites accordingly.

---

Duplicate comments:
In `@packages/sushi/src/router/liquidity-providers/AlgebraIntegralV1_2Base.ts`:
- Line 179: The Swap handler currently compares overrideFee and pluginFee
directly to 0n which can throw if they are undefined; before any mutations to
pool (reserve0/reserve1/sqrtPriceX96/liquidity/activeTick) add undefined guards
for overrideFee and pluginFee (e.g., check !== undefined like the other
destructured event.args fields) and only perform the BigInt comparisons or treat
undefined as 0n after validation, ensuring you validate both values first and
bail or skip fee logic so the pool state is not mutated when these args are
missing.
- Around line 202-204: The loop in which "for (const tick of newTicks)" reuses
the name tick already destructured from event.args, causing variable shadowing;
rename the loop variable (e.g., newTick or pushedTick) in the block that pushes
into queue[1] and update any references inside that loop accordingly so it no
longer shadows the outer tick variable used elsewhere in the function (refer to
newTicks, queue, and the earlier event.args destructured tick).
- Line 29: The override of eventsAbi in AlgebraIntegralV1_2Base is too strictly
typed, causing parseEventLogs to infer event.args fields (e.g., overrideFee,
pluginFee) as bigint | undefined; fix it by casting the override to any like
other providers — change the declaration that sets AlgebraIntegralV1_2EventsAbi
in AlgebraIntegralV1_2Base (the eventsAbi override) to use an explicit `as any`
cast so parseEventLogs and usages of event.args (overrideFee, pluginFee) get the
expected bigint types.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/sushi/src/router/liquidity-providers/AlgebraIntegralV1_2Base.ts`:
- Around line 79-80: Remove the redundant non-null assertion on the result of
this.pools.get by changing the declaration of pool in AlgebraIntegralV1_2Base
(currently: const pool = this.pools.get(logAddress)!) to not use '!' so the
subsequent if (pool) guard is meaningful; in short, replace the asserted lookup
with a nullable one (const pool = this.pools.get(logAddress)) and keep the
existing if (pool) branch unchanged.

---

Duplicate comments:
In `@packages/sushi/src/router/liquidity-providers/AlgebraIntegralV1_2Base.ts`:
- Around line 28-29: The eventsAbi override in AlgebraIntegralV1_2BaseProvider
lacks the same type-cast used elsewhere causing TypeScript errors; update the
override to cast AlgebraIntegralV1_2EventsAbi with "as any" (matching the
pattern used in AlgebraIntegralV1BaseProvider and PancakeSwapV3Provider) so the
property signature aligns with consumers of this.eventsAbi; locate the override
on the AlgebraIntegralV1_2BaseProvider class and change the assignment of
eventsAbi to use the as any cast for AlgebraIntegralV1_2EventsAbi.
- Around line 33-71: The code is dropping pools added to
onSwapPluginFeeUpdatePools during awaiting of getReserves/getTicks; mirror the
newTicksQueue pattern by taking an atomic snapshot at the start (e.g. const
poolsSnapshot = [...this.onSwapPluginFeeUpdatePools.splice(0)]) and use
poolsSnapshot for the multicall inputs, for awaiting results, and for the
subsequent loop (replace references to this.onSwapPluginFeeUpdatePools with
poolsSnapshot) so pools pushed by handlePoolEvents during awaits are not lost;
finally, do not unconditionally clear this.onSwapPluginFeeUpdatePools (leave it
intact for new entries) — only clear or repush items from the snapshot as
needed.
- Line 179: Guard against undefined for event.args.pluginFee and
event.args.overrideFee before performing BigInt comparisons to avoid partial
pool updates; e.g., read const pluginFeeRaw = event.args.pluginFee and const
overrideFeeRaw = event.args.overrideFee, coerce with nullish fallback (pluginFee
= pluginFeeRaw ?? 0n, overrideFee = overrideFeeRaw ?? 0n) or explicitly check
(pluginFeeRaw !== undefined && pluginFeeRaw > 0n) before mutating the pool
state, then use those safe values in the existing pool-state mutation block and
subsequent logic so no mutations occur based on undefined values.

In `@packages/sushi/src/router/rain/UniswapV3Base.ts`:
- Around line 231-232: The positional bare undefined used for the nearestTick
argument when calling the constructor (the parameter before pool.tick) is
unclear and fragile; replace that bare undefined with an explicit placeholder
accompanied by an inline comment clarifying it is the nearestTick argument (or,
alternatively, pass a properly named variable/constant like nearestTick) so
future readers and refactors understand the intent in the call site in
UniswapV3Base (the parameter immediately preceding pool.tick).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants