Job

3675b9ccDeploying

Release Breaker (token symbol CBRK) on Sepolia as a univ4_hook launch.

Token: Breaker (CBRK), total supply 1,000,000,000 CBRK with 18 decimals, minted once to the deployer (a separate zero-argument ERC-20, no mint, owner or admin).

Hook: CircuitBreakerHook, a Uniswap v4 hook on the token's native-ETH pool that trips on sharp moves within a block. beforeSwap: if refBlock[poolId] != block.number, store refBlock = block.number and refSqrtPrice = the current sqrtPriceX96 …

the approved task

Approved workflow

Release Breaker (token symbol CBRK) on Sepolia as a univ4_hook launch. Token: Breaker (CBRK), total supply 1,000,000,000 CBRK with 18 decimals, minted once to the deployer (a separate zero-argument ERC-20, no mint, owner or admin). Hook: CircuitBreakerHook, a Uniswap v4 hook on the token's native-ETH pool that trips on sharp moves within a block. beforeSwap: if refBlock[poolId] != block.number, store refBlock = block.number and refSqrtPrice = the current sqrtPriceX96 (StateLibrary.getSlot0), the price before the block's first swap, and emit ReferenceSet(poolId, block, sqrtPriceX96). afterSwap: read the new sqrtPriceX96 and revert with Tripped(refSqrtPrice, newSqrtPrice) when the price (sqrtPrice squared) is more than 10% above or below the reference: the allowed band is refSqrt x sqrt(0.9) <= newSqrt <= refSqrt x sqrt(1.1), computed with FullMath.mulDiv against Q96 constants for sqrt(0.9) and sqrt(1.1), rounded inward so the band never exceeds 10%. This includes a block's first swap, so any single swap moving the price more than 10% reverts and large trades must be split across blocks. Liquidity changes and donations do not move the price and are never checked. No deltas, fee, funds or admin. Tripped swaps revert, so they leave no event; the site simulates instead. Deploy shape, matching the live Sepolia hook launches 170 and 186 (168 passed the mainnet PoolManager and is not a model): CircuitBreakerHook's only constructor argument is the Sepolia PoolManager 0xE03A1074c86CFeDd5C142C4F04F1a1536e203543; every rate, window and threshold here is a source constant; there is no owner, admin, setter, pause, upgrade or sweep, and no $owner or $token argument. Permissions are exactly beforeSwap, afterSwap (low address bits 0x00C0), all others false; the constructor calls Hooks.validateHookPermissions and the CREATE2 salt is mined for those bits. The factory initializes the pool (currency0 native ETH, currency1 CBRK, fee 3000, tickSpacing 60) and seeds one-sided CBRK liquidity, so nothing in the hook may revert that initialize or that liquidity add (launch 138 was parked when a beforeInitialize gate reverted the factory), and the first buy lands in a pool that holds no ETH. All state is keyed by PoolId; a pool on this hook whose currency0 is not native ETH gets zero deltas and no other effect. Every callback requires msg.sender == PoolManager. Tests (Foundry, a real v4-core PoolManager deployed in the test, hook at a mined address): a launch rehearsal that initializes at the manifest price, seeds one-sided CBRK liquidity like the factory and makes the first buy into the ETH-less pool; exact-in and exact-out in both directions; dust amounts; a pool whose currency0 is not ETH; direct callback calls from a non-PoolManager address revert; fuzzed sizes; and specifically: a 9.9% move passes and 10.1% reverts, up and down; two swaps in one block that together pass 10% make the second revert; a swap back inside the band passes; a new block resets the reference; on the freshly seeded pool a small first buy passes and an oversized one reverts. An independent adversarial review (read-only) must attack: the sqrt constants and rounding direction, overflow in the band maths, that the reference is captured before any swap including the first, any same-block path that moves the price without reaching afterSwap, and griefing (pushing the price to the band edge to block others for a block; document it). It reports each finding with the exact call sequence that triggers it. Website: one static page (dist/index.html) that reads the hook's views and events and the pool price through Uniswap's Sepolia StateView, with a buy/sell form that swaps through Uniswap's published Sepolia PoolSwapTest router (check it has code). It shows this block's reference price (from ReferenceSet, or the current price when there is no swap yet this block), the plus/minus 10% band, and a pre-check that simulates a typed swap with eth_call and says whether it would trip (replacing the earlier 'recent tripped swaps' list, which reverted swaps cannot supply).

Sepolia (11155111) only, launched as univ4_hook on the native-ETH pool the factory opens. GitHub publication and IPFS hosting are approved. Launch token: fixed supply of 1,000,000,000, 18 decimals, no constructor arguments, minted to msg.sender, no mint or admin. One hook; enable only the permission flags its logic uses and never revert the factory's pool initialisation or its one-sided seed. Like every hook launch that has gone live, the hook constructor takes exactly one argument, the Sepolia PoolManager 0xE03A1074c86CFeDd5C142C4F04F1a1536e203543; rates, recipients and the token are source constants or learned from the pool key, and there is no owner. Take any hook fee through return deltas (settled as ERC-6909 claims, paid out by pull) instead of assuming a dynamic-fee pool key. Where a swapper identity is needed, read it from hookData; a swap without valid hookData credits nobody (a router can never claim), and hookData is unauthenticated, which the README states. No external oracles or VRF, no proxies, delegatecall or selfdestruct. foundry.toml sets bytecode_hash = "none". Any website is a static export with index.html in dist/. Site label lab-circuit-breaker-hook.

Build CBRK and CircuitBreakerHook (permissions beforeSwap, afterSwap; PoolManager-only constructor) with a launch-rehearsal Foundry suite and an independent adversarial review, deploy them through the factory on Sepolia, then build the one-page site against the live pool.

the website assignment

Website: one static page (dist/index.html) that reads the hook's views and events and the pool price through Uniswap's Sepolia StateView, with a buy/sell form that swaps through Uniswap's published Sepolia PoolSwapTest router (check it has code).

It shows this block's reference price (from ReferenceSet, or the current price when there is no swap yet this block), the plus/minus 10% band, and a pre-check that simulates a typed swap with eth_call and says whether it would trip (replacing the earlier 'recent tripped swaps' list, which reverted swaps cannot supply).

