fix(hooks): anchor HeavierHand to the pool's own price; make CapGate cap decimals-safe - #13
Merged
Merged
Conversation
…cap decimals-safe HeavierHand's skew gate compared the two virtual reserves, whose ratio is exactly 1/price (liquidity cancels), so it really tested the raw price against an implicit 1.0. Any pool not near a same-decimals 1:1 (USDC/WETH, or two 18-dec tokens at price 2.0) was permanently one-directional: one whole leg of trade reverted forever. Re-anchor to the pool's OWN sqrt price captured at afterInitialize (new flag 0x10C4) and gate the current price against that via sqrt-band thresholds (never squares a sqrt price, so no overflow at any drift). CapGate's MAX_TRADE = 100e18 was a raw token-unit cap: a no-op on any pool whose specified token had < 18 decimals, and wildly inconsistent across pairs. Replace with MAX_TRADE_BPS = 500 (5%) of the specified currency's virtual reserve - dimensionless and decimals-safe. - script/DeployFleet.s.sol: HeavierHand flag set adds AFTER_INITIALIZE. - test/fork/ForkDeploy.t.sol: same flag bump for HeavierHand. - test/fork/GateFix.t.sol: new Base-fork behavioral proof (a price-4 pool trades both legs; the gate engages symmetrically; CapGate's cap equals 5% of reserves and rejects oversize swaps). Redeployed across 7 chains (Base, Ethereum, Robinhood, Monad, Arbitrum, BNB, Unichain). New addresses supersede the prior deployments; registry and address-record updates follow separately.
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.
Summary
Fixes two hooks whose gates silently misbehaved on realistic pools, and redeploys both across all 7 chains. The HeavierHand issue is the serious one.
HeavierHand - was permanently one-directional off 1:1
The skew gate compared the two virtual reserves. Their ratio is exactly
1/price(liquidity cancels), so the gate was really comparing the pool's RAW price to an implicit1.0. Any pool that isn't a same-decimals pair near parity - a USDC(6d)/WETH(18d) pool sits ~8 orders of magnitude off; two 18-dec tokens at price 2.0 are already outside a 10% band - was permanently one-directional: one whole leg of trade reverted forever.Fix: capture the pool's OWN sqrt price at
afterInitializeand gate the current price against THAT, never1.0. Adds theafterInitializecallback, so flags go0xC4->0x10C4. The band test compares sqrt prices against precomputed sqrt-band edges (sqrt(1.1),sqrt(0.9)* 2^96) so it never squares a sqrt price and cannot overflow at any drift.CapGate - cap was decimals-blind
MAX_TRADE = 100e18was a raw token-unit cap: a no-op on any pool whose specified token had < 18 decimals (100e18 USDC-raw = 100 trillion), and wildly inconsistent across pairs. Replaced withMAX_TRADE_BPS = 500(5%) of the specified currency's virtual reserve - dimensionless and decimals-safe. Flags unchanged (0xC4). Adds amaxTradeSize()quoter.Tests
test/fork/GateFix.t.sol(new, Base fork, no cheatcodes): a HeavierHand pool opened at price 4.0 trades BOTH legs (the previously-dead leg swaps), and the gate engages symmetrically inside/beyond the band; CapGate's cap equals exactly 5% of the reserve and rejects an oversize swap while allowing one just under.test/fork/ForkDeploy.t.solHeavierHand flags bumped to0x10C4to match.Redeployment (new addresses, all verified live)
Redeployed HeavierHand + CapGate across Base, Ethereum, Robinhood, Monad, Arbitrum, BNB, Unichain. New CREATE2 addresses supersede the prior deployments (immutable; the old ones remain on-chain). Registry/marketplace records (
hooklist.json,hooks/*.json,HOOKS.md,DEPLOYMENTS.md, aeon.fun) and the "Audited" badge are handled in a separate follow-up.forge fmt --checkclean,forge buildclean.