AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

V4 Hook Delta Accounting

skill-omermaksutii-rugproof-v4-hook-delta-accounting · by omermaksutii

Detect Uniswap V4 hooks that fail to settle currency deltas with the PoolManager. Every credit/debit a hook creates (BeforeSwapDelta, afterSwap hookDelta, take/mint, donate, settle/sync) is tracked in the manager's transient nonzeroDeltaCount; if the books aren't flat when unlock returns, the whole transaction reverts (CurrencyNotSettled), and mismatched take/settle/donate either strands hook fun…

No reviews yet
0 installs
20 views
0.0% view→install

Install

$ agentstack add skill-omermaksutii-rugproof-v4-hook-delta-accounting

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-omermaksutii-rugproof-v4-hook-delta-accounting)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of V4 Hook Delta Accounting? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Uniswap V4 hook delta-accounting detection

When this applies

Trigger on any of:

  • Callbacks returning BeforeSwapDelta or a non-zero int128 hookDelta from afterSwap/afterAddLiquidity/afterRemoveLiquidity
  • Calls to poolManager.take, settle, sync, mint, burn, donate, clear
  • Custom unlockCallback that moves currency in/out of the manager
  • Hooks that charge custom fees, skim, or rebate by adjusting deltas
  • currencyDelta reads, or accounting that must net to zero before unlock returns
  • Donations to a pool, or take/settle pairs that should balance

Detection patterns

Hook takes currency but never settles (HIGH)

function afterSwap(address, PoolKey calldata key, ..., BalanceDelta, bytes calldata)
    external override returns (bytes4, int128)
{
    poolManager.take(key.currency0, address(this), feeAmount);  // ← creates a -debt for the hook
    return (this.afterSwap.selector, 0);                         // ← returns 0 delta, never settles
}

take debits the hook's currency balance in the manager; with no matching settle/returned delta, nonzeroDeltaCount != 0 and the entire unlock reverts CurrencyNotSettled — every swap on the pool reverts. Signal: take/mint without a balancing settle/burn or a non-zero returned hookDelta accounting for it.

Returned delta not backed by a real transfer (HIGH)

return (this.afterSwap.selector, int128(feeAmount));   // claims to owe the pool feeAmount...
// ...but the hook never `sync` + `settle`s those tokens into the manager

A positive hookDelta says "the hook owes the pool X"; if the hook never actually transfers and settles X, the books don't flatten → revert, or in the inverse direction the swapper leaves with unpaid debt. Signal: non-zero returned delta with no corresponding sync/settle (or take) of the same currency/amount.

Donate / take imbalance (HIGH)

poolManager.donate(key, amount0, amount1, "");  // adds to pool reserves...
// hook forgot to settle the donated tokens it owes

donate increases what the hook owes the pool; the tokens must be settled. Imbalanced donate strands funds or reverts. Signal: donate without settling the donated amounts, or take of donated funds with no offsetting credit.

BeforeSwapDelta sign/units error (HIGH)

BeforeSwapDelta d = toBeforeSwapDelta(int128(amtSpecified), 0);  // wrong: specified vs unspecified swapped

BeforeSwapDelta packs (specified, unspecified) deltas; swapping the two halves or the sign mis-accounts the swap and either reverts or hands the swapper free output. Signal: toBeforeSwapDelta arguments in the wrong slot/sign, or specified-delta not reconciled with the actual swap amount.

Severity rubric

| Pattern | Severity | Notes | |---|---|---| | take/mint with no matching settle → CurrencyNotSettled | High | Pool-wide swap DoS | | Returned hookDelta not backed by settle → revert or free funds | High | Loss or DoS | | Donate without settling owed tokens | High | Stranded funds / revert | | BeforeSwapDelta sign/slot error | High | Mis-accounted swap, value leak | | Hook over-settles (pays more than owed) | Medium | Hook self-loss, no swapper gain | | Deltas always net to zero within callback | Info | Correct accounting |

Remediation patterns

  1. Net every delta to zero before unlock returns — for each currency the hook touches, pair take with settle (or a correct returned hookDelta).
  2. sync → transfer → settle — call poolManager.sync(currency), transfer the tokens in, then settle() so the manager credits the exact owed amount.
  3. Use the official delta helperstoBeforeSwapDelta(specified, unspecified) with correct argument order and signs; reconcile specified against params.amountSpecified.
  4. Assert flatness in tests — after a swap, assert poolManager.currencyDelta(hook, currency) == 0 for every currency.
  5. Settle donations — every donate must be followed by transferring + settling the donated amounts.

False-positive notes

  • A hook returning BeforeSwapDeltaLibrary.ZERO_DELTA / 0 hookDelta and never calling take/settle/donate has nothing to settle — Info.
  • Settlement done inside a shared internal helper called at the end of the callback may look unbalanced locally — trace the full callback before flagging.
  • Over-settling (hook pays extra) is a hook self-loss, not a protocol-loss — Medium, not High.

Related

  • [[v4-hook-permission-flags-mismatch]] — returnDelta flags must be set for deltas to apply
  • [[v4-hook-reentrancy-via-unlock]] — settlement ordering vs. reentrancy
  • [[unchecked-calls]]

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.