Work

  1. contracts built
    #658Build contract project589 files changedrevised

    The work is complete and committed as 31cd11b on main. The working tree is clean.

    What was delivered

    • src/CBRK.sol: Breaker (CBRK), 1,000,000,000 tokens with 18 decimals, zero-argument constructor, minted once to the deployer, no owner or mint path. Built on OpenZeppelin ERC20 v5.7.0.
    • src/CircuitBreakerHook.sol: implements IHooks directly with exactly beforeSwap and afterSwap enabled and validated in the constructor. beforeSwap records the block's pre-swap sqrtPriceX96 per PoolId and emits ReferenceSet. afterSwap reverts with Tripped(ref, new) outside the band ref·sqrt(0.9) ≤ new ≤ ref·sqrt(1.1), computed with FullMath.mulDiv against inward-rounded Q96 constants. Zero deltas, no fee, no funds, no admin. Pools whose currency0 is not native ETH are ignored. Every callback checks msg.sender == PoolManager. Views for the site: currentReference, currentBand, allowedBand, isWithinBand, wouldTrip.
    • src/HookFlags.sol: the library the protected floor test imports, plus an allocation-free CREATE2 salt miner.
    • script/Deploy.s.sol: constants only, no environment reads, deploy() covered by a test.
    • docs/abi/CBRK.json and docs/abi/CircuitBreakerHook.json, a README covering assumptions, deployment parameters, operational responsibilities and review targets, and lib/VERSIONS.md recording the vendored dependency pins.

    Verification

    CheckResult
    forge build (solc 0.8.26, cancun, via-IR)passes
    forge test, 53 tests, two fuzz seedsall pass
    forge fmt --checkpasses
    Protected floor tests run locally with the verifier's env vars9 of 9 pass, with and without IMD_POOL_MANAGER

    The launch rehearsal initializes at the documented price, seeds one-sided CBRK with zero ETH taken, and lands a 1 ETH first buy in the ETH-less pool. It also shows a 20 ETH first buy tripping and the same amount succeeding when split across blocks. The suite covers 9.9% passing and 10.1% tripping in both directions, inclusive band edges, cumulative same-block trips, swap-back, new-block reset, dust, exact-in and exact-out both ways, a non-ETH pool, per-pool state, all ten callbacks refusing outside callers, and fuzzed sizes with truthful revert reasons.

    Assumptions to flag

    • The workflow does not state the opening price or seed size. The rehearsal uses tick 152040 (about 4.0 million CBRK per ETH) and a 500 million CBRK seed from that tick down to about 9,900 CBRK per ETH. These live in test/utils/LaunchParams.sol and the README; only the "small" and "oversized" buy sizes depend on them.
    • v4-core is vendored from main (commit 46c6834), not the v4.0.0 tag, because the protected test imports PoolOperation.sol, which the tag does not have.
    • Griefing is possible by design: pushing the price to the band edge blocks further same-direction moves for that block. This is documented and tested, not mitigated.

    Next for other assignments: the manifest node needs the flags 0x00C0, the creation code from Deploy.hookCreationCode(), and the pool key in the README. The independent review should start from the "Operational responsibilities" section, which lists the attack surfaces the workflow asks for.

    ran onclaude · claude-fable-5-1 · 77 turns · 29m 4s · 994 in · 121.5K out · 4.4M cached
    submission5772157cc957708d8e986ce4feb8f81b5c4290979a8df7cef4bc04af23851937
    device2468e053049c5c80472fff75183b00e52d7b62ed1c1d3f374ea7f24f7931642c
    started from0243d7da4a4337ae8b16bcdf15bb4ead736fd68f
    bundleeecfa13382be79eab2b8f7c614769e5366bcb43c71ac126f69fa251dd33ff43e · 768 KB
    verifiedrebuilt and matched · verifier 0.1.0 ·
    changed · 589 files
    .gitignoreREADME.mddocs/abi/CBRK.jsondocs/abi/CircuitBreakerHook.jsonfoundry.tomllib/VERSIONS.mdlib/forge-std/LICENSE-APACHElib/forge-std/LICENSE-MITlib/forge-std/README.mdlib/forge-std/src/Base.sollib/forge-std/src/Config.sollib/forge-std/src/LibVariable.sollib/forge-std/src/Script.sollib/forge-std/src/StdAssertions.sollib/forge-std/src/StdChains.sollib/forge-std/src/StdCheats.sollib/forge-std/src/StdConfig.sollib/forge-std/src/StdConstants.sollib/forge-std/src/StdError.sollib/forge-std/src/StdInvariant.sollib/forge-std/src/StdJson.sollib/forge-std/src/StdMath.sollib/forge-std/src/StdStorage.sollib/forge-std/src/StdStyle.sollib/forge-std/src/StdToml.sollib/forge-std/src/StdUtils.sollib/forge-std/src/Test.sollib/forge-std/src/Vm.sollib/forge-std/src/console.sollib/forge-std/src/console2.sollib/forge-std/src/interfaces/IERC1155.sollib/forge-std/src/interfaces/IERC165.sollib/forge-std/src/interfaces/IERC20.sollib/forge-std/src/interfaces/IERC4626.sollib/forge-std/src/interfaces/IERC6909.sollib/forge-std/src/interfaces/IERC721.sollib/forge-std/src/interfaces/IERC7540.sollib/forge-std/src/interfaces/IERC7575.sollib/forge-std/src/interfaces/IMulticall3.sollib/forge-std/src/safeconsole.sollib/openzeppelin-contracts/LICENSElib/openzeppelin-contracts/README.mdlib/openzeppelin-contracts/contracts/access/AccessControl.sollib/openzeppelin-contracts/contracts/access/IAccessControl.sollib/openzeppelin-contracts/contracts/access/Ownable.sollib/openzeppelin-contracts/contracts/access/Ownable2Step.sollib/openzeppelin-contracts/contracts/access/README.adoclib/openzeppelin-contracts/contracts/access/extensions/AccessControlDefaultAdminRules.sollib/openzeppelin-contracts/contracts/access/extensions/AccessControlEnumerable.sollib/openzeppelin-contracts/contracts/access/extensions/IAccessControlDefaultAdminRules.sollib/openzeppelin-contracts/contracts/access/extensions/IAccessControlEnumerable.sollib/openzeppelin-contracts/contracts/access/manager/AccessManaged.sollib/openzeppelin-contracts/contracts/access/manager/AccessManager.sollib/openzeppelin-contracts/contracts/access/manager/AuthorityUtils.sollib/openzeppelin-contracts/contracts/access/manager/IAccessManaged.sollib/openzeppelin-contracts/contracts/access/manager/IAccessManager.sollib/openzeppelin-contracts/contracts/access/manager/IAuthority.sollib/openzeppelin-contracts/contracts/account/Account.sollib/openzeppelin-contracts/contracts/account/README.adoclib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579.sollib/openzeppelin-contracts/contracts/account/extensions/draft-AccountERC7579Hooked.sollib/openzeppelin-contracts/contracts/account/extensions/draft-ERC7821.sollib/openzeppelin-contracts/contracts/account/paymaster/Paymaster.sollib/openzeppelin-contracts/contracts/account/paymaster/extensions/PaymasterERC20.sollib/openzeppelin-contracts/contracts/account/paymaster/extensions/PaymasterERC20Guarantor.sollib/openzeppelin-contracts/contracts/account/paymaster/extensions/PaymasterERC721Owner.sollib/openzeppelin-contracts/contracts/account/paymaster/extensions/PaymasterSigner.sollib/openzeppelin-contracts/contracts/account/utils/EIP7702Utils.sollib/openzeppelin-contracts/contracts/account/utils/ERC4337Utils.sollib/openzeppelin-contracts/contracts/account/utils/draft-ERC7579Utils.sollib/openzeppelin-contracts/contracts/crosschain/CrosschainLinked.sollib/openzeppelin-contracts/contracts/crosschain/CrosschainRemoteExecutor.sollib/openzeppelin-contracts/contracts/crosschain/ERC7786Recipient.sollib/openzeppelin-contracts/contracts/crosschain/README.adoclib/openzeppelin-contracts/contracts/crosschain/bridges/BridgeERC1155.sollib/openzeppelin-contracts/contracts/crosschain/bridges/BridgeERC20.sollib/openzeppelin-contracts/contracts/crosschain/bridges/BridgeERC721.sollib/openzeppelin-contracts/contracts/crosschain/bridges/BridgeERC7802.sollib/openzeppelin-contracts/contracts/crosschain/bridges/abstract/BridgeFungible.sollib/openzeppelin-contracts/contracts/crosschain/bridges/abstract/BridgeMultiToken.sollib/openzeppelin-contracts/contracts/crosschain/bridges/abstract/BridgeNonFungible.sollib/openzeppelin-contracts/contracts/finance/README.adoclib/openzeppelin-contracts/contracts/finance/VestingWallet.sollib/openzeppelin-contracts/contracts/finance/VestingWalletCliff.sollib/openzeppelin-contracts/contracts/governance/Governor.sollib/openzeppelin-contracts/contracts/governance/IGovernor.sollib/openzeppelin-contracts/contracts/governance/README.adoclib/openzeppelin-contracts/contracts/governance/TimelockController.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingFractional.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingOverridable.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorCountingSimple.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorCrosschain.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorNoncesKeyed.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorPreventLateQuorum.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorProposalGuardian.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorSequentialProposalId.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorSettings.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorStorage.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorSuperQuorum.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockAccess.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockCompound.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorTimelockControl.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotes.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesQuorumFraction.sollib/openzeppelin-contracts/contracts/governance/extensions/GovernorVotesSuperQuorumFraction.sollib/openzeppelin-contracts/contracts/governance/utils/IVotes.sollib/openzeppelin-contracts/contracts/governance/utils/Votes.sollib/openzeppelin-contracts/contracts/governance/utils/VotesExtended.sollib/openzeppelin-contracts/contracts/interfaces/IERC1155.sollib/openzeppelin-contracts/contracts/interfaces/IERC1155MetadataURI.sollib/openzeppelin-contracts/contracts/interfaces/IERC1155Receiver.sollib/openzeppelin-contracts/contracts/interfaces/IERC1271.sollib/openzeppelin-contracts/contracts/interfaces/IERC1363.sollib/openzeppelin-contracts/contracts/interfaces/IERC1363Receiver.sollib/openzeppelin-contracts/contracts/interfaces/IERC1363Spender.sollib/openzeppelin-contracts/contracts/interfaces/IERC165.sollib/openzeppelin-contracts/contracts/interfaces/IERC1820Implementer.sollib/openzeppelin-contracts/contracts/interfaces/IERC1820Registry.sollib/openzeppelin-contracts/contracts/interfaces/IERC1967.sollib/openzeppelin-contracts/contracts/interfaces/IERC20.sollib/openzeppelin-contracts/contracts/interfaces/IERC20Metadata.sollib/openzeppelin-contracts/contracts/interfaces/IERC2309.sollib/openzeppelin-contracts/contracts/interfaces/IERC2612.sollib/openzeppelin-contracts/contracts/interfaces/IERC2981.sollib/openzeppelin-contracts/contracts/interfaces/IERC3156.sollib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashBorrower.sollib/openzeppelin-contracts/contracts/interfaces/IERC3156FlashLender.sollib/openzeppelin-contracts/contracts/interfaces/IERC4337.sollib/openzeppelin-contracts/contracts/interfaces/IERC4626.sollib/openzeppelin-contracts/contracts/interfaces/IERC4906.sollib/openzeppelin-contracts/contracts/interfaces/IERC5267.sollib/openzeppelin-contracts/contracts/interfaces/IERC5313.sollib/openzeppelin-contracts/contracts/interfaces/IERC5805.sollib/openzeppelin-contracts/contracts/interfaces/IERC6372.sollib/openzeppelin-contracts/contracts/interfaces/IERC6909.sollib/openzeppelin-contracts/contracts/interfaces/IERC721.sollib/openzeppelin-contracts/contracts/interfaces/IERC721Enumerable.sollib/openzeppelin-contracts/contracts/interfaces/IERC721Metadata.sollib/openzeppelin-contracts/contracts/interfaces/IERC721Receiver.sollib/openzeppelin-contracts/contracts/interfaces/IERC7751.sollib/openzeppelin-contracts/contracts/interfaces/IERC777.sollib/openzeppelin-contracts/contracts/interfaces/IERC777Recipient.sollib/openzeppelin-contracts/contracts/interfaces/IERC777Sender.sollib/openzeppelin-contracts/contracts/interfaces/IERC7913.sollib/openzeppelin-contracts/contracts/interfaces/README.adoclib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sollib/openzeppelin-contracts/contracts/interfaces/draft-IERC3009.sollib/openzeppelin-contracts/contracts/interfaces/draft-IERC6093.sollib/openzeppelin-contracts/contracts/interfaces/draft-IERC7579.sollib/openzeppelin-contracts/contracts/interfaces/draft-IERC7674.sollib/openzeppelin-contracts/contracts/interfaces/draft-IERC7786.sollib/openzeppelin-contracts/contracts/interfaces/draft-IERC7802.sollib/openzeppelin-contracts/contracts/interfaces/draft-IERC7821.sollib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sollib/openzeppelin-contracts/contracts/metatx/ERC2771Forwarder.sollib/openzeppelin-contracts/contracts/metatx/README.adoclib/openzeppelin-contracts/contracts/mocks/AccessManagedTarget.sollib/openzeppelin-contracts/contracts/mocks/AccessManagerMock.sollib/openzeppelin-contracts/contracts/mocks/ArraysMock.sollib/openzeppelin-contracts/contracts/mocks/AuthorityMock.sollib/openzeppelin-contracts/contracts/mocks/Base64Dirty.sollib/openzeppelin-contracts/contracts/mocks/BatchCaller.sollib/openzeppelin-contracts/contracts/mocks/BlockHeaderMock.sollib/openzeppelin-contracts/contracts/mocks/CallReceiverMock.sollib/openzeppelin-contracts/contracts/mocks/ConstructorMock.sollib/openzeppelin-contracts/contracts/mocks/ContextMock.sollib/openzeppelin-contracts/contracts/mocks/DummyImplementation.sollib/openzeppelin-contracts/contracts/mocks/EIP712Verifier.sollib/openzeppelin-contracts/contracts/mocks/ERC1271WalletMock.sollib/openzeppelin-contracts/contracts/mocks/ERC165Mock.sollib/openzeppelin-contracts/contracts/mocks/ERC2771ContextMock.sollib/openzeppelin-contracts/contracts/mocks/ERC3156FlashBorrowerMock.sollib/openzeppelin-contracts/contracts/mocks/EtherReceiverMock.sollib/openzeppelin-contracts/contracts/mocks/InitializableMock.sollib/openzeppelin-contracts/contracts/mocks/MerkleProofCustomHashMock.sollib/openzeppelin-contracts/contracts/mocks/MerkleTreeMock.sollib/openzeppelin-contracts/contracts/mocks/MulticallHelper.sollib/openzeppelin-contracts/contracts/mocks/MultipleInheritanceInitializableMocks.sollib/openzeppelin-contracts/contracts/mocks/PausableMock.sollib/openzeppelin-contracts/contracts/mocks/ReentrancyAttack.sollib/openzeppelin-contracts/contracts/mocks/ReentrancyMock.sollib/openzeppelin-contracts/contracts/mocks/ReentrancyTransientMock.sollib/openzeppelin-contracts/contracts/mocks/RegressionImplementation.sollib/openzeppelin-contracts/contracts/mocks/SingleInheritanceInitializableMocks.sollib/openzeppelin-contracts/contracts/mocks/Stateless.sollib/openzeppelin-contracts/contracts/mocks/StorageSlotMock.sollib/openzeppelin-contracts/contracts/mocks/TimelockReentrant.sollib/openzeppelin-contracts/contracts/mocks/TransientSlotMock.sollib/openzeppelin-contracts/contracts/mocks/UpgradeableBeaconMock.sollib/openzeppelin-contracts/contracts/mocks/VotesExtendedMock.sollib/openzeppelin-contracts/contracts/mocks/VotesMock.sollib/openzeppelin-contracts/contracts/mocks/account/AccountMock.sollib/openzeppelin-contracts/contracts/mocks/account/modules/ERC7579Mock.sollib/openzeppelin-contracts/contracts/mocks/account/paymaster/PaymasterERC20Mock.sollib/openzeppelin-contracts/contracts/mocks/account/paymaster/PaymasterERC721OwnerMock.sollib/openzeppelin-contracts/contracts/mocks/account/paymaster/PaymasterSignerMock.sollib/openzeppelin-contracts/contracts/mocks/account/utils/ERC7579UtilsMock.sollib/openzeppelin-contracts/contracts/mocks/compound/CompTimelock.sollib/openzeppelin-contracts/contracts/mocks/crosschain/ERC7786GatewayMock.sollib/openzeppelin-contracts/contracts/mocks/crosschain/ERC7786RecipientMock.sollib/openzeppelin-contracts/contracts/mocks/docs/AccessManagerEnumerable.sollib/openzeppelin-contracts/contracts/mocks/docs/ERC20WithAutoMinerReward.sollib/openzeppelin-contracts/contracts/mocks/docs/ERC4626Fees.sollib/openzeppelin-contracts/contracts/mocks/docs/MyNFT.sollib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintBase.sollib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintMissing.sollib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlERC20MintOnlyRole.sollib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessControlModified.sollib/openzeppelin-contracts/contracts/mocks/docs/access-control/AccessManagedERC20MintBase.sollib/openzeppelin-contracts/contracts/mocks/docs/access-control/MyContractOwnable.sollib/openzeppelin-contracts/contracts/mocks/docs/account/MyAccountEIP7702.sollib/openzeppelin-contracts/contracts/mocks/docs/account/MyFactoryAccount.sollib/openzeppelin-contracts/contracts/mocks/docs/account/paymaster/PaymasterECDSASigner.sollib/openzeppelin-contracts/contracts/mocks/docs/governance/MyGovernor.sollib/openzeppelin-contracts/contracts/mocks/docs/governance/MyToken.sollib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenTimestampBased.sollib/openzeppelin-contracts/contracts/mocks/docs/governance/MyTokenWrapped.sollib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/GameItems.sollib/openzeppelin-contracts/contracts/mocks/docs/token/ERC1155/MyERC1155HolderContract.sollib/openzeppelin-contracts/contracts/mocks/docs/token/ERC20/GLDToken.sollib/openzeppelin-contracts/contracts/mocks/docs/token/ERC6909/ERC6909GameItems.sollib/openzeppelin-contracts/contracts/mocks/docs/token/ERC721/GameItem.sollib/openzeppelin-contracts/contracts/mocks/docs/utilities/Base64NFT.sollib/openzeppelin-contracts/contracts/mocks/docs/utilities/Multicall.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorCountingOverridableMock.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorCrosschain.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorFractionalMock.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorMock.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorNoncesKeyedMock.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorPreventLateQuorumMock.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorProposalGuardianMock.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorQueueingFailedMock.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorSequentialProposalIdMock.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorStorageMock.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorSuperQuorumMock.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockAccessMock.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockCompoundMock.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorTimelockControlMock.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorVoteMock.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorVotesSuperQuorumFractionMock.sollib/openzeppelin-contracts/contracts/mocks/governance/GovernorWithParamsMock.sollib/openzeppelin-contracts/contracts/mocks/proxy/BadBeacon.sollib/openzeppelin-contracts/contracts/mocks/proxy/ClashingImplementation.sollib/openzeppelin-contracts/contracts/mocks/proxy/ERC1967ProxyUnsafe.sollib/openzeppelin-contracts/contracts/mocks/proxy/UUPSUpgradeableMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC1155ReceiverMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC1363ForceApproveMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC1363NoReturnMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReceiverMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC1363ReturnFalseMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC1363SpenderMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC20ApprovalMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC20BlocklistMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC20BridgeableMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC20DecimalsMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC20ExcessDecimalsMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC20FlashMintMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC20ForceApproveMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC20GetterHelper.sollib/openzeppelin-contracts/contracts/mocks/token/ERC20Mock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC20MulticallMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC20NoReturnMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC20Reentrant.sollib/openzeppelin-contracts/contracts/mocks/token/ERC20ReturnFalseMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesAdditionalCheckpointsMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesLegacyMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC20VotesTimestampMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC4626LimitsMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC4626Mock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC4626OffsetMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC4646FeesMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveEnumerableMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC721ConsecutiveMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC721ReceiverMock.sollib/openzeppelin-contracts/contracts/mocks/token/ERC721URIStorageMock.sollib/openzeppelin-contracts/contracts/mocks/utils/cryptography/ERC7739Mock.sollib/openzeppelin-contracts/contracts/package.jsonlib/openzeppelin-contracts/contracts/proxy/Clones.sollib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Clones.sollib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sollib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Utils.sollib/openzeppelin-contracts/contracts/proxy/Proxy.sollib/openzeppelin-contracts/contracts/proxy/README.adoclib/openzeppelin-contracts/contracts/proxy/beacon/BeaconProxy.sollib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sollib/openzeppelin-contracts/contracts/proxy/beacon/UpgradeableBeacon.sollib/openzeppelin-contracts/contracts/proxy/transparent/ProxyAdmin.sollib/openzeppelin-contracts/contracts/proxy/transparent/TransparentUpgradeableProxy.sollib/openzeppelin-contracts/contracts/proxy/utils/Initializable.sollib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sollib/openzeppelin-contracts/contracts/token/ERC1155/ERC1155.sollib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155.sollib/openzeppelin-contracts/contracts/token/ERC1155/IERC1155Receiver.sollib/openzeppelin-contracts/contracts/token/ERC1155/README.adoclib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Burnable.sollib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Crosschain.sollib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Pausable.sollib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155Supply.sollib/openzeppelin-contracts/contracts/token/ERC1155/extensions/ERC1155URIStorage.sollib/openzeppelin-contracts/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sollib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Holder.sollib/openzeppelin-contracts/contracts/token/ERC1155/utils/ERC1155Utils.sollib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sollib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sollib/openzeppelin-contracts/contracts/token/ERC20/README.adoclib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC1363.sollib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sollib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Capped.sollib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Crosschain.sollib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20FlashMint.sollib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Pausable.sollib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Permit.sollib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20TransferAuthorization.sollib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Votes.sollib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Wrapper.sollib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sollib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sollib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sollib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20Bridgeable.sollib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC20TemporaryApproval.sollib/openzeppelin-contracts/contracts/token/ERC20/extensions/draft-ERC3009.sollib/openzeppelin-contracts/contracts/token/ERC20/utils/ERC1363Utils.sollib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sollib/openzeppelin-contracts/contracts/token/ERC6909/ERC6909.sollib/openzeppelin-contracts/contracts/token/ERC6909/README.adoclib/openzeppelin-contracts/contracts/token/ERC6909/extensions/ERC6909ContentURI.sollib/openzeppelin-contracts/contracts/token/ERC6909/extensions/ERC6909Metadata.sollib/openzeppelin-contracts/contracts/token/ERC6909/extensions/ERC6909TokenSupply.sollib/openzeppelin-contracts/contracts/token/ERC721/ERC721.sollib/openzeppelin-contracts/contracts/token/ERC721/IERC721.sollib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sollib/openzeppelin-contracts/contracts/token/ERC721/README.adoclib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Burnable.sollib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Consecutive.sollib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Crosschain.sollib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Enumerable.sollib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sollib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Royalty.sollib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sollib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Votes.sollib/openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Wrapper.sollib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Enumerable.sollib/openzeppelin-contracts/contracts/token/ERC721/extensions/IERC721Metadata.sollib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Holder.sollib/openzeppelin-contracts/contracts/token/ERC721/utils/ERC721Utils.sollib/openzeppelin-contracts/contracts/token/common/ERC2981.sollib/openzeppelin-contracts/contracts/token/common/README.adoclib/openzeppelin-contracts/contracts/utils/Address.sollib/openzeppelin-contracts/contracts/utils/Arrays.sollib/openzeppelin-contracts/contracts/utils/Base58.sollib/openzeppelin-contracts/contracts/utils/Base64.sollib/openzeppelin-contracts/contracts/utils/BlockHeader.sollib/openzeppelin-contracts/contracts/utils/Blockhash.sollib/openzeppelin-contracts/contracts/utils/Bytes.sollib/openzeppelin-contracts/contracts/utils/CAIP10.sollib/openzeppelin-contracts/contracts/utils/CAIP2.sollib/openzeppelin-contracts/contracts/utils/Calldata.sollib/openzeppelin-contracts/contracts/utils/Comparators.sollib/openzeppelin-contracts/contracts/utils/Context.sollib/openzeppelin-contracts/contracts/utils/Create2.sollib/openzeppelin-contracts/contracts/utils/Create3.sollib/openzeppelin-contracts/contracts/utils/ERC6372Utils.sollib/openzeppelin-contracts/contracts/utils/Errors.sollib/openzeppelin-contracts/contracts/utils/LowLevelCall.sollib/openzeppelin-contracts/contracts/utils/Memory.sollib/openzeppelin-contracts/contracts/utils/Multicall.sollib/openzeppelin-contracts/contracts/utils/Nonces.sollib/openzeppelin-contracts/contracts/utils/NoncesKeyed.sollib/openzeppelin-contracts/contracts/utils/Packing.sollib/openzeppelin-contracts/contracts/utils/Panic.sollib/openzeppelin-contracts/contracts/utils/Pausable.sollib/openzeppelin-contracts/contracts/utils/README.adoclib/openzeppelin-contracts/contracts/utils/RLP.sollib/openzeppelin-contracts/contracts/utils/RateLimiter.sollib/openzeppelin-contracts/contracts/utils/ReentrancyGuard.sollib/openzeppelin-contracts/contracts/utils/ReentrancyGuardTransient.sollib/openzeppelin-contracts/contracts/utils/RelayedCall.sollib/openzeppelin-contracts/contracts/utils/ShortStrings.sollib/openzeppelin-contracts/contracts/utils/SimulateCall.sollib/openzeppelin-contracts/contracts/utils/SlotDerivation.sollib/openzeppelin-contracts/contracts/utils/StorageSlot.sollib/openzeppelin-contracts/contracts/utils/Strings.sollib/openzeppelin-contracts/contracts/utils/TransientSlot.sollib/openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sollib/openzeppelin-contracts/contracts/utils/cryptography/EIP712.sollib/openzeppelin-contracts/contracts/utils/cryptography/Hashes.sollib/openzeppelin-contracts/contracts/utils/cryptography/MerkleProof.sollib/openzeppelin-contracts/contracts/utils/cryptography/MessageHashUtils.sollib/openzeppelin-contracts/contracts/utils/cryptography/P256.sollib/openzeppelin-contracts/contracts/utils/cryptography/README.adoclib/openzeppelin-contracts/contracts/utils/cryptography/RSA.sollib/openzeppelin-contracts/contracts/utils/cryptography/SignatureChecker.sollib/openzeppelin-contracts/contracts/utils/cryptography/TrieProof.sollib/openzeppelin-contracts/contracts/utils/cryptography/WebAuthn.sollib/openzeppelin-contracts/contracts/utils/cryptography/draft-ERC7739Utils.sollib/openzeppelin-contracts/contracts/utils/cryptography/signers/AbstractSigner.sollib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913.sollib/openzeppelin-contracts/contracts/utils/cryptography/signers/MultiSignerERC7913Weighted.sollib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerECDSA.sollib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerEIP7702.sollib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerERC7913.sollib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerP256.sollib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerRSA.sollib/openzeppelin-contracts/contracts/utils/cryptography/signers/SignerWebAuthn.sollib/openzeppelin-contracts/contracts/utils/cryptography/signers/draft-ERC7739.sollib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913P256Verifier.sollib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913RSAVerifier.sollib/openzeppelin-contracts/contracts/utils/cryptography/verifiers/ERC7913WebAuthnVerifier.sollib/openzeppelin-contracts/contracts/utils/draft-InteroperableAddress.sollib/openzeppelin-contracts/contracts/utils/introspection/ERC165.sollib/openzeppelin-contracts/contracts/utils/introspection/ERC165Checker.sollib/openzeppelin-contracts/contracts/utils/introspection/IERC165.sollib/openzeppelin-contracts/contracts/utils/math/Math.sollib/openzeppelin-contracts/contracts/utils/math/SafeCast.sollib/openzeppelin-contracts/contracts/utils/math/SignedMath.sollib/openzeppelin-contracts/contracts/utils/structs/Accumulators.sollib/openzeppelin-contracts/contracts/utils/structs/BitMaps.sollib/openzeppelin-contracts/contracts/utils/structs/Checkpoints.sollib/openzeppelin-contracts/contracts/utils/structs/CircularBuffer.sollib/openzeppelin-contracts/contracts/utils/structs/DoubleEndedQueue.sollib/openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sollib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sollib/openzeppelin-contracts/contracts/utils/structs/Heap.sollib/openzeppelin-contracts/contracts/utils/structs/MerkleTree.sollib/openzeppelin-contracts/contracts/utils/types/Time.sollib/openzeppelin-contracts/contracts/vendor/compound/ICompoundTimelock.sollib/openzeppelin-contracts/contracts/vendor/compound/LICENSElib/solmate/LICENSElib/solmate/README.mdlib/solmate/src/auth/Auth.sollib/solmate/src/auth/Owned.sollib/solmate/src/auth/authorities/MultiRolesAuthority.sollib/solmate/src/auth/authorities/RolesAuthority.sollib/solmate/src/mixins/ERC4626.sollib/solmate/src/test/Auth.t.sollib/solmate/src/test/Bytes32AddressLib.t.sollib/solmate/src/test/CREATE3.t.sollib/solmate/src/test/DSTestPlus.t.sollib/solmate/src/test/ERC1155.t.sollib/solmate/src/test/ERC20.t.sollib/solmate/src/test/ERC4626.t.sollib/solmate/src/test/ERC6909.t.sollib/solmate/src/test/ERC721.t.sollib/solmate/src/test/FixedPointMathLib.t.sollib/solmate/src/test/LibString.t.sollib/solmate/src/test/MerkleProofLib.t.sollib/solmate/src/test/MultiRolesAuthority.t.sollib/solmate/src/test/Owned.t.sollib/solmate/src/test/ReentrancyGuard.t.sollib/solmate/src/test/RolesAuthority.t.sollib/solmate/src/test/SSTORE2.t.sollib/solmate/src/test/SafeCastLib.t.sollib/solmate/src/test/SafeTransferLib.t.sollib/solmate/src/test/SignedWadMath.t.sollib/solmate/src/test/WETH.t.sollib/solmate/src/test/utils/DSInvariantTest.sollib/solmate/src/test/utils/DSTestPlus.sollib/solmate/src/test/utils/Hevm.sollib/solmate/src/test/utils/mocks/MockAuthChild.sollib/solmate/src/test/utils/mocks/MockAuthority.sollib/solmate/src/test/utils/mocks/MockERC1155.sollib/solmate/src/test/utils/mocks/MockERC20.sollib/solmate/src/test/utils/mocks/MockERC4626.sollib/solmate/src/test/utils/mocks/MockERC6909.sollib/solmate/src/test/utils/mocks/MockERC721.sollib/solmate/src/test/utils/mocks/MockOwned.sollib/solmate/src/test/utils/weird-tokens/MissingReturnToken.sollib/solmate/src/test/utils/weird-tokens/ReturnsFalseToken.sollib/solmate/src/test/utils/weird-tokens/ReturnsGarbageToken.sollib/solmate/src/test/utils/weird-tokens/ReturnsTooLittleToken.sollib/solmate/src/test/utils/weird-tokens/ReturnsTooMuchToken.sollib/solmate/src/test/utils/weird-tokens/ReturnsTwoToken.sollib/solmate/src/test/utils/weird-tokens/RevertingToken.sollib/solmate/src/tokens/ERC1155.sollib/solmate/src/tokens/ERC20.sollib/solmate/src/tokens/ERC6909.sollib/solmate/src/tokens/ERC721.sollib/solmate/src/tokens/WETH.sollib/solmate/src/utils/Bytes32AddressLib.sollib/solmate/src/utils/CREATE3.sollib/solmate/src/utils/FixedPointMathLib.sollib/solmate/src/utils/LibString.sollib/solmate/src/utils/MerkleProofLib.sollib/solmate/src/utils/ReentrancyGuard.sollib/solmate/src/utils/SSTORE2.sollib/solmate/src/utils/SafeCastLib.sollib/solmate/src/utils/SafeTransferLib.sollib/solmate/src/utils/SignedWadMath.sollib/v4-core/README.mdlib/v4-core/licenses/BUSL_LICENSElib/v4-core/licenses/MIT_LICENSElib/v4-core/src/ERC6909.sollib/v4-core/src/ERC6909Claims.sollib/v4-core/src/Extsload.sollib/v4-core/src/Exttload.sollib/v4-core/src/NoDelegateCall.sollib/v4-core/src/PoolManager.sollib/v4-core/src/ProtocolFees.sollib/v4-core/src/interfaces/IExtsload.sollib/v4-core/src/interfaces/IExttload.sollib/v4-core/src/interfaces/IHooks.sollib/v4-core/src/interfaces/IPoolManager.sollib/v4-core/src/interfaces/IProtocolFees.sollib/v4-core/src/interfaces/callback/IUnlockCallback.sollib/v4-core/src/interfaces/external/IERC20Minimal.sollib/v4-core/src/interfaces/external/IERC6909Claims.sollib/v4-core/src/libraries/BitMath.sollib/v4-core/src/libraries/CurrencyDelta.sollib/v4-core/src/libraries/CurrencyReserves.sollib/v4-core/src/libraries/CustomRevert.sollib/v4-core/src/libraries/FixedPoint128.sollib/v4-core/src/libraries/FixedPoint96.sollib/v4-core/src/libraries/FullMath.sollib/v4-core/src/libraries/Hooks.sollib/v4-core/src/libraries/LPFeeLibrary.sollib/v4-core/src/libraries/LiquidityMath.sollib/v4-core/src/libraries/Lock.sollib/v4-core/src/libraries/NonzeroDeltaCount.sollib/v4-core/src/libraries/ParseBytes.sollib/v4-core/src/libraries/Pool.sollib/v4-core/src/libraries/Position.sollib/v4-core/src/libraries/ProtocolFeeLibrary.sollib/v4-core/src/libraries/SafeCast.sollib/v4-core/src/libraries/SqrtPriceMath.sollib/v4-core/src/libraries/StateLibrary.sollib/v4-core/src/libraries/SwapMath.sollib/v4-core/src/libraries/TickBitmap.sollib/v4-core/src/libraries/TickMath.sollib/v4-core/src/libraries/TransientStateLibrary.sollib/v4-core/src/libraries/UnsafeMath.sollib/v4-core/src/test/ActionsRouter.sollib/v4-core/src/test/BaseTestHooks.sollib/v4-core/src/test/CurrencyTest.sollib/v4-core/src/test/CustomCurveHook.sollib/v4-core/src/test/DeltaReturningHook.sollib/v4-core/src/test/DynamicFeesTestHook.sollib/v4-core/src/test/DynamicReturnFeeTestHook.sollib/v4-core/src/test/EmptyRevertContract.sollib/v4-core/src/test/EmptyTestHooks.sollib/v4-core/src/test/FeeTakingHook.sollib/v4-core/src/test/Fuzzers.sollib/v4-core/src/test/HooksTest.sollib/v4-core/src/test/LPFeeTakingHook.sollib/v4-core/src/test/LiquidityMathTest.sollib/v4-core/src/test/MockContract.sollib/v4-core/src/test/MockERC6909Claims.sollib/v4-core/src/test/MockHooks.sollib/v4-core/src/test/NativeERC20.sollib/v4-core/src/test/NoDelegateCallTest.sollib/v4-core/src/test/PoolClaimsTest.sollib/v4-core/src/test/PoolDonateTest.sollib/v4-core/src/test/PoolEmptyUnlockTest.sollib/v4-core/src/test/PoolModifyLiquidityTest.sollib/v4-core/src/test/PoolModifyLiquidityTestNoChecks.sollib/v4-core/src/test/PoolNestedActionsTest.sollib/v4-core/src/test/PoolSwapTest.sollib/v4-core/src/test/PoolTakeTest.sollib/v4-core/src/test/PoolTestBase.sollib/v4-core/src/test/ProtocolFeesImplementation.sollib/v4-core/src/test/ProxyPoolManager.sollib/v4-core/src/test/SkipCallsTestHook.sollib/v4-core/src/test/SqrtPriceMathEchidnaTest.sollib/v4-core/src/test/SwapRouterNoChecks.sollib/v4-core/src/test/TestERC20.sollib/v4-core/src/test/TestInvalidERC20.sollib/v4-core/src/test/TickMathEchidnaTest.sollib/v4-core/src/test/TickMathTest.sollib/v4-core/src/test/TickOverflowSafetyEchidnaTest.sollib/v4-core/src/types/BalanceDelta.sollib/v4-core/src/types/BeforeSwapDelta.sollib/v4-core/src/types/Currency.sollib/v4-core/src/types/PoolId.sollib/v4-core/src/types/PoolKey.sollib/v4-core/src/types/PoolOperation.sollib/v4-core/src/types/Slot0.sollib/v4-core/test/utils/CurrencySettler.solremappings.txtscript/Deploy.s.solsrc/CBRK.solsrc/CircuitBreakerHook.solsrc/HookFlags.soltest/CBRK.t.soltest/CircuitBreakerHook.t.soltest/Deploy.t.soltest/HookFlags.t.soltest/LaunchRehearsal.t.soltest/mocks/MockERC20.soltest/utils/CircuitBreakerFixture.soltest/utils/LaunchParams.sol
  2. contracts tested
    #1860Gas and size reporttests failed2 files changed

    The work is complete. Recap for a reader who only sees this message:

    Deliverables (all within the allowed paths; the build and full suite pass, 87 tests, 0 failures)

    • test/GasReport.t.sol: 35 new tests in three contracts. They measure swaps on two identical pools that differ only in the hook field, the two callbacks in isolation, every public function of every repository contract, and both deployments. Ceiling assertions turn a cost regression into a failing test.
    • .gas-snapshot: forge snapshot of the full suite.
    • artifacts/gas.md: the report. artifacts/gas-report.txt holds the raw forge test --gas-report output with a note on how forge meters top-level calls.

    Sizes. No contract exceeds 24,576 bytes, so there is no size defect to report. The hook is 5,318 bytes and the token 2,469. Uniswap's own PoolManager compiles to 24,009 bytes (567 under the limit) but is not deployed by this launch.

    Gas per swap. The hook's overhead on top of an identical hook-less swap, measured as execution gas with cold state, is the same in both directions:

    Block stateHook overhead
    First swap the pool ever sees (two fresh storage writes)56,167
    First swap of a later block (two rewrites plus event)21,967
    Later swap in the same block (reads only)13,151

    A routine hooked buy bills 112,842 gas as a transaction versus 99,451 without the hook. A tripped swap costs its sender 83,559 gas and leaves no state.

    Callbacks. afterSwap costs 9,963 gas; beforeSwap costs 6,289 in a block's later swaps, 19,105 for a block's first swap, and 53,305 once per pool. Both stay under the guidance's hard ceilings; the 50,000 target is exceeded only on that one first-ever swap.

    Things worth knowing, none of them defects. The two reference slots could be packed into one to save about 22,100 gas on a pool's first swap and 5,000 on each block's first swap. Nothing in either callback loops or grows with input. Salt mining costs about 233 gas per candidate and runs off chain.

    Measurement notes. Foundry meters each top-level call from a test as its own transaction, including 21,000 intrinsic gas plus calldata, and consecutive calls into the same contract leak about 4,500 gas of warmth. The tests place a separating call before every measurement and split intrinsic gas out from the encoded calldata; the resulting numbers match forge test --isolate and reconcile exactly with EVM storage pricing (the 34,200 gap between the first two rows is two writes moving from fresh to rewrite).

    No findings file was written because no defect was found. The artifacts/ directory is excluded from git by the harness's own .git/info/exclude, alongside the other designated output paths, so it is left for collection from the working tree.

    ran onclaude · claude-fable-5-1 · 63 turns · 30m 0s · 1.1K in · 124.1K out · 6M cached
    submission9fa690f56bebdf1b7d570bf99635e27fe353f4ed69263c79f7fe93c60141c656
    device6f9434502e35e613f5b5e17b39a8e2f8d5f5d541a063aec5ee97f751dbfcf62a
    started from230afdba87b17be9d88110ff6f2da066ff2d6c6d
    bundlede8772c7c563dffa0680e2651f1ad5b9e023d8a87deddde35068f3f8b87b25f5 · 778 KB
    applied ona2f5c4edc45b412c7afb483a3cc08ccbd3b867db49644776a33d2649ef2c334f
    changed · 2 files
    .gas-snapshottest/GasReport.t.sol
    #4947 files changedrevised
    afterBuild contract project
    writes to
    test/**.gas-snapshotartifacts/**

    Created gas report, benchmarks, and .gas-snapshot.

    • Offline build, all 179 tests, and snapshot verification pass.
    • Hook runtime: 5,318 bytes.
    • Three existing oversized test harnesses are explicitly reported as defects.

    Commit blocked: .git is read-only. Files remain local; ignored artifacts/ also requires force-adding.

    ran oncodex · gpt-6-astra · 8 turns · 20m 10s · 114.9K in · 36.7K out · 3.3M cached
    submissionf1af6047da92e6c37d583b40f493a4ad2578e2a375f39212e6f76375362faec7
    devicec4f696e22e7a36f7235c9baaeaec7a27f0a1cc13d82b8d61e1e9f7b019d5015b
    started from230afdba87b17be9d88110ff6f2da066ff2d6c6d
    bundle33a5a0253ebd8772636356def58547cd7b9c5f0006106c775ddcae395a4d8bb8 · 781 KB
    verifiedrebuilt and matched · verifier 0.1.0 ·
    applied ona2f5c4edc45b412c7afb483a3cc08ccbd3b867db49644776a33d2649ef2c334f
    changed · 7 files
    .gas-snapshottest/gas/DependencyGas.t.soltest/gas/GasFixture.soltest/gas/LibraryGas.t.soltest/gas/MockGas.t.soltest/gas/PublicFunctionGas.t.soltest/gas/SwapGas.t.sol
  3. contracts integrated
    #494Manifest1 file changedrevised
    afterBuild contract project, Gas and size report
    writes to
    launch.json

    Created launch.json with matching contract metadata, permissions, constructor argument and pool price.

    Schema validation and forge build passed. forge test: 186 passed, zero failures. Notes: 1,527/4,000 characters.

    Only launch.json is deliverable; verification files remain under excluded test/scratch/.

    ran oncodex · gpt-6-astra · 4 turns · 3m 9s · 43K in · 5.4K out · 401.2K cached
    submissionc0278af25b247106aae85c12f978b91ecdb61e284e56ea56cb34642cb325edbc
    devicec4f696e22e7a36f7235c9baaeaec7a27f0a1cc13d82b8d61e1e9f7b019d5015b
    started from293a37a95db61a0e37b3b876e8ebb6da80575b6a
    bundle39e6ddbc9eb17b81e6fcfa4ad0a9b7ea6bb54013e5dc5d6c87c3808c38beadf1 · 783 KB
    verifiedrebuilt and matched · verifier 0.1.0 ·
    applied ona2f5c4edc45b412c7afb483a3cc08ccbd3b867db49644776a33d2649ef2c334f, ec96f72063319a89cc5d803e69605eda19632e5a3fb2cda54d74be8cf0ad9618
    changed · 1 file
    launch.json
  4. contracts reviewed
    #2Adversarial review2 findings · 1 highrevised
    afterBuild contract project, Gas and size report, Manifest

    Review complete. Findings are in .imd-findings.json at the repo root; no source, test, doc or config file was touched (git shows the tree clean apart from the findings file).

    One high finding, one documented acceptance.

    • High: zero-cost cross-block reference ratchet. The reference is whatever slot0 holds before the block's first swap, and the launch pool has no liquidity above the opening tick. A caller with no CBRK, no ETH and no approvals can sell 1 wei exact-in with the price limit set to the block's upper band edge. Nothing is exchanged, the delta is (0, 0), and slot0 lands exactly on the inclusive edge, so afterSwap passes. Next block the reference is 10% higher. After two such blocks, every buy of any size trips because a buy must slide back below the opening price, which is more than 10% under the reference. A defender's free walk-down is undone by a same-block re-push, so whoever is last in the block wins. Measured cost per push: 48k to 92k gas, zero tokens. I reproduced both sequences in a scratch copy against a real PoolManager with exact sqrtPriceX96 values in the finding. The README's claim that the attacker pays fees and slippage is false for the launch pool. Any remedy changes the approved reference semantics or the seed shape, so it needs a scope decision rather than a patch.
    • Info: one-block edge griefing with live liquidity. Documented with its call sequence as the workflow asked. It costs a real trade and is already accepted in the README, manifest notes and tests.

    Checked and found correct:

    • Both sqrt constants are the exact tightest inward integers, confirmed independently in Python. Lower edge uses ceil with the rounded-up constant, upper uses floor with the rounded-down constant.
    • Band maths cannot overflow: FullMath handles the 257-bit product, and results are uint256 so the upper edge past the uint160 range is safe. The fuzz over the full sqrt-price domain covers it.
    • The reference is captured in beforeSwap from slot0 before any state change, including the pool's first swap and after a tripped attempt, which leaves no state.
    • No same-block path moves the price without reaching afterSwap. Liquidity, donate and initialize do not move slot0, and v4's self-call skip is unreachable because the hook never calls the PoolManager.
    • Manifest price equals tick 152040, constructor and permissions match source, ABI exports list every function, event and error, and the full suite passes offline (181 tests).
    ran onclaude · claude-fable-5-1 · 18 turns · 9m 32s · 546 in · 26.4K out · 1.7M cached
    submissionda32a6c9609267ee7420f6144e40479993bc6a3084c226ec1d0773fdd19bdced
    device468e82a89b9bfe188ef46b055e2ea554bde626cc162630c20effb0fcc7e13fed
    started from13e4b1729f39857c0600ed96762a44dda16dd447
    bundlenone
    applied ona2f5c4edc45b412c7afb483a3cc08ccbd3b867db49644776a33d2649ef2c334f, ec96f72063319a89cc5d803e69605eda19632e5a3fb2cda54d74be8cf0ad9618, bd9dacf8d2a4692694b63bfdb97ef7b7e3d39edaa346482d96c173c40b4c4300
    changed · 0 filesnothing
    • highZero-cost cross-block reference ratchet: the block reference follows price moves through empty liquidity, so an attacker holding no tokens can push the launch pool's reference above the seeded range asrc/CircuitBreakerHook.sol:134

      beforeSwap stores whatever sqrtPriceX96 slot0 holds at the block's first swap (line 134-136), and afterSwap only compares the post-swap price with it. The band is enforced correctly, but nothing distinguishes a price that was reached by trading from one that was reached by sliding through a range with zero liquidity.

      In the launch pool the factory seeds CBRK only in [SEED_TICK_LOWER, INITIAL_TICK] and the pool opens at the top of that range, so everything above the opening tick is empty forever (nothing in the design ever adds ETH-side liquidity there).

      A oneForZero swap with any non-zero amountSpecified and sqrtPriceLimitX96 set to the block's upper band edge moves slot0 to that edge while exchanging nothing: amount0 = amount1 = 0, the router settles nothing, the caller needs no CBRK, no ETH and no approval, and afterSwap passes because the end price is exactly the (inclusive) upper edge. The next block's reference is then that pushed price.

      Repeating once per block ratchets the reference by +10% in spot terms per block for gas only. From the second block on, every buy of any size trips: a buy has to travel back down through the empty range and its end price can never be above the opening price, which is more than 10% below the ratcheted reference.

      Walking the price back down is also free but limited to -10% per block, and the attacker can re-push to the upper edge in the same block after any walk-down (the band is relative to the block reference, not to the previous swap), so whoever is last in the block decides the next reference; the attacker wins by being last. Cost measured in the reproduction: 91,760 gas for the first push, 48,151 gas for later ones, zero tokens.

      This contradicts README ('the attacker pays fees and slippage to hold the edge') and the launch.json notes ('block further same-direction swaps for the rest of that block'): on the launch pool the edge push costs nothing and its effect is not confined to one block. test_rehearsal_sellIntoEthlessPool already exercises the free slide inside the band but no test rolls to the next block and observes that the buy side is now locked.

      This is a property of the approved design (reference = raw pre-block slot0 price) combined with the approved one-sided seed, not an arithmetic bug; any remedy (for example refusing in afterSwap a swap that moved slot0 while exchanging nothing, or seeding two-sided) changes agreed behaviour and needs a scope decision by the launch owners rather than a unilateral patch.

      Pool as in test/LaunchRehearsal.t.sol: initialize at sqrtPriceX96 = 158570052814919122920977766972888 (tick 152040), add the one-sided CBRK seed in [92040, 152040], no other liquidity.

      Attacker = fresh address with 0 CBRK, 0 ETH, no approvals.

      Block N: attacker calls PoolSwapTest.swap(key, SwapParams(zeroForOne=false, amountSpecified=-1, sqrtPriceLimitX96=166309674447095422316896063468880 /* = allowedBand(init).upper */), TestSettings(false,false), '').

      Expected by README: attacker pays fees/slippage.

      Actual: returns BalanceDelta(0, 0), slot0.sqrtPriceX96 = 166309674447095422316896063468880 (spot +9.99%), ReferenceSet(poolId, N, 158570052814919122920977766972888) emitted, afterSwap passes.

      Block N+1: an honest exactIn buy of 1 ether (zeroForOne=true, limit MIN_SQRT_PRICE+1) reverts with Tripped(166309674447095422316896063468880, ~156.4e30) because it must slide back to the opening price and then move ~1.5% into liquidity (spot ratio 0.895 < 0.9).

      Attacker repeats the push with limit 174427058096411035213075543667450 (= allowedBand(166309674447095422316896063468880).upper); again delta (0,0).

      Block N+2: reference = 174427058096411035213075543667450 (spot +21% over the opening price).

      Buys of 1 wei, 0.001 ether and 1 ether exactIn all revert with Tripped(174427058096411035213075543667450, <= 158570052814919122920977766972888); exactOut 1 ether reverts too.

      Pool still holds 0 ETH; attacker balances unchanged.

      Each further block the attacker re-pushes by +10% or simply re-pushes after any defender's walk-down in the same block (verified: defender pushes to allowedBand(ref).lower with delta (0,0), attacker pushes to allowedBand(ref).upper in the same block, next block's reference is higher than before).

      Verified with a Foundry test on a copy of this repo (real PoolManager, hook at a mined address): both sequences behave exactly as stated.

    • infoOne-block edge griefing with live liquidity (documented, accepted): pushing the price to within the band edge blocks every same-direction swap for the rest of the block and makes victims' transactionssrc/CircuitBreakerHook.sol:157

      As the workflow asked, here is the call sequence for the accepted griefing. With two-sided liquidity around the price, an attacker who is first in a block can swap the price to just inside a band edge. Every later swap in the block that would move further in that direction reverts in afterSwap, so victims lose gas and get no fill; swaps back toward the reference still pass and the next block re-anchors at the pushed price.

      Unlike the high finding above, this costs the attacker the 0.30% fee plus slippage on a real trade of roughly 9.5% of pool depth, and it can be unwound the next block. It is documented in README ('Griefing is possible and accepted'), in launch.json notes, and covered by test_griefing_edgePushBlocksSameDirectionForTheBlock. No change is required; recorded so the acceptance is explicit in this review.

      Pool from test/CircuitBreakerHook.t.sol setUp (two-sided liquidity 1e22 over +/-6000 ticks around tick 152040), ref = slot0.sqrtPriceX96.

      Block N, tx 1 (attacker): swap(key, zeroForOne=true, amountSpecified=-type(uint96).max, sqrtPriceLimitX96=sqrtPriceAtRatio(ref, 9050)) -> passes, spot is -9.5% from ref, ReferenceSet(poolId, N, ref).

      Tx 2 (victim, same block): swapExactIn(true, 0.05 ether) with limit MIN_SQRT_PRICE+1 -> reverts with Tripped(ref, <sqrtPriceAtRatio(ref, 9000)); victim pays gas, receives nothing.

      Tx 3 (anyone): swapExactIn(false, 1000 ether) -> passes (moves back toward ref).

      Block N+1: swapExactIn(true, 0.05 ether) -> passes, new ReferenceSet with the -9.5% price.

      Attacker's cost: 0.30% fee and the slippage of the 9.5% move, recoverable only by trading back.

  5. contracts updated
    #1548Build contract projectruntime erroron the agent's machine: This content was flagged for possible cybersecurity risk.

    This content was flagged for possible cybersecurity risk. If this seems wrong, try rephrasing your request. If you’re doing authorized security work that requires more cyber permissive safeguards, apply for Daybreak access via https://platform.openai.com/settings/organization/status-and-access before retrying.

    ran oncodex · 1 turn · 1m 36s
    submission86e69d7b5dc6a21e5a1a4d017ed3d6d18309cf1279efebd37eba1cc64af3c8d5
    device35c52a5b502e847cda633d436a25cd57d809a4ea7935560acc2b18eccfd592ac
    started from230afdba87b17be9d88110ff6f2da066ff2d6c6d
    bundlenone
    changed · 0 filesnothing
    #25 files changed

    The revision is complete. Both findings reproduced, one led to a code change and the other to a documentation change.

    The high finding is real and is now closed for the reported sequence. On the one-sided launch pool, a 1 wei sell with its price limit at the band's upper edge slid through the empty range above the opening tick, exchanged nothing, and became the next block's reference. A 1 ETH buy in the next block then tripped. The hook's afterSwap now reverts with a new PhantomSwap error when the pool's swap delta is zero in both currencies. The band check still runs first, so out-of-band phantom moves keep reporting Tripped. No ordinary trade is affected, and a real sell that drains the pool's ETH and slides on keeps a non-zero delta.

    What I changed:

    • src/CircuitBreakerHook.sol: the zero-delta rule, the new error, and updated doc comments.
    • test/LaunchRehearsal.t.sol: the reported attack replayed and refused, next-block buys of three sizes passing, the arithmetic of a pushed reference, a drain-and-slide sell judged only by the band, and the in-band slide test now expecting PhantomSwap.
    • test/utils/CircuitBreakerFixture.sol: revert and decode helpers for the new error.
    • docs/abi/CircuitBreakerHook.json regenerated. README gains a "Reference ratchet through empty liquidity" section, the new selector, the new creation-code size, and the new deterministic-deployer salt and address.
    • .imd-responses.json answers both findings.

    One residual needs a launch-owner decision, stated plainly in the README and pinned by a test. The rule raises the attacker's cost from zero to a few wei, not to a real trade. An attacker who parks a dust ETH-only position just above the opening tick can sell dust CBRK through it with a non-zero delta and still walk the reference up 10% per block. Closing that requires either a two-sided factory seed or a different reference definition than the approved raw pre-block price. Both are outside this assignment, so I left the approved reference definition and seed shape alone, as the reviewer recommended.

    The advisory finding on one-block edge griefing with live liquidity is accepted behaviour. No code changed. The README bullet now carries the reviewer's exact call sequence and states the attacker's real cost, and no longer implies that cost applies on the one-sided launch pool.

    Verification, all offline: build clean, 56 tests pass, formatting check passes, and the deploy script dry run lands the hook at the address the README states with flags 192.

    ran onclaude · claude-fable-5-1 · 46 turns · 14m 2s · 546 in · 40.2K out · 1.9M cached
    submissione6c91c5a7ddd5bc7473401f20c830dec4becea1c43b8d58cb8d5cd1bf8222960
    device468e82a89b9bfe188ef46b055e2ea554bde626cc162630c20effb0fcc7e13fed
    started from230afdba87b17be9d88110ff6f2da066ff2d6c6d
    bundlea2f5c4edc45b412c7afb483a3cc08ccbd3b867db49644776a33d2649ef2c334f · 774 KB
    verifiedrebuilt and matched · verifier 0.1.0 ·
    changed · 5 files
    README.mddocs/abi/CircuitBreakerHook.jsonsrc/CircuitBreakerHook.soltest/LaunchRehearsal.t.soltest/utils/CircuitBreakerFixture.sol
  6. contracts updated
    #2Gas and size report4 files changed
    afterBuild contract project
    writes to
    test/**.gas-snapshotartifacts/**

    The revision is complete and verified. The rejected attempt's file no longer exists; I repaired the accepted test/gas suite instead of rewriting it.

    Why the previous run failed. After my accepted round, another contributor added a PhantomSwap check to afterSwap that reverts on a zero swap delta. My direct-callback gas test passed a zero BalanceDelta, so it now reverted. The full suite showed exactly that one failure and nothing else.

    What changed (only test/gas/**, .gas-snapshot, artifacts/gas.md):

    • test/gas/PublicFunctionGas.t.sol: the in-band afterSwap measurement now passes a real non-zero delta. Two new tests measure the PhantomSwap and Tripped revert paths of afterSwap directly, asserting the exact revert reason.
    • test/gas/GasFixture.sol: added a measureRevert helper and a measureTrippedSwap fixture that sends an oversized first-in-block buy through the router, checks the wrapped Tripped error, and confirms no state or reference survives.
    • test/gas/SwapGas.t.sol: added test_gas_swap_hook_buy_tripped to both block-position suites.
    • .gas-snapshot regenerated with forge snapshot --offline, and --check confirms it matches.
    • artifacts/gas.md written: every contract's runtime and initcode size, per-function gas for the hook, token, script, PoolManager, routers, mock and library constants, and a notes section.

    Results.

    CheckOutcome
    forge build --offlinesuccess
    forge test --offline187 passed, 0 failed
    forge snapshot --offline --checkmatches
    Largest deployed sizePoolManager 24,009 bytes, under the 24,576 limit

    Headline numbers in the report. The hook adds 19,489 gas to a block's first swap and 10,673 to every later swap in that block, identical across buy, sell, exact-in and exact-out. The pool's very first swap ever pays 53,689 once for the zero-to-non-zero reference slots. A tripped swap burns 55,921 to 64,737 gas. CircuitBreakerHook is 5,396 bytes and CBRK 2,469 bytes, so there is no size defect and no findings file was needed.

    ran onclaude · claude-fable-5-1 · 36 turns · 9m 13s · 354 in · 25.5K out · 1.2M cached
    submission96c634e673e53c1d2c4780672f4806a37abac38c31cdbea39c20c25b5f7ff0ee
    device468e82a89b9bfe188ef46b055e2ea554bde626cc162630c20effb0fcc7e13fed
    started frombf338356595e74a49431a8cbc468e30f2e393b73
    bundleec96f72063319a89cc5d803e69605eda19632e5a3fb2cda54d74be8cf0ad9618 · 790 KB
    verifiedrebuilt and matched · verifier 0.1.0 ·
    applied ona2f5c4edc45b412c7afb483a3cc08ccbd3b867db49644776a33d2649ef2c334f
    changed · 4 files
    .gas-snapshottest/gas/GasFixture.soltest/gas/PublicFunctionGas.t.soltest/gas/SwapGas.t.sol
  7. contracts updated
    #2Manifest1 file changed
    afterBuild contract project, Gas and size report
    writes to
    launch.json

    Done. The only tracked change is launch.json.

    What I changed. The manifest's structured fields were already correct against the source, so I left them alone. The notes were stale: the accepted hook now also reverts with PhantomSwap when a swap exchanges nothing in either currency, added after the independent review's reference-ratchet finding, and the old notes never mentioned it. The revised notes describe the accepted implementation:

    • The phantom-swap refusal, why it exists, and that the band check runs first.
    • The residual dust-liquidity ratchet exposure and the one-block edge griefing, both as the README documents them.
    • Pool key, opening tick and price derivation, the single PoolManager constructor argument, permission bits 0x00C0 with constructor validation, PoolManager-only callbacks, no fee, deltas, funds or admin, the integrator views, and ABI paths.

    Verification.

    CheckResult
    Schema validation (scratch script covering every constraint, key order, initialPrice below 2^256)valid, notes 3176 of 4000 chars
    initialPrice equals TickMath.getSqrtPriceAtTick(152040) and LaunchParamsscratch test passed
    Permissions vs getHookPermissionssource returns exactly beforeSwap and afterSwap, HOOK_FLAGS 0xC0
    forge build, forge test187 passed, 0 failed
    forge fmt --checkclean

    One of my scratch tests could not use deployCodeTo because the repo forbids filesystem reads, so I confirmed the permissions by reading the source and relying on the repo's own flag tests instead. The scratch files under test/scratch/ are the only other additions and are discarded before submission.

    ran onclaude · claude-fable-5-1 · 18 turns · 14m 22s · 292 in · 9.5K out · 728.2K cached
    submission640c4918f7548e66f3f6554b29b37cb054ba02c497f484383747ef8120259c02
    device468e82a89b9bfe188ef46b055e2ea554bde626cc162630c20effb0fcc7e13fed
    started froma7d591dfde714f78f54e29c1ec6a2c7470529c0f
    bundlebd9dacf8d2a4692694b63bfdb97ef7b7e3d39edaa346482d96c173c40b4c4300 · 793 KB
    verifiedrebuilt and matched · verifier 0.1.0 ·
    applied ona2f5c4edc45b412c7afb483a3cc08ccbd3b867db49644776a33d2649ef2c334f, ec96f72063319a89cc5d803e69605eda19632e5a3fb2cda54d74be8cf0ad9618
    changed · 1 file
    launch.json
  8. contracts reviewed
    #617Adversarial reviewruntime erroron the agent's machine: This content was flagged for possible cybersecurity risk.

    This content was flagged for possible cybersecurity risk. If this seems wrong, try rephrasing your request. If you’re doing authorized security work that requires more cyber permissive safeguards, apply for Daybreak access via https://platform.openai.com/settings/organization/status-and-access before retrying.

    ran oncodex · 1 turn · 35s
    submissioneec06137acbd59ac53b62bdf9b693fc22d066e71d77cecfa89cd277358287e78
    devicebb0a3bf63233e5e5722f6eae6cd08dc581298f894dd83aa00d8a87a846a28c34
    started from41942e8d9335e3f4e35738eb008e5bb9245baf10
    bundlenone
    applied ona2f5c4edc45b412c7afb483a3cc08ccbd3b867db49644776a33d2649ef2c334f, ec96f72063319a89cc5d803e69605eda19632e5a3fb2cda54d74be8cf0ad9618, bd9dacf8d2a4692694b63bfdb97ef7b7e3d39edaa346482d96c173c40b4c4300
    changed · 0 filesnothing
    #17311 finding · 1 medium
    afterBuild contract project, Gas and size report, Manifest

    The free edge push from my high finding is fixed, and the griefing note is settled. But the harm behind the high finding is still reachable for a few wei, so I've reported one medium finding. It needs a decision from the launch owners, not a code patch. I changed no repo files; the findings are in .imd-findings.json.

    High finding a8a8d7ba: the zero-cost push is fixed. afterSwap now reverts with PhantomSwap when a swap exchanges nothing in either currency (src/CircuitBreakerHook.sol:170). I reran the attack as I originally reported it and it is now refused. Normal trading isn't affected: with the 0.30% fee, even a 1-wei trade into liquidity pays 1 wei of fee, and any real price move costs at least 1 wei of input. So no legitimate swap has a zero delta.

    New medium finding: the dust version of the same attack locks buys indefinitely. The author documented that an attacker can still push the reference up 10% per block by parking a tiny ETH position above the opening price. That write-up understates it. I reproduced the following in a scratch copy under /tmp:

    • Setup: over two blocks the attacker makes two dust pushes, spending 2 wei of ETH and 5 wei of CBRK. They then remove their dust positions and stop.
    • The pool freezes: the price now sits about 21% above the opening price, with no liquidity between it and the seeded range. Any swap that stays inside the band trades nothing and reverts PhantomSwap. Any swap that reaches liquidity falls outside the band and reverts Tripped.
    • Result: in every later block, every swap through the router the site uses fails. That includes 1 ETH buys, exact-out buys and 1-wei moves in either direction.
    • The new rule made it worse: before this round's fix, anyone could walk the price back down for free. Now that walk-down is refused as well.
    • Recovery: someone has to add their own liquidity in the empty range and walk the price down over about two blocks. That works, but ordinary buyers and the site can't do it, and the attacker can re-lock for a few wei at any time.

    The approved brief only accepts griefing that blocks others for one block. Fixing this properly means a two-sided seed or a different reference definition, or explicitly accepting the lock. That choice belongs to the launch owners. At minimum, the README and the launch.json notes should say that the lock stays in place after the attacker stops and that router swaps can't undo it.

    Griefing note (info): settled. It's reproduced by test_griefing_edgePushBlocksSameDirectionForTheBlock and documented with the exact call sequence, and the new rule doesn't affect it. No further finding.

    Other areas in scope: nothing new found.

    • Sqrt constants: I recomputed both. SQRT_0_9_X96 is floor+1 (rounded up) and SQRT_1_1_X96 is exactly floor, so both lean inward as intended.
    • Band maths: the bounds round inward and the 512-bit arithmetic can't overflow. Results wider than 160 bits are handled.
    • Reference capture: the reference is set in beforeSwap before the price changes, including on the first swap ever.
    • Price moves that skip afterSwap: I found no way to move the price in a block without reaching afterSwap.
    • Tests and ABI: the ABI export matches the compiled contract, and forge test --offline passes all 187 tests.
    ran onclaude · claude-fable-5-1 · 16 turns · 5m 22s · 30 in · 19.9K out · 1.1M cached
    submission8c8bd2e3b792e6285132c462e8dbab736b3c5599aa8b8535b2c001aca57f5afb
    device3c7630b22a73c1fb36d7cccb511d3c400a92c46f4065d9046a3f71b9ce3aa6be
    started from41942e8d9335e3f4e35738eb008e5bb9245baf10
    bundlenone
    applied ona2f5c4edc45b412c7afb483a3cc08ccbd3b867db49644776a33d2649ef2c334f, ec96f72063319a89cc5d803e69605eda19632e5a3fb2cda54d74be8cf0ad9618, bd9dacf8d2a4692694b63bfdb97ef7b7e3d39edaa346482d96c173c40b4c4300
    changed · 0 filesnothing
    • mediumRatchet finding a8a8d7ba only partly fixed: the dust-liquidity push still locks the launch pool's buy side, and the PhantomSwap rule now stops router swaps from undoing it after the attacker stopssrc/CircuitBreakerHook.sol:170

      Settlement of a8a8d7ba. The reported zero-token sequence is fixed. I confirmed that the PhantomSwap check on a zero BalanceDelta refuses it, and test_ratchet_freeEdgePushIsRefusedAndNextBlockBuysStillPass reproduces it.

      With fee 3000, no legitimate swap has a zero delta: an exact-in of 1 wei into liquidity pays 1 wei of fee, and any price move through L>0 rounds amountIn up to at least 1. So the rule does not block normal trading. The harm the finding described is still reachable, and the author's residual description (README 'Reference ratchet through empty liquidity', launch.json notes: 'walk the reference up by 10% per block at a cost of wei') understates it in two ways.

      (1) The attacker does not have to keep acting. After two dust pushes the attacker can remove the dust positions and stop. The gap between the opening tick and the pushed price then holds no liquidity.

      (2) The new rule turns that empty gap into a lock. Before the fix, anyone could walk the price back down for free, up to -10% per block. Now any swap that ends inside the band exchanges nothing and reverts PhantomSwap.

      Any swap that reaches liquidity ends below the band and reverts Tripped. From that state, no swap through PoolSwapTest (the router the site's buy/sell form uses) can succeed in any later block. The pool stays frozen until someone adds their own liquidity inside the gap and walks the price down over about 2 blocks.

      That recovery works (verified), but it is not available to ordinary buyers or the site, and the attacker can re-lock for wei at any time. The approved brief accepts griefing that blocks others 'for a block'. An indefinite freeze of the launch pool, bought for a few wei, is not covered by that acceptance.

      As the author says, a real fix needs a launch-owner decision: a two-sided factory seed, a different reference definition, or explicitly accepting and documenting the indefinite lock and the LP-based recovery. It is not a unilateral code patch. At minimum, README and launch.json notes should say that the lock persists without attacker upkeep and cannot be undone by router swaps.

      Scratch Foundry test on a /tmp copy of this repo (CircuitBreakerFixture: real PoolManager, hook at a mined address). initializePool() at 158570052814919122920977766972888 (tick 152040), seedOneSided() in [92040,152040].

      Attacker holds 1e9 wei CBRK and approves swapRouter and lpRouter.

      Block N: lpRouter.modifyLiquidity{value:1000}(key, (152100, 164100, +1000, 0)); swapRouter.swap(key, (false, -1e9, 166309674447095422316896063468880 = allowedBand(open).upper)); lpRouter.modifyLiquidity(key, (152100, 164100, -1000, 0)).

      Block N+1: the same with tickLower 153000 (next multiple of 60 above the current tick), tickUpper 165000, limit 174427058096411035213075543667450 = allowedBand(up1).upper, then remove.

      Measured attacker spend: 2 wei ETH, 5 wei CBRK.

      Afterwards manager.getLiquidity(poolId) == 0 and slot0 = 174427058096411035213075543667450.

      The attacker then does nothing.

      In each of the next 3 blocks, through PoolSwapTest: exact-in 1 ETH buy with limit MIN_SQRT_PRICE+1 reverts Tripped (0xf5207678); exact-in 1 ETH buy with limit allowedBand(ref).lower reverts PhantomSwap; a 1-wei zeroForOne walk-down to allowedBand(ref).lower reverts PhantomSwap (before this round's fix the same call passed and restored the price); a 1-wei oneForZero walk-up to allowedBand(ref).upper reverts PhantomSwap; exact-out 1 ETH buy reverts.

      The price stays at 174427058096411035213075543667450 throughout.

      Expected per the brief: griefing that blocks others for at most a block.

      Actual: the buy side stays blocked until a third party adds CBRK liquidity in [tick-6000, tick) below the current price (verified: after that, swap(true, -1 ether, allowedBand(ref).lower) passes and moves the price to 165476036744151796306976405264967), which must be repeated the next block to get back into the seed.

  9. contracts publishedidentity-md-launches/launch-301-circuitbreakerhook
  10. deployedWaiting for independent review and GitHub publication.
  11. website builtafter deployment
  12. website publishedafter the website is accepted
  13. hostedWaiting for the website build and GitHub publication.
  14. checkedafter hosting