{"assessments":[],"deployments":[{"attestationHash":"7a02d8bc9dd6a197df3714baa0ce099c9997c23bb5b95f0706f757565444f80b","chainId":11155111,"contracts":[],"id":"97b298e6-98ea-4b2f-9f8e-f71c7736bc27","manifestHash":"a4a2cbd7ac4dbe9f6c53a0a193dc0078022dbc3bb9d5053bae1287fb43d68913","status":"parked"}],"fuzz":[],"identity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"interpretation":"Records acceptance and evidence. Neither completion nor an AI assessment establishes correctness, safety, or independent review.","jobId":"8aaaa07a-eb16-439a-ad3d-1964ec7aa10e","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"deded3b6aca8bab2eccb0e4ea0c55baf745d67c3c327af311f78f46e3d19788e","dependsOn":["audit_imported_code"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"a2cea02e8b33e91eeb784e0e5eaeb571cd62cd69e768d335d5834e24b3aa46e5","skillId":"adapt-contract-project","tools":[]},"key":"adapt_contract_project","kind":"code","role":"implement","skillHash":"a2cea02e8b33e91eeb784e0e5eaeb571cd62cd69e768d335d5834e24b3aa46e5","skillId":"adapt-contract-project","state":"accepted"},{"acceptedSubmissionHash":"dd925ef1cb6d714aadcdfa6869f9747455c3c40d69ae588cd610aae5dc979c67","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_economics","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"0c25f838bcee42c40cb613538f82b517d1361ad8a84eb1e2890e18c884b2644f","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_flow","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"69f037089418813cee442ddb14a50b266505387bccef102aa53fa193fb1c0b93","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","tools":[]},"key":"audit_imported_code","kind":"code","role":"review","skillHash":"9897597976b0e72440db7ca402d225aea20f3d37205ba53e7df2400ff80f29cc","skillId":"audit-imported-code","state":"accepted"},{"acceptedSubmissionHash":"3388bf144710c81b9b0ee6717e7fd99c1a6e9b1e7f7265909675a0d596e5f074","dependsOn":["adapt_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","tools":[]},"key":"audit_judge","kind":"code","role":"review","skillHash":"3014f1ea5961918ca059453a484bf4c8bcbbfc2248dbe31d94ac7c5cdf8f50bd","skillId":"audit-judge","state":"accepted"},{"acceptedSubmissionHash":"b906ef99d718605d78e92ffc4db550ac26da37e37988b3a86fab5870a5bdbac0","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_math","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"daa82171e23773affe92229aeab5b09d5fb071094987dbc96d13b5c453522110","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","tools":[]},"key":"audit_permissions","kind":"code","role":"review","skillHash":"e5ac2cb1fd91a56aa40b16487fc230c48de0d317c8266140331dd3219bb40a85","skillId":"audit-specialist","state":"accepted"},{"acceptedSubmissionHash":"d567a4e235cca9fe844192330ecbeb38da17af7df69c22d0db93f062a717f324","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"c8dfcd05af07598bedad181e07935bf4ac9f1c15ee966957ffb8ab48125bde59","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"73431852439ad3a343f3d2b7db1c43cd363b9f48f9bb51497374a0cf6d50b223","skillId":"write-foundry-tests","state":"accepted"}],"objective":"The launch deploys only src/CabalGate.sol, which creates its own QuestionBuilder and ImpactEstimator. Do not deploy or change CabalHook or CabalCoin.\n\nThe factory cannot pass a struct, so replace the constructor's Config parameter with flat arguments in this order: hook, initialOwner, intake, imd, signer, action, maxBuyAmount, maxSellAmount, maxImpactBps, maxDriftBps, panelSize, quorum, windowHours. Build the Config inside with oracleVerifier = address(this) and boolAnswerType = 0, and run the same validation. Change nothing else in the gate: the oracle struct, type string, domain, request flow, fees and limits stay exactly as audited.\n\nManifest constructorArgs: \"0xf41b6ff942a082c0d320a0c151310ac2a922a0c0\", \"$owner\", \"0x1397434cd35e8a9c8ac312a61d3a285eb31dea56\", \"0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7\", \"0x5598aa9146215bc13eb26f2c692ad1461fd32982\", \"0x6f7261636c652e72657175657374406f7261636c652d31000000000000000000\", \"1000000000000000000000000\", \"10000000000000000000000000\", \"300\", \"500\", \"30\", \"20\", \"1\".\n\nAfter launch the hook's owner calls hook.setGate(gate) once. It requires gate.hook() == the hook and gate.cabal() == CABAL, so keep both getters. Test with a mock hook that reports initialized, poolKey, poolManager, imd and cabal like the live one, and test that setGate accepts the deployed gate and refuses a second one.\n\n\ndo not launch any token or cabal hook again, only cabalgate.","parentJobId":null,"planHash":"3592735705d29cd882c2c1c94b0e7fc577f1b97c0db9dc5580b368628d93225e","previousHash":"27978f0626f514891b6193824468b5bfffc3c9242527219c85f4fdfd00a8e396","projectId":"8aaaa07a-eb16-439a-ad3d-1964ec7aa10e","publication":{"commit":"0f183d343aa806024bd8c40883a459856155e98a","deliveredAt":"2026-10-08T07:44:04.592Z","repoUrl":"https://github.com/identity-md-launches/launch-990-launch-deploys-only-src-cabalgate-sol"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[],"site":null,"snapshotHash":"3b8b9103deb252762a30ae554ea6b1f7776d9c97b66a4b45adbc8b8dfbf628c2","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"5835e48821d8827d","findings":[{"citation":"resolved","description":"This launch deploys CabalGate alone; the hook at 0xf41b6ff942a082c0d320a0c151310ac2a922a0c0 is bound to it only when its owner (0xFc3C962FAD2C1cC77f1a0d46e7B8a2De79A21774) later calls hook.setGate(gate) in a separate transaction, and that binding is single and permanent. Until it happens CabalHook._checkSwap (src/CabalHook.sol:169, `if (sender != gate || gate == address(0)) revert Unauthorized();`) refuses every swap the gate attempts, so no request can ever execute. Yet _submit checks only the chain id, the per-user slot, the size limit and the impact estimate (lines 237-247), then pulls the user's IMD for Intake.priceOf (line 273), forwards it to the Intake (line 275) and records a Pending request; the constructor (lines 142-148) reads initialized(), poolManager(), cabal(), poolKey() and imd() from the hook but never gate(). The live hook reported gate() == address(0), initialized() == true and Intake.priceOf(action, IMD) == 0.5 IMD at block 26145621, which is exactly the state the gate is launched into. From the factory deployment until the handoff (and forever if the handoff is skipped, fails, or binds a different gate) every submitBuyRequest/submitSellRequest spends 0.5 IMD plus about 570k gas on a request the oracle answers but executeBuyRequest/executeSellRequest reverts inside PoolManager.swap with the hook's Unauthorized() wrapped in v4's Hooks.WrappedError; the Intake never refunds (docs/ORACLE.md), and the user can only clearRequest once the approval expires. The window is not theoretical: the deployer, the attestation step and the hook owner's transaction are separate actors, and the gate address is public from the deployment event. Fix (one line, measured +337 runtime bytes, 23,967 < 24,576): in _submit revert (e.g. InvalidConfig) when `hook.gate() != address(this)`; optionally also revert in the constructor when `launchHook.gate() != address(0)` so a launch against an already-bound hook fails instead of deploying a permanent fee sink. Neither change touches the oracle struct, type string, domain, request flow, fees or limits.","line":237,"path":"src/CabalGate.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {PoolManager} from \"v4-core/src/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IHooks} from \"v4-core/src/interfaces/IHooks.sol\";\nimport {IUnlockCallback} from \"v4-core/src/interfaces/callback/IUnlockCallback.sol\";\nimport {PoolKey} from \"v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {ModifyLiquidityParams} from \"v4-core/src/types/PoolOperation.sol\";\nimport {BalanceDelta} from \"v4-core/src/types/BalanceDelta.sol\";\nimport {CabalCoin} from \"src/CabalCoin.sol\";\nimport {CabalHook} from \"src/CabalHook.sol\";\nimport {CabalGate} from \"src/CabalGate.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\n\ncontract ScratchIMD is ERC20 {\n    constructor() ERC20(\"IdentityMD\", \"IMD\") {}\n\n    function mint(address to, uint256 amount) external {\n        _mint(to, amount);\n    }\n}\n\n/// @dev Pulls exactly the quoted price and returns a nonzero id, as the live Intake does. It never answers.\ncontract ScratchIntake is IIntake {\n    uint256 public nonce;\n\n    function priceOf(bytes32, address) external pure returns (uint256) {\n        return 0.5 ether;\n    }\n\n    function request(bytes32, bytes calldata, Callback calldata, address token, uint256 paid)\n        external\n        returns (bytes32)\n    {\n        require(IERC20(token).transferFrom(msg.sender, address(this), paid), \"pull failed\");\n        return keccak256(abi.encode(block.chainid, address(this), ++nonce));\n    }\n}\n\n/// @notice The gate is launched alone and the hook owner binds it later. Until `hook.gate()` is this gate, no\n///         request can ever execute (CabalHook.beforeSwap refuses any sender but the bound gate), yet the gate\n///         still charges the user the non-refundable oracle price for such a request.\ncontract UnboundGateSubmissionTest is Test, IUnlockCallback {\n    address internal constant ALICE = address(0xA11CE);\n    uint160 internal constant Q96 = 1 << 96;\n\n    IPoolManager internal manager;\n    ScratchIMD internal imd;\n    CabalCoin internal token;\n    CabalHook internal hook;\n    CabalGate internal gate;\n    ScratchIntake internal intake;\n    PoolKey internal key;\n\n    function setUp() public {\n        vm.chainId(1);\n        vm.warp(1_800_000_000);\n        vm.roll(12345);\n        manager = IPoolManager(address(new PoolManager(address(this))));\n        imd = new ScratchIMD();\n        token = new CabalCoin();\n        bytes memory creation = abi.encodePacked(type(CabalHook).creationCode, abi.encode(manager, address(this), imd));\n        bytes32 salt = _mine(keccak256(creation));\n        hook = new CabalHook{salt: salt}(manager, address(this), imd);\n        (address c0, address c1) =\n            address(imd) < address(token) ? (address(imd), address(token)) : (address(token), address(imd));\n        key = PoolKey(Currency.wrap(c0), Currency.wrap(c1), 12500, 60, IHooks(address(hook)));\n        manager.initialize(key, Q96);\n        imd.mint(address(this), 100_000_000 ether);\n        manager.unlock(abi.encode(int256(10_000_000 ether)));\n        intake = new ScratchIntake();\n        gate = new CabalGate(\n            hook,\n            address(this),\n            address(intake),\n            address(imd),\n            vm.addr(0x123456),\n            bytes32(\"oracle.request@oracle-1\"),\n            uint128(1e24),\n            uint128(1e25),\n            300,\n            500,\n            30,\n            20,\n            1\n        );\n        imd.mint(ALICE, 1_000 ether);\n        vm.prank(ALICE);\n        imd.approve(address(gate), type(uint256).max);\n    }\n\n    /// @dev Fails on the current code: the gate accepts the request and spends ALICE's 0.5 IMD although the hook\n    ///      is not bound to it. Passes once submissions are refused until `hook.gate() == address(this)`.\n    function test_submissionRefusedWhileHookIsNotBoundToThisGate() public {\n        assertTrue(hook.initialized());\n        assertEq(hook.gate(), address(0), \"hook is unbound after the gate-only launch\");\n        uint256 before = imd.balanceOf(ALICE);\n        vm.prank(ALICE);\n        vm.expectRevert();\n        gate.submitBuyRequest(100 ether, \"Fund my community research for October\");\n        assertEq(imd.balanceOf(ALICE), before, \"no oracle price may be charged for a request that can never execute\");\n        assertEq(gate.activeRequest(ALICE), bytes32(0));\n        // Once the hook owner performs the handoff the same request is accepted.\n        hook.setGate(address(gate));\n        vm.prank(ALICE);\n        bytes32 id = gate.submitBuyRequest(100 ether, \"Fund my community research for October\");\n        assertEq(uint8(gate.getRequest(id).status), uint8(CabalGate.Status.Pending));\n        assertEq(imd.balanceOf(ALICE), before - 0.5 ether);\n    }\n\n    function _mine(bytes32 initCodeHash) internal view returns (bytes32) {\n        for (uint256 i; i < 400_000; ++i) {\n            address predicted = address(\n                uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), bytes32(i), initCodeHash))))\n            );\n            if (uint160(predicted) & 0x3FFF == 0x20C0) return bytes32(i);\n        }\n        revert(\"no salt\");\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        require(msg.sender == address(manager), \"manager only\");\n        int256 liquidity = abi.decode(data, (int256));\n        (BalanceDelta delta,) = manager.modifyLiquidity(key, ModifyLiquidityParams(-1200, 1200, liquidity, 0), \"\");\n        _settle(key.currency0, delta.amount0());\n        _settle(key.currency1, delta.amount1());\n        return \"\";\n    }\n\n    function _settle(Currency currency, int128 amount) private {\n        if (amount < 0) {\n            manager.sync(currency);\n            IERC20(Currency.unwrap(currency)).transfer(address(manager), uint256(-int256(amount)));\n            manager.settle();\n        } else if (amount > 0) {\n            manager.take(currency, address(this), uint128(amount));\n        }\n    }\n}","reproduction":"State: initialized CabalHook with gate() == address(0) (the live state of 0xf41b…), CabalGate deployed with the manifest's thirteen words, ALICE holds 1000 IMD and has approved the gate. Call: vm.prank(ALICE); gate.submitBuyRequest(100e18, \"Fund my community research for October\"). Expected: revert, ALICE's IMD unchanged, activeRequest[ALICE] == 0. Actual: returns a Pending id, ALICE's IMD balance drops by Intake.priceOf (0.5 IMD live), the Intake holds it, activeRequest[ALICE] == id. Continue: deliver a true attestation (status Approved), then vm.prank(ALICE); gate.executeBuyRequest(id, 1): reverts from beforeSwap with CabalHook.Unauthorized() wrapped in v4's Hooks.WrappedError (verified: status stays Approved, the 0.5 IMD stays with the Intake, activeRequest[ALICE] stays set and clearRequest reverts InvalidRequest until approvedUntil); the oracle price is gone and ALICE's slot is blocked for five more minutes. test/scratch/UnboundGateSubmission.t.sol (proof) fails on this tree with 'next call did not revert as expected' (gas 594451) and passes once _submit reverts while hook.gate() != address(this); after hook.setGate(gate) in the same test the identical request is accepted in both versions.","severity":"medium","snippet":"        if (block.chainid != 1) revert WrongChain();\n        if (activeRequest[msg.sender] != bytes32(0)) revert ActiveRequest();","title":"Gate accepts and charges oracle requests while the hook is not bound to it, so every request made before (or without) the owner's setGate handoff is paid for and can never execute"},{"citation":"resolved","description":"The brief for this launch is an evm_contracts manifest that deploys only src/CabalGate.sol with the thirteen flat constructor words and explicitly must not launch any token or hook again. The committed launch.json is the previous launch: kind univ4_hook, a hook entry for CabalHook with constructorArgs [$poolManager, $owner, IMD], a token entry for CabalCoin and a pool section; it has no contracts array. ADAPTATION.md and docs/DEPLOYMENT.md acknowledge this and defer the rewrite to a 'next assignment', but nothing in the tree supersedes the file. Validated against the LaunchManifest schema quoted in the assignment (kind const 'evm_contracts', required contracts and notes, additionalProperties false) it fails on kind, on the missing contracts array and on the extra hook/token/pool keys, so the contracts-only policy cannot deploy it; a hook-mode consumer of the same file would instead deploy a second CabalCoin and CabalHook (with $owner, not the existing hook owner) and no gate at all. Expected content: {\"kind\":\"evm_contracts\",\"contracts\":[{\"contract\":\"CabalGate\",\"constructorArgs\":[\"0xf41b6ff942a082c0d320a0c151310ac2a922a0c0\",\"$owner\",\"0x1397434cd35e8a9c8ac312a61d3a285eb31dea56\",\"0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7\",\"0x5598aa9146215bc13eb26f2c692ad1461fd32982\",\"0x6f7261636c652e72657175657374406f7261636c652d31000000000000000000\",\"1000000000000000000000000\",\"10000000000000000000000000\",\"300\",\"500\",\"30\",\"20\",\"1\"]}],\"notes\":\"...\"} (test/GateLaunch.t.sol already rehearses exactly these words). If the manifest assignment has not run yet, this is the gap it must close before anything downstream reads the file.","line":2,"path":"launch.json","reproduction":"Read launch.json: line 2 is `\"kind\": \"univ4_hook\",`; the top-level keys are kind, hook, token, pool, notes; hook.contract == \"CabalHook\", token.contract == \"CabalCoin\"; there is no contracts array and no CabalGate entry. Expected for this launch: kind \"evm_contracts\" with a single contracts entry {\"contract\":\"CabalGate\",\"constructorArgs\":[the thirteen words above]} and notes. Actual: a manifest that either fails schema validation (kind, contracts, additionalProperties) or deploys the token and hook again and no gate.","severity":"medium","snippet":"  \"kind\": \"univ4_hook\",","title":"launch.json is still the old univ4_hook manifest: as committed it would relaunch CabalCoin and CabalHook and never deploy CabalGate"}],"hash":"0c25f838bcee42c40cb613538f82b517d1361ad8a84eb1e2890e18c884b2644f","nodeId":"77efbd3f-d3a0-4431-8234-984b3a5e4df1","outcome":"completed","summary":"Review complete. The findings are in `.imd-findings.json` with all 27 entry points covered, one embedded proof, and the tracked tree unchanged.\n\n**What I found**\n\n1. **Medium. The gate charges the oracle price while the hook is not bound to it** (`src/CabalGate.sol:237`). This launch deploys the gate alone and relies on the hook owner's later `setGate` call. In that window, and forever if the handoff never happens or binds another gate, every submission pulls 0.5 IMD, forwards it to the Intake, and records a request that can never execute because the hook refuses swaps from an unbound sender. Neither the constructor nor `_submit` reads `hook.gate()`. I verified the live hook is initialized and unbound right now, and the live Intake quotes 0.5 IMD. The proof test under `test/scratch/` fails on this tree and passes with a one-line guard that keeps the runtime under the EIP-170 limit. A second scratch test confirms an approved request on the unbound gate reverts at execution, keeps the user's slot blocked, and refunds nothing.\n\n2. **Medium. `launch.json` is still the old univ4_hook manifest** (`launch.json:2`). As committed it names CabalHook and CabalCoin and has no contracts array, so it either fails the evm_contracts schema or would relaunch the token and hook with no gate. The docs defer this to a later manifest step, but nothing in the tree supersedes the file. The expected thirteen-word CabalGate entry is spelled out in the finding.\n\n**What held in my area (execution trace, periphery, first principles)**\n\n- The flat constructor builds the same Config the audited gate used, with the gate as verifier and bool type zero, and runs the same validation.\n- Submit, callback, execute, clear and slippage flows were traced end to end, including state consumed before external calls, version snapshots, replay consumption, and the unlock capability.\n- The live request record fetched from the oracle API shows the exact `consumer` object shape the gate emits, and the live vector reproduces the question hash with non-ASCII text, closing the periphery leads on body shape and hash rule.\n- The live hook bytecode equals the vendored CabalHook runtime except for its two immutables, so `setGate`, `beforeSwap` and `feeFor` behave as the gate assumes.\n- Callback gas measured about 78k of the 200k stipend.\n\n**Left unverified**\n\n- Launch gas: factory deployment of the gate and its two helpers measured about 7.75M gas locally, and the policy ceiling is not available offline.\n- Oracle latency for a 30-member panel against the one-hour request timeout is a service property I could not measure.","treeHash":null,"usage":{"cachedInputTokens":3199223,"inputTokens":610,"model":"claude-fable-5-1","outputTokens":73410,"runtime":"claude","turns":58,"wallClockMs":1460674}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"fd5402086dce252e","findings":[{"citation":"resolved","description":"Carried from the previous round as an advisory, not a defect. The author disputed only the need for a contract change and documented the power instead; that settles it. _configure (lines 214-226) accepts any cfg.intake with code and any non-zero cfg.signer; the asset is pinned to hook.imd() but the price is whatever IIntake(cfg.intake).priceOf(action, imd) returns at submission (line 272) and _pullExact pulls exactly that from msg.sender (line 274). A malicious or compromised gate owner ($owner, the paying wallet) who reconfigures the Intake to a contract quoting a user's whole balance takes that balance from any user who has an unbounded allowance and submits afterwards, and a signer under the owner's control makes every subsequent approval the owner's decision. The brief keeps owner configuration and fees as audited, configure is a public, event-emitting transaction, Ownable2Step prevents accidental handover, and ADAPTATION.md and docs/DEPLOYMENT.md now state the uncapped quote and tell operators to surface the current Intake, signer and price and users to approve only the request price plus the trade input. No change is proposed; this row exists so the privileged power stays on record.","line":210,"path":"src/CabalGate.sol","reproduction":"State: deployed gate, ALICE holds 1000 IMD and approved the gate for type(uint256).max IMD. Owner calls configure({intake: E, imd: hook.imd(), signer: anyNonZero, oracleVerifier: 0, action: nonZero, maxBuyAmount: 1e24, maxSellAmount: 1e25, maxImpactBps: 300, maxDriftBps: 500, panelSize: 30, quorum: 20, windowHours: 1, boolAnswerType: 0}) where E is a contract whose priceOf returns 1000e18 and whose request() pulls that amount and returns a non-zero id; hook.gate() == gate. ALICE calls submitBuyRequest(1e18, reason). Expected under the user's model: 0.5 IMD charged. Actual: _pullExact pulls 1000e18 IMD from ALICE, forwards it to E, ALICE's balance is 0. Reachable only through onlyOwner; the author's scratch IntakePriceTrustTest reproduces it and confirms a non-owner cannot configure.","severity":"info","snippet":"    function configure(Config calldata cfg) external onlyOwner nonReentrant {","title":"Trust assumption (settled, documented): the gate owner can point configure() at any Intake, and the price it quotes is pulled from the submitter without a cap"}],"hash":"3388bf144710c81b9b0ee6717e7fd99c1a6e9b1e7f7265909675a0d596e5f074","nodeId":"3e03dd0f-8101-4c5e-8460-57e91fd070d2","outcome":"completed","summary":"The review is complete and the findings file is written. Nothing more is needed.\n\n**Outcome: the previous medium finding is fixed, and nothing blocks this launch.**\n\n- **Unbound-hook fee sink (medium, previous round): fixed.** The only production change is one line at `src/CabalGate.sol:238`, which refuses both submission paths while the hook is not bound to this gate, before any question is built, the Intake is called or IMD is pulled. I copied all three attached proofs into test/scratch and ran them on this tree. All three pass, and the author's new HookBinding tests cover buys and sells in both currency orderings, including a differently bound hook and a refused second binding. Runtime size after the fix is 23,967 bytes, under the EIP-170 limit.\n- **Uncapped Intake quote (advisory): settled as documented.** The author kept the owner power as the brief requires and now states it in ADAPTATION.md and docs/DEPLOYMENT.md. I carried it once more as info so the trust assumption stays on record. It is not a defect.\n- **Manifest findings from all four specialists: resolved.** launch.json is now an evm_contracts manifest with exactly one CabalGate entry whose thirteen words match the brief in order, and it passes the schema's key, pattern and length rules.\n- **Full suite:** 27 suites, 165 tests pass, including the three proofs.\n\nThe coverage record answers all 27 entry points. The one open item is operational, not a defect: the economics specialist measured roughly 7.8M gas for the factory call, and the deployer's simulation against the policy ceiling is the check for that.\n\nOne environment note: the process memory cap of 1.5 GB kills a single via_ir compile of the whole project. I compiled source first and then each test file on its own, which worked. The verifier may need the same staging.","treeHash":null,"usage":{"cachedInputTokens":1767601,"inputTokens":676,"model":"claude-fable-5-1","outputTokens":18508,"runtime":"claude","turns":34,"wallClockMs":1698786}},{"artifacts":[],"attempt":1,"bundleHash":"6d4943605658e56c120e139ee77975eaacee3256c3a6867b144dafc391c781bd","device":"3d55f5b0ed8fa3df","findings":[],"hash":"37629c235286cf66b0590c9eda67cbaf682e43a30a9bc9b87295a04049570da8","nodeId":"c21f2976-094c-4923-b7be-f4770c7ae531","outcome":"completed","summary":"Implemented the 13-argument CabalGate constructor and fixed the reproduced oracle-validity issue. Gate runtime remains identical; CabalHook and CabalCoin are unchanged.\n\n`forge build` passes. All **147 tests pass**, including factory deployment and one-time hook binding.\n\nChanges and audit dispositions are in [ADAPTATION.md](/root/.identitymd/work/8aaaa07a-eb16-439a-ad3d-1964ec7aa10e/c21f2976-094c-4923-b7be-f4770c7ae531/ADAPTATION.md). The old manifest still requires replacement by the separate gate-only manifest step.","treeHash":"db0b7fd29c290c681f9b63ed169e8068ce276f55","usage":{"cachedInputTokens":5918592,"inputTokens":133036,"model":"gpt-6-astra","outputTokens":38023,"runtime":"codex","turns":21,"wallClockMs":2229067}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"2f1d693f218c1c18","findings":[],"hash":"3a16c5316421f9fccf09ab2bf35f14bd03df8aeff232eac6dfbca8ac6a2818f3","nodeId":"1adeb774-86b0-4a6d-a566-2f034f88a8da","outcome":"failed","summary":"the task produced no changes; the agent's last message was: [launch.json](/home/seat/.identitymd/work/8aaaa07a-eb16-439a-ad3d-1964ec7aa10e/1adeb774-86b0-4a6d-a566-2f034f88a8da/launch.json) already matches the brief: only `CabalGate`, all 13 exact arguments, and `$owner`. No edits were needed.\n\nManifest constraints and compiled ABI checks passed. `forge build` succeeded; `forge test` passed all 151 tests, including one-time hook binding. No repository files changed.","treeHash":null,"usage":{"cachedInputTokens":677504,"inputTokens":54546,"model":"gpt-6-astra","outputTokens":4715,"runtime":"codex","turns":5,"wallClockMs":291870}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"fa5c50e7abe46571","findings":[{"citation":"resolved","description":"QuestionBuilder.build hard-codes validForSeconds 900 into every request body, so the oracle signs expiresAt = issuedAt + 900. CabalGate.onOracleResult (src/CabalGate.sol:282) reverts InvalidAttestation when a.expiresAt <= block.timestamp, and the Intake delivers each result once under a try with no retry (docs/ORACLE.md, oracle-consumer skill), so any delivery landing 15 minutes or more after the attestation was issued is lost: the 0.5 IMD already pulled at submission is spent, the request stays Pending until the one-hour deadline, and the user cannot submit another request meanwhile (activeRequest). A delivery that lands late but inside the window also shrinks the execution window: r.approvedUntil = min(now + 300, a.expiresAt) (line 297), so a result delivered 14 minutes after issue leaves 60 seconds to execute. The gate already bounds approvals to five minutes and MAX_VALIDITY to one day, so a longer validForSeconds costs nothing in security; 900 only adds a failure mode that is outside both the user's and the owner's control, because the constant is not owner-settable (every other oracle parameter is). Observed live latency was 64 to 85 seconds from request creation to attestation for recent requests, so this is a margin problem on a congested mainnet day, not an observed failure.","line":109,"path":"src/QuestionBuilder.sol","reproduction":"State: a request id submitted at block time T0 (status Pending). Attestation a with issuedAt = T (T >= T0), expiresAt = T + 900, valid signature for the gate domain. (1) Intake delivers at block.timestamp = T + 900: onOracleResult reverts InvalidAttestation (a.expiresAt <= block.timestamp); the Intake records the result as not delivered and does not retry; the user's 0.5 IMD is gone and the id stays Pending until T0 + 3600, then only clearRequest is possible. (2) Intake delivers at block.timestamp = T + 899: status becomes Approved with approvedUntil = T + 900; executeBuyRequest at T + 900 reverts Expired, so the approval is usable for one second. Expected: a result issued inside the one-hour request window should be deliverable for the remainder of that window, with the gate's own five-minute approval bound applying afterwards. The existing tests test_approvalNeverOutlivesAttestation and testFuzz_attestationFieldsAreBound(field=15) exercise exactly these two boundaries and confirm the behaviour.","severity":"low","snippet":"            ',\"v\":1,\"validForSeconds\":900,\"window\":{\"hours\":',","title":"validForSeconds=900 is compiled into the body: a result delivered 15 minutes after issue is refused and the paid request is lost"},{"citation":"resolved","description":"Not a code defect; a launch-state fact the adapter and owner should know before the manifest's limits go live. Read from mainnet at block 26145229 through the live hook 0xf41b6ff942a082c0d320a0c151310ac2a922a0c0: pool (CABAL 0x450e5910..., IMD 0xd34a99bc..., fee 12500, spacing 60) sits at tick -128999 (2.5e-6 IMD per CABAL) with zero active liquidity; the only initialised tick above is -128940 with liquidityNet 1427203723558688610055083, i.e. a single-sided CABAL seed, and nothing is initialised below. With the manifest's maxImpactBps = 300 the gate's estimate (which counts the 59 bps empty gap as movement) returns 68 bps for a 1 IMD buy, 272 bps for 25 IMD, 873 bps for 100 IMD and 5182 bps for 1000 IMD, so submitBuyRequest reverts LimitExceeded above 28.35 IMD while maxBuyAmount is 1,000,000 IMD. estimateImpact(false, x) returns 10000 for every sell until a buy has moved the price into the seed and the hook has placed its IMD position below it, so every submitSellRequest reverts LimitExceeded at launch. With maxDriftBps = 500, two approved 25 IMD buys executed ahead of a third approval move the price 479 bps (the approval still executes); three strand it (LimitExceeded) and its 0.5 IMD is spent. All of this is owner-adjustable later through configure, which also invalidates every pending approval.","line":217,"path":"src/CabalGate.sol","reproduction":"Fork mainnet at block 26145229, deploy CabalGate(hook 0xf41b6ff9..., owner, Config{intake 0x1397434c..., imd 0xd34a99bc..., signer, verifier 0, action bytes32('oracle.request@oracle-1'), 1e24, 1e25, 300, 500, 30, 20, 1, 0}), prank 0xFc3C962FAD2C1cC77f1a0d46e7B8a2De79A21774 and hook.setGate(gate). gate.estimateImpact(true, 1000e18) = 5182; vm.prank(alice); gate.submitBuyRequest(1000e18, 'Fund my community research for October') reverts LimitExceeded. gate.estimateImpact(true, 28.35e18) = 300 passes; 28.36e18 fails. gate.estimateImpact(false, 1e18) = 10000, so submitSellRequest(1e18, ...) reverts LimitExceeded. A 25 IMD buy then executes with actual movement 272 bps, burning 0.0625 IMD and adding 0.0625 IMD of hook-owned liquidity, after which a sell of half the output returns 12.19 IMD. Expected per the brief: these are the audited limits; the numbers are reported so the owner can decide whether 300/500 bps fit the seed depth.","severity":"info","snippet":"        if (estimated > cfg.maxImpactBps) revert LimitExceeded();","title":"Against the live pool the 300 bps impact cap admits buys of at most about 28 IMD and no sells until price enters the seed range"},{"citation":"resolved","description":"forge build --sizes with the pinned profile (0.8.26, via-IR, 200 runs, bytecode_hash none) gives CabalGate runtime 23,630 bytes and init code 36,645 bytes (the init code carries QuestionBuilder and ImpactEstimator creation code, 5,913 and 4,171 bytes). The protected floor refuses runtime above 24,576 and init code above 49,152 bytes. Replacing the Config struct parameter with thirteen flat arguments changes only constructor code, which lives in the init code, so the runtime should be unchanged, but any extra public getter or validation added to the runtime has 946 bytes of room. The runtime opcode scan used by the protected test (skipping PUSH immediates) finds no DELEGATECALL, CALLCODE or SELFDESTRUCT in CabalGate, QuestionBuilder, ImpactEstimator or CabalHook; the existing test_runtimeSizeAndNoEscapeHatches scans only the hook's opcodes and only the gate's size, so the adapter should extend it to the gate's opcodes.","line":28,"path":"src/CabalGate.sol","reproduction":"Run forge build --sizes: CabalGate runtime 23,630 / margin 946; init 36,645 / margin 12,507. Any adaptation that pushes the runtime above 24,576 bytes makes the factory's CREATE2 fail with 'application constructor failed' in Contracts.protected.t.sol and the deployment revert on chain.","severity":"info","snippet":"contract CabalGate is Ownable2Step, ReentrancyGuard, IUnlockCallback {","title":"Gate runtime is 23,630 bytes, 946 bytes under EIP-170; the flat-constructor rewrite must not add runtime code"},{"citation":"resolved","description":"The constructor calls launchHook.initialized(), poolManager(), cabal(), poolKey() and, through _configure (line 187), hook.imd(), and requires cfg.intake.code.length and cfg.imd.code.length to be nonzero. On a chain where 0xf41b6ff9... has no code, the high-level call reverts and the factory's CREATE2 returns zero, which the protected probe reports as 'application constructor failed'. Verified live at block 26145191: the hook's runtime is byte-identical to the local CabalHook build after masking its two immutables; initialized() is true, gate() is zero, imd() is 0xD34a99Bc0f67aE1bbd63C660e6d0b0dd03E263B7 (matches the manifest's fourth argument), cabal() is 0x450e5910DEcEe15c3AC056E3ed66Cb5ea3Dd33BE whose runtime is byte-identical to CabalCoin with totalSupply 1e27, owner() is 0xFc3C962FAD2C1cC77f1a0d46e7B8a2De79A21774 (an EOA, the owner the launch notes name) with no pending owner, poolManager() is 0x000000000004444c5dc75cB358380D2e3dE08A90, and the pool key is (CABAL, IMD, 12500, 60, hook). The Intake 0x1397434c... has code, priceOf(action, IMD) = 0.5 IMD, callbackGas 200000, MAX_BODY_BYTES 16384; IMD has 18 decimals, no EIP-1967 implementation slot and no paused()/blacklist selectors; the identity NFT answers balanceOf for about 3,500 gas, inside the 30,000 stipend. All thirteen manifest arguments pass _configure's validation. The hook's setGate accepted a gate built from this source and refused a second one on the fork.","line":128,"path":"src/CabalGate.sol","reproduction":"Deploy the gate's creation code with the manifest's arguments on a bare EVM with no code at 0xf41b6ff9...: the constructor reverts at launchHook.initialized() and the probe fails. Deploy the same bytes on a mainnet fork (or after etching a hook mock that returns initialized()=true, poolManager(), cabal(), poolKey() and imd() as above and giving the Intake and IMD addresses code): the constructor succeeds, hook() and cabal() return the hook and 0x450e5910..., and vm.prank(0xFc3C962F...) hook.setGate(gate) succeeds while a second setGate reverts InvalidGate.","severity":"info","snippet":"        if (!launchHook.initialized()) revert InvalidConfig();","title":"The constructor reads the live hook, Intake and IMD, so a deployment rehearsal needs those addresses populated (fork or etched mocks)"},{"citation":"resolved","description":"The oracle-consumer reference verifies with SignatureChecker so a consumer can point oracleSigner at an ERC-1271 registry when the attester rotates keys. The gate recovers an EOA and compares it to cfg.signer. The live signer 0x5598aa91... has no code today, so this works now; if the protocol later publishes a registry address as the signer, configuring it here makes every attestation revert InvalidAttestation and every request a lost 0.5 IMD until the owner switches back to a bare key. Owner-settable, so no redeploy is needed, but the owner must know to set a key, not a registry.","line":288,"path":"src/CabalGate.sol","reproduction":"gate.configure with signer = any address that has code (for example the Intake). Submit a request; have the signer's key sign the attestation digest; deliver from the Intake: ECDSA.recover returns the key's EOA, which is not cfg.signer, so the callback reverts InvalidAttestation and the request stays Pending. Expected under the reference's model: an ERC-1271 isValidSignature check on the configured signer would accept it.","severity":"info","snippet":"        if (ECDSA.recover(OracleSignature.digest(a, 1, cfg.oracleVerifier), signature) != cfg.signer) {","title":"Signer verification is ECDSA-only; a contract signer such as the protocol's OracleSignerRegistry can never verify"},{"citation":"resolved","description":"Documented design, listed so the adapter and the audit panel see the concrete reach of the owner key (0xFc3C962F... via $owner). (1) configure(signer = K) or configure(intake = C) where the owner controls K or C: from the next version, an attestation signed by K, or a callback from C carrying one, approves any request, so the owner can self-approve trades up to maxImpactBps 5000 and amounts up to int128.max; the pool price and the user's own minimum output still apply. (2) configure(maxBuyAmount = 1, maxSellAmount = 1) stops every new submission above one wei: trading pauses without any pause flag. (3) Every accepted configure increments configVersion; _execute requires r.version == configVersion, so all Approved and Pending requests of users become unexecutable, their 0.5 IMD oracle fee is already spent, and clearRequest is the only exit. Ownership is two-step; renounceOwnership freezes the configuration permanently. None of these is a permission bypass; they are the owner's intended reach.","line":180,"path":"src/CabalGate.sol","reproduction":"Alice submits a buy (pays 0.5 IMD) and receives an Approved result. Owner calls configure(cfg) with any valid change (for example windowHours 2). Alice's executeBuyRequest(id, 1) reverts InvalidRequest (r.version 1 != configVersion 2); she can only clearRequest and resubmit, paying another 0.5 IMD. Existing test test_ownerConfigSnapshotsInvalidatesOldExecutionAndCanClear shows this sequence.","severity":"info","snippet":"    function configure(Config calldata cfg) external onlyOwner nonReentrant {","title":"Owner powers (trust assumptions): configure can redirect approvals to an owner-chosen signer or intake, halt trading through limits, and invalidates every pending approval at the user's cost"}],"hash":"69f037089418813cee442ddb14a50b266505387bccef102aa53fa193fb1c0b93","nodeId":"8b58ee84-a156-4cbc-b390-a6c29617fcff","outcome":"completed","summary":"The review is complete. The findings file `.imd-findings.json` is written at the repository root (it is excluded from git by a global ignore rule, as is `.imd/`), no source or configuration file was changed, and my scratch tests were removed.\n\n**Outcome.** No critical, high or medium defect in `src/CabalGate.sol` or the contracts it creates. The gate, as it arrived, works end to end against the live mainnet contracts: I deployed it on a fork from the current source with the manifest's thirteen values, the live hook owner's `setGate` accepted it and refused a second gate, the real Intake accepted the body and pulled 0.5 IMD, a signed result delivered under the 200,000 gas stipend approved the request, and a 25 IMD buy and a sell settled with the fee burned and hook liquidity added. The live hook and token runtimes are byte-identical to the local build.\n\n**Findings written (1 low, 5 info), each with a concrete input or state:**\n- **Low.** `validForSeconds` 900 is compiled into the body and not owner-settable. A result delivered 900 seconds after issue is refused, the Intake does not retry, and the user's 0.5 IMD is spent. Observed live latency is 64 to 85 seconds, so this is a margin, not an observed failure.\n- **Info, live economics.** Against today's seed (zero active liquidity, a single CABAL range starting 59 bps above price) the 300 bps cap admits buys up to about 28 IMD and refuses every sell until price enters that range. Two approved buys ahead of a third leave 479 bps drift and it still executes; three strand it.\n- **Info.** Gate runtime is 23,630 bytes, 946 under the EIP-170 limit. The flat-constructor change touches only init code, but nothing may be added to the runtime. Opcode scan is clean for all four contracts.\n- **Info.** The constructor reads the live hook, Intake and IMD, so the deployment rehearsal needs a fork or etched mocks. All live preconditions were verified: hook initialized, gate unbound, owner is the named EOA, pool key is CABAL/IMD 12500/60, Intake price 0.5 IMD, IMD plain 18-decimal token.\n- **Info.** Signer check is ECDSA only; an ERC-1271 registry as signer would never verify. The live signer is a bare key today.\n- **Info.** Owner powers as trust assumptions: redirect approvals via signer or intake, halt trading via limits, and every reconfigure invalidates pending approvals at users' cost.\n\n**Coverage.** Read in full: `CabalGate`, `CabalHook`, `CabalCoin`, `QuestionBuilder`, `ImpactEstimator`, `IIntake`, and the five libraries, plus all tests, docs and the pinned skill references. Reached live on Ethereum: the hook, CabalCoin, Intake, IMD, the identity NFT, the PoolManager pool state, and the oracle API record the hash rule was derived from, which confirmed that a request's `consumer` field is excluded from the signed hash. Not reached: the live Intake's source (behaviour verified by calls only) and the oracle's wording screen, so whether the gate's fixed question passes the ambiguity check without `allowAmbiguous` remains unverified; the existing suite of 115 tests passes.","treeHash":null,"usage":{"cachedInputTokens":4699120,"inputTokens":706,"model":"claude-fable-5-1","outputTokens":73840,"runtime":"claude","turns":55,"wallClockMs":1543755}},{"artifacts":[],"attempt":2,"bundleHash":null,"device":"72b617d4b615473a","findings":[{"citation":"resolved","description":"Merged from audit_permissions (low), audit_flow (medium) and audit_economics (low); same root cause, one finding. This launch deploys CabalGate alone against the already-initialized hook 0xf41b6ff942a082c0d320a0c151310ac2a922a0c0, whose gate() is address(0) until its owner calls setGate(gate) in a separate, later transaction; that binding is owner-only and permanent (src/CabalHook.sol:113-121). Every execute path ends in poolManager.swap, whose beforeSwap/afterSwap run CabalHook._checkSwap: `if (sender != gate || gate == address(0)) revert Unauthorized();` (src/CabalHook.sol:169). Yet _submit (src/CabalGate.sol:236-295) checks only the chain id, the per-user slot, the size limit and the impact estimate, then pulls Intake.priceOf (0.5 IMD live) from the user at line 273, forwards it to the Intake at line 275 and records a Pending request. Neither the constructor (lines 142-148 read initialized(), poolManager(), cabal(), poolKey() and imd() from the hook, never gate()) nor _submit ever checks hook.gate() == address(this). So from the factory deployment until the handoff, and forever if the handoff is skipped, fails, or binds a different gate, each submitBuyRequest/submitSellRequest spends the user's 0.5 IMD plus about 575k gas on a request whose approval can never be executed; the Intake refunds nothing and the user's single request slot stays blocked until approvedUntil (clearRequest reverts InvalidRequest before that). Impact is bounded to the oracle price plus gas per submission, with no compounding, hence medium: loss under a specific but certain condition (the handoff window exists by construction of this launch). The brief forbids changing the gate's request flow, so the fix is a scope decision for the author: (a) one line in _submit before the price is pulled, `if (hook.gate() != address(this)) revert InvalidConfig();` (one staticcall to the hook's public getter; measured by the flow specialist at +337 runtime bytes, still under EIP-170), optionally also `if (launchHook.gate() != address(0)) revert InvalidConfig();` in the constructor so a launch against an already-bound hook fails instead of deploying a permanent fee sink; neither touches the oracle struct, type string, domain, fees or limits; or (b) keep the gate byte-identical and treat hook.gate() == gate as the go-live condition operationally: the hook owner binds in the same block as or immediately after deployment, and the front end refuses submissions until the getter matches. Note the hook itself is correct: setGate is owner-only, one-time, and checks gate.hook() and gate.cabal(); the asymmetry is only that the gate treats itself as live before the hook does.","line":273,"path":"src/CabalGate.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {PoolManager} from \"v4-core/src/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IHooks} from \"v4-core/src/interfaces/IHooks.sol\";\nimport {IUnlockCallback} from \"v4-core/src/interfaces/callback/IUnlockCallback.sol\";\nimport {PoolKey} from \"v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {ModifyLiquidityParams} from \"v4-core/src/types/PoolOperation.sol\";\nimport {BalanceDelta} from \"v4-core/src/types/BalanceDelta.sol\";\nimport {CabalCoin} from \"src/CabalCoin.sol\";\nimport {CabalHook} from \"src/CabalHook.sol\";\nimport {CabalGate} from \"src/CabalGate.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\n\ncontract ScratchIMD is ERC20 {\n    constructor() ERC20(\"IdentityMD\", \"IMD\") {}\n\n    function mint(address to, uint256 amount) external {\n        _mint(to, amount);\n    }\n}\n\n/// @dev Pulls exactly the quoted price and returns a nonzero id, as the live Intake does. It never answers.\ncontract ScratchIntake is IIntake {\n    uint256 public nonce;\n\n    function priceOf(bytes32, address) external pure returns (uint256) {\n        return 0.5 ether;\n    }\n\n    function request(bytes32, bytes calldata, Callback calldata, address token, uint256 paid)\n        external\n        returns (bytes32)\n    {\n        require(IERC20(token).transferFrom(msg.sender, address(this), paid), \"pull failed\");\n        return keccak256(abi.encode(block.chainid, address(this), ++nonce));\n    }\n}\n\n/// @notice The gate is launched alone and the hook owner binds it later. Until `hook.gate()` is this gate, no\n///         request can ever execute (CabalHook.beforeSwap refuses any sender but the bound gate), yet the gate\n///         still charges the user the non-refundable oracle price for such a request.\ncontract UnboundGateSubmissionTest is Test, IUnlockCallback {\n    address internal constant ALICE = address(0xA11CE);\n    uint160 internal constant Q96 = 1 << 96;\n\n    IPoolManager internal manager;\n    ScratchIMD internal imd;\n    CabalCoin internal token;\n    CabalHook internal hook;\n    CabalGate internal gate;\n    ScratchIntake internal intake;\n    PoolKey internal key;\n\n    function setUp() public {\n        vm.chainId(1);\n        vm.warp(1_800_000_000);\n        vm.roll(12345);\n        manager = IPoolManager(address(new PoolManager(address(this))));\n        imd = new ScratchIMD();\n        token = new CabalCoin();\n        bytes memory creation = abi.encodePacked(type(CabalHook).creationCode, abi.encode(manager, address(this), imd));\n        bytes32 salt = _mine(keccak256(creation));\n        hook = new CabalHook{salt: salt}(manager, address(this), imd);\n        (address c0, address c1) =\n            address(imd) < address(token) ? (address(imd), address(token)) : (address(token), address(imd));\n        key = PoolKey(Currency.wrap(c0), Currency.wrap(c1), 12500, 60, IHooks(address(hook)));\n        manager.initialize(key, Q96);\n        imd.mint(address(this), 100_000_000 ether);\n        manager.unlock(abi.encode(int256(10_000_000 ether)));\n        intake = new ScratchIntake();\n        gate = new CabalGate(\n            hook,\n            address(this),\n            address(intake),\n            address(imd),\n            vm.addr(0x123456),\n            bytes32(\"oracle.request@oracle-1\"),\n            uint128(1e24),\n            uint128(1e25),\n            300,\n            500,\n            30,\n            20,\n            1\n        );\n        imd.mint(ALICE, 1_000 ether);\n        vm.prank(ALICE);\n        imd.approve(address(gate), type(uint256).max);\n    }\n\n    /// @dev Fails on the current code: the gate accepts the request and spends ALICE's 0.5 IMD although the hook\n    ///      is not bound to it. Passes once submissions are refused until `hook.gate() == address(this)`.\n    function test_submissionRefusedWhileHookIsNotBoundToThisGate() public {\n        assertTrue(hook.initialized());\n        assertEq(hook.gate(), address(0), \"hook is unbound after the gate-only launch\");\n        uint256 before = imd.balanceOf(ALICE);\n        vm.prank(ALICE);\n        vm.expectRevert();\n        gate.submitBuyRequest(100 ether, \"Fund my community research for October\");\n        assertEq(imd.balanceOf(ALICE), before, \"no oracle price may be charged for a request that can never execute\");\n        assertEq(gate.activeRequest(ALICE), bytes32(0));\n        // Once the hook owner performs the handoff the same request is accepted.\n        hook.setGate(address(gate));\n        vm.prank(ALICE);\n        bytes32 id = gate.submitBuyRequest(100 ether, \"Fund my community research for October\");\n        assertEq(uint8(gate.getRequest(id).status), uint8(CabalGate.Status.Pending));\n        assertEq(imd.balanceOf(ALICE), before - 0.5 ether);\n    }\n\n    function _mine(bytes32 initCodeHash) internal view returns (bytes32) {\n        for (uint256 i; i < 400_000; ++i) {\n            address predicted = address(\n                uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), bytes32(i), initCodeHash))))\n            );\n            if (uint160(predicted) & 0x3FFF == 0x20C0) return bytes32(i);\n        }\n        revert(\"no salt\");\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        require(msg.sender == address(manager), \"manager only\");\n        int256 liquidity = abi.decode(data, (int256));\n        (BalanceDelta delta,) = manager.modifyLiquidity(key, ModifyLiquidityParams(-1200, 1200, liquidity, 0), \"\");\n        _settle(key.currency0, delta.amount0());\n        _settle(key.currency1, delta.amount1());\n        return \"\";\n    }\n\n    function _settle(Currency currency, int128 amount) private {\n        if (amount < 0) {\n            manager.sync(currency);\n            IERC20(Currency.unwrap(currency)).transfer(address(manager), uint256(-int256(amount)));\n            manager.settle();\n        } else if (amount > 0) {\n            manager.take(currency, address(this), uint128(amount));\n        }\n    }\n}","reproduction":"State: real PoolManager, CabalHook initialized on a CABAL/IMD pool with liquidity, hook.gate() == address(0) (the live post-deployment, pre-setGate state), CabalGate deployed with the thirteen manifest words (owner, mock Intake pulling exactly priceOf = 0.5 IMD), ALICE holds 1000 IMD and approved the gate. Call: vm.prank(ALICE); gate.submitBuyRequest(100 ether, \"Fund my community research for October\"). Expected: revert, ALICE's IMD unchanged, activeRequest[ALICE] == 0. Actual: returns a Pending id, ALICE's balance drops by 0.5 IMD, activeRequest[ALICE] == id. Continuing on the same state with a validly signed true attestation delivered from the Intake: status becomes Approved; vm.prank(ALICE); gate.executeBuyRequest(id, 1) reverts from beforeSwap with CabalHook.Unauthorized() wrapped in v4's Hooks.Wrap__FailedHookCall; status stays Approved, the 0.5 IMD stays with the Intake, clearRequest(id) reverts InvalidRequest until block.timestamp >= approvedUntil. Verified: test/scratch/UnboundGateSubmission.t.sol fails on this tree with 'next call did not revert as expected' (gas 594451); after hook.setGate(gate) in the same test the identical request is accepted (status Pending, balance before - 0.5 IMD), which is the behaviour a fixed gate must keep. The second specialist proof (Proof_88145d506f0b) fails the same way (gas 574596).","severity":"medium","snippet":"        _pullExact(payment, msg.sender, price);","title":"Gate charges the non-refundable oracle price for requests while the live hook is not bound to it, so every request submitted before (or without) the hook owner's setGate handoff is paid for and can ne"},{"citation":"resolved","description":"Documented as a privileged power, not a permission bypass; the brief keeps owner configuration as audited and the earlier imported audit (272e6271) already lists the owner's powers. _configure accepts any cfg.intake with code and any cfg.signer; the asset is pinned to hook.imd() but the price is whatever IIntake(cfg.intake).priceOf(action, imd) returns at submission (line 271) and _pullExact pulls exactly that from msg.sender (line 273). Users approve the gate for IMD; a user who has given an unbounded allowance and submits after an owner has reconfigured the intake to a contract that quotes the user's whole balance loses it, and a signer under the owner's control makes every subsequent approval the owner's decision. Preconditions: a malicious or compromised gate owner ($owner, the paying wallet) and a submission after the reconfiguration; configure is a public, event-emitting transaction and Ownable2Step prevents accidental handover, so this is visible on chain before any user is affected. No change is proposed; operators and the front end should surface the current configuration (intake, signer, price) to submitters and users should approve only the price plus trade amount they intend to spend.","line":210,"path":"src/CabalGate.sol","reproduction":"State: deployed gate, ALICE approved the gate for type(uint256).max IMD and holds 1000 IMD. Owner calls configure({intake: E, imd: hook.imd(), signer: anyNonZero, oracleVerifier: 0, action: nonZero, maxBuyAmount: 1e24, maxSellAmount: 1e25, maxImpactBps: 300, maxDriftBps: 500, panelSize: 30, quorum: 20, windowHours: 1, boolAnswerType: 0}) where E is a contract whose priceOf returns 1000e18 and whose request() pulls that amount and returns a nonzero id. ALICE calls submitBuyRequest(1e18, reason). Expected under the user's model: 0.5 IMD charged. Actual: _pullExact pulls 1000e18 IMD from ALICE, forwards it to E, and ALICE's balance is 0. This is reachable only through onlyOwner and is reported as a trust assumption; it is not reproduced as a defect of the requested design.","severity":"info","snippet":"    function configure(Config calldata cfg) external onlyOwner nonReentrant {","title":"Trust assumption: the gate owner can point configure() at any Intake contract, and the price that contract quotes is pulled from the submitter without any cap"}],"hash":"9a3ecb440ef8918d92f0c79a3e9853a3e46515bad49befb77f2a9fd3cef3dce8","nodeId":"3e03dd0f-8101-4c5e-8460-57e91fd070d2","outcome":"completed","summary":"Review complete. The findings file is written at `.imd-findings.json` with 2 findings and a 28-row coverage record (all 27 listed entry points plus the manifest).\n\n**What I kept**\n\n- **Medium, merged from three specialists:** the gate charges the non-refundable 0.5 IMD oracle price for requests while the live hook's `gate()` is still zero. Every execute path then reverts inside `beforeSwap` with `Unauthorized`, and the user's slot stays blocked until the approval expires. Nothing in the constructor or `_submit` ever reads `hook.gate()`. I ran both specialist proofs on this tree and both fail with \"next call did not revert as expected\". The flow specialist's proof is attached as `test/scratch/UnboundGateSubmission.t.sol`. Because the brief forbids changing the request flow, I state the fix as a scope decision: a one-line `hook.gate() != address(this)` check before the price pull, or an operational go-live rule that binds the gate in the same block and refuses submissions until the getter matches.\n- **Info, trust assumption:** the gate owner can point `configure()` at any Intake, and whatever price that contract quotes is pulled from the submitter without a cap. Reported as a documented owner power with its preconditions, not as a defect.\n\n**What I dropped**\n\n- The four manifest findings (one per specialist) no longer reproduce. The tree's `launch.json` is now the gate-only `evm_contracts` manifest with the thirteen words in the brief's order, `$owner` in the second slot, and notes under the 4000-character limit.\n- The deployment-gas note is not a code defect; the deployer's simulation decides it.\n\n**What I verified myself**\n\n- `forge build` and the full suite pass: 157 tests, 0 failures, including the factory rehearsal with a mock hook and the setGate accept-once/refuse-second test the brief asked for.\n- The attestation struct, type string, domain and callback selector match the oracle-consumer reference, and the request body's keys are all ones the reference names.\n- Hook entry points are the live, unchanged contract. I traced each and marked them `holds`.\n\nOne observation outside the findings: the earlier accepted round changed QuestionBuilder's requested validity from 900 to 3900 seconds to fix an imported audit finding. It is within protocol bounds and the gate runtime is unchanged, so I did not report it.","treeHash":null,"usage":{"cachedInputTokens":820678,"inputTokens":226,"model":"claude-fable-5-1","outputTokens":17266,"runtime":"claude","turns":22,"wallClockMs":694069}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"7c0191a32541eb74","findings":[{"citation":"resolved","description":"The brief says the launch deploys only src/CabalGate.sol and must not launch the token or the hook again, and ADAPTATION.md and docs/DEPLOYMENT.md both say launch.json must be replaced with an evm_contracts manifest naming only CabalGate with the thirteen flat arguments. The file in the tree is unchanged from the previous launch: kind univ4_hook, a CabalHook entry with constructorArgs [$poolManager, $owner, IMD], a CabalCoin token entry and a pool section. It does not validate against the evm_contracts LaunchManifest schema (kind must be the constant 'evm_contracts', and 'hook', 'token' and 'pool' are not allowed properties), and if it were consumed under the univ4_hook recipe it would deploy a second CabalHook and CabalCoin and initialize a new pool, exactly what the brief forbids. This is outside the math area and is expected to be fixed by the separate manifest assignment, so it is reported as low: it blocks nothing today but the tree as it stands cannot be launched as the brief describes.","line":2,"path":"launch.json","reproduction":"Read launch.json: line 2 is \"kind\": \"univ4_hook\" and lines 3-22 describe CabalHook, CabalCoin and a pool. Expected for this launch: {\"kind\":\"evm_contracts\",\"contracts\":[{\"contract\":\"CabalGate\",\"constructorArgs\":[\"0xf41b6ff942a082c0d320a0c151310ac2a922a0c0\",\"$owner\",\"0x1397434cd35e8a9c8ac312a61d3a285eb31dea56\",\"0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7\",\"0x5598aa9146215bc13eb26f2c692ad1461fd32982\",\"0x6f7261636c652e72657175657374406f7261636c652d31000000000000000000\",\"1000000000000000000000000\",\"10000000000000000000000000\",\"300\",\"500\",\"30\",\"20\",\"1\"]}],\"notes\":\"...\"}. Actual: validating the committed file against the evm_contracts schema fails on kind and on the additional properties hook/token/pool; consuming it under its own kind launches CabalHook and CabalCoin again.","severity":"low","snippet":"  \"kind\": \"univ4_hook\",","title":"Committed launch.json is still the univ4_hook manifest that redeploys CabalHook and CabalCoin"}],"hash":"b906ef99d718605d78e92ffc4db550ac26da37e37988b3a86fab5870a5bdbac0","nodeId":"6846bfd7-49ad-4462-826c-52789f7b8aa5","outcome":"completed","summary":"Review complete. The findings file is at `.imd-findings.json` with one finding and 30 coverage rows, and my scratch tests are removed so the tree is unchanged.\n\n**Result for the assigned area (Math Precision, Boundary, Numerical Gap): clean.** Every CabalGate entry point holds. What I traced and measured:\n\n- **Amount and cast bounds.** Amounts are capped at int128.max in configuration, so the uint128 store and the negated swap amount are safe. The manifest values of 1e24 and 1e25 pass, as do 300/500 bps, 30/20 panel and the 1-hour window.\n- **Fee rounding.** The gate's pre-pulled buy fee, the callback's recomputed fee and the hook's finishSwap all compute floor(volume/400)*2 on the same volume, so they always agree. The sell-side subtraction cannot underflow. Fees below 400 wei round to zero, which is dust and clears the hook's state correctly.\n- **Impact estimator versus v4.** The estimator reproduces v4's computeSwapStep: same net-of-fee input, same sqrt-price update, floor rounding that is equal or conservative. The empty-gap case and the tick-bitmap walk match v4's compress and position logic. Under-estimation across range boundaries is caught by the post-swap re-check, which reverts before any state is kept.\n- **Attestation boundaries.** All fifteen field checks were traced. The live vector's one-day validity lands exactly on the gate's MAX_VALIDITY and is accepted. The subtraction is guarded. The widest stored question fits the 200k callback budget per the existing test.\n- **Service-side limits.** The widest possible question measures 1388 scalars and 1668 UTF-16 units, and the body is 3597 bytes, so neither counting convention can breach the 2000-character or 16 KiB caps. Each definitions value is under 512 characters.\n- **Hook liquidity rounding.** I fuzzed the single-sided liquidity formulas 20k runs per side against v4's round-up mint cost. The required amount never exceeded the hook's balance, so the fee leg inside the gate's unlock cannot revert on rounding.\n\n**One finding, low, outside my area.** The committed `launch.json` is still the old univ4_hook manifest describing CabalHook, CabalCoin and a pool. It does not validate as an evm_contracts manifest, and consumed as-is it would redeploy the hook and token the brief says not to launch. ADAPTATION.md states the separate manifest step must replace it, so this blocks nothing yet but the tree cannot launch as described until that happens.\n\nNot reported, by the validation gates: the documented single-range estimate can let a request pass at submission and revert at execution, costing the requester the non-refundable 0.5 IMD oracle fee. That is self-harm under stated design and is already covered by the definitions text and a test.","treeHash":null,"usage":{"cachedInputTokens":1976450,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":52731,"runtime":"claude","turns":33,"wallClockMs":1138446}},{"artifacts":[],"attempt":2,"bundleHash":"3a4734caa40328b17a6ee6371fe0e85f4878c79920dee28b438e6f2c64ca9248","device":"0df32ad47eb953fc","findings":[{"description":"The approved task requires an evm_contracts launch containing only CabalGate, with the thirteen supplied flat constructor arguments and the existing hook. The current manifest has kind univ4_hook, selects CabalHook and CabalCoin, and has no contracts entry for CabalGate. It describes another hook/token/pool launch rather than the authorized gate-only deployment. The gate constructor and mock-based rehearsals cannot repair this manifest. Updating launch.json is outside the tests-only assignment.","line":2,"path":"launch.json","reproduction":"Run the following Python source from the repository root. It was executed as python3 test/scratch/check_gate_manifest.py and exited 1 with AssertionError. Expected: kind evm_contracts and exactly the CabalGate contract entry below. Actual: kind univ4_hook, contracts absent, hook.contract CabalHook, token.contract CabalCoin.\n\nimport json\nfrom pathlib import Path\n\nmanifest = json.loads(Path(\"launch.json\").read_text())\nexpected = [{\n    \"contract\": \"CabalGate\",\n    \"constructorArgs\": [\n        \"0xf41b6ff942a082c0d320a0c151310ac2a922a0c0\", \"$owner\",\n        \"0x1397434cd35e8a9c8ac312a61d3a285eb31dea56\",\n        \"0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7\",\n        \"0x5598aa9146215bc13eb26f2c692ad1461fd32982\",\n        \"0x6f7261636c652e72657175657374406f7261636c652d31000000000000000000\",\n        \"1000000000000000000000000\", \"10000000000000000000000000\",\n        \"300\", \"500\", \"30\", \"20\", \"1\",\n    ],\n}]\nactual = {key: manifest.get(key) for key in (\"kind\", \"contracts\", \"hook\", \"token\")}\nassert manifest.get(\"kind\") == \"evm_contracts\" and manifest.get(\"contracts\") == expected, (\n    f\"Expected evm_contracts with exactly {expected}; actual {actual}\"\n)\n","severity":"high","title":"Launch manifest still deploys CabalHook and CabalCoin instead of the requested CabalGate"}],"hash":"c8dfcd05af07598bedad181e07935bf4ac9f1c15ee966957ffb8ab48125bde59","nodeId":"3d2c9d11-a0b0-4f90-9fe0-34162bc91516","outcome":"completed","summary":"Added constructor failure coverage verifying helper rollback and successful retry at the same address.\n\n`forge build` and `forge test` passed: **162 tests, zero failures**, including invariant campaigns.\n\nReported a high-severity mismatch in `.imd-findings.json`: `launch.json` still selects CabalHook/CabalCoin instead of the required CabalGate-only launch.","treeHash":"39da5f9a11a40d86c7ea2a055f942c3795cf0920","usage":{"cachedInputTokens":1345408,"inputTokens":100432,"model":"gpt-6-astra","outputTokens":6883,"runtime":"codex","turns":6,"wallClockMs":311165}},{"artifacts":[],"attempt":2,"bundleHash":"a306c8199543f33c5930544ea6c96b02fd84ab422738d5cc84fe57905d60c760","device":"0cd01c5082189cbf","findings":[],"hash":"d567a4e235cca9fe844192330ecbeb38da17af7df69c22d0db93f062a717f324","nodeId":"1adeb774-86b0-4a6d-a566-2f034f88a8da","outcome":"completed","summary":"Updated only [launch.json](/root/.identitymd/work/8aaaa07a-eb16-439a-ad3d-1964ec7aa10e/1adeb774-86b0-4a6d-a566-2f034f88a8da/launch.json), adding the pre-launch check that `hook.gate()` is unset. It retains only `CabalGate`, the exact 13 arguments, and `$owner`.\n\nManifest and compiled ABI checks passed. `forge build` succeeded; `forge test` passed all 151 tests, including one-time hook binding.","treeHash":"7085ccb3c1c501e3965fc43d117d4d0c66e76955","usage":{"cachedInputTokens":593408,"inputTokens":75086,"model":"gpt-6-astra","outputTokens":4455,"runtime":"codex","turns":6,"wallClockMs":341519}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"74a99f640688d37b","findings":[{"citation":"resolved","description":"Trust gap (access x economics). The launch deploys only CabalGate; the swap permission lives in the already-deployed hook and is granted later by a different actor (the hook owner calling setGate). Between deployment and that call, and forever if the call never happens (hook owner lost, hook already bound to another gate, or the owner declines), nothing in _submit checks hook.gate() == address(this). The gate still pulls Intake.priceOf (0.5 IMD) from the user, files the request, and the oracle answers. On a true answer the request becomes Approved, but every execute path reaches CabalHook._checkSwap with sender == this unbound gate and reverts Unauthorized (wrapped by v4 as Wrap__FailedHookCall). clearRequest refuses while block.timestamp < approvedUntil, so the user's single slot is also stuck for the five-minute window. The price is never refunded by design. The hook side is correct (owner-only, one-time binding, both getters present and checked); the asymmetry is that the gate treats itself as live before the hook does. The brief forbids changing the gate, so the remedy is operational: the hook owner must call setGate in the same block as, or immediately after, deployment, the launch handoff should treat 'hook.gate() == gate' as the go-live condition, and the UI must refuse submissions until it holds. If the author is allowed to touch the gate, a one-line 'if (hook.gate() != address(this)) revert' in _submit closes it; that is a design-scope decision the brief currently rules out.","line":236,"path":"src/CabalGate.sol","reproduction":"State: CabalFixture (real PoolManager, real CabalHook bound to gate #1). Deploy a second gate with deployGate(hook); hook.gate() != address(fresh). Alice: imd.approve(fresh, max); fresh.submitBuyRequest(100 ether, reason) -> succeeds, Alice's IMD drops by intake.price() (3 IMD in the mock, 0.5 IMD live). Intake delivers a validly signed true attestation for the id -> status Approved. Alice: fresh.executeBuyRequest(id, 1) -> reverts inside CabalHook.beforeSwap (Unauthorized, wrapped by Hooks library); status stays Approved. Alice: fresh.clearRequest(id) -> reverts InvalidRequest until block.timestamp >= approvedUntil; after warp(+300) it clears and Alice's balance is still before - price. Expected: a gate that cannot trade refuses (or at least does not charge for) requests; actual: it charges and approves them. Verified with test/scratch/UnboundGate.t.sol (passes, demonstrating the behaviour; see description for why no fix-passing proof is attached).","severity":"low","snippet":"    function _submit(bool buy, uint256 amount, string calldata reason) private returns (bytes32 id) {","title":"Gate accepts paid oracle requests while the live hook has not bound it, so every approval in that window is unexecutable and the 0.5 IMD is lost"},{"citation":"resolved","description":"Not a Solidity defect and not a blocker for this early review, but a configuration gap the judge should see. The adaptation notes (ADAPTATION.md, docs/DEPLOYMENT.md) say the manifest step must replace the file; until it does, the only manifest in the tree contradicts the brief (gate-only launch, no token or hook). The CabalGate constructor, argument order, owner placeholder and the thirteen manifest words in the brief are all consistent with src/CabalGate.sol and test/GateLaunch.t.sol, so when the manifest is written as {kind: evm_contracts, contracts: [{contract: CabalGate, constructorArgs: [hook, $owner, intake, imd, signer, action, 1e24, 1e25, 300, 500, 30, 20, 1]}]} it will validate against both the schema and _configure.","line":2,"path":"launch.json","reproduction":"Validate the current launch.json against the LaunchManifest schema in the assignment: 'kind' is \"univ4_hook\" but the schema requires const \"evm_contracts\"; required property 'contracts' is absent; 'hook', 'token' and 'pool' are additional properties. Expected: a single-contract evm_contracts manifest for CabalGate; actual: schema failure, and if a univ4_hook pipeline consumed it, a second CabalCoin and CabalHook would be deployed, which the brief forbids.","severity":"info","snippet":"  \"kind\": \"univ4_hook\",","title":"launch.json in the tree is the previous univ4_hook token/hook manifest; it fails the evm_contracts schema and names CabalHook/CabalCoin which this launch must not redeploy"}],"hash":"daa82171e23773affe92229aeab5b09d5fb071094987dbc96d13b5c453522110","nodeId":"1c8777ec-a72c-4697-8dbf-cd427bf5809e","outcome":"completed","summary":"The findings file is written and validated. Snippets match the tree, all 27 listed entry points have a coverage row, and the scratch test lives in the ignored `test/scratch/` directory, so no tracked file changed.\n\n**Outcome.** The gate's permission model holds across the Access Control, Trust Gap and Asymmetry checklists. I found one low-severity trust gap and one informational configuration gap. No critical or high defects, so no fix-proving test is attached.\n\n**Finding 1, low.** The gate charges the oracle price and files requests even when the hook has not bound it. The launch deploys only the gate; swap permission is granted later by the hook owner through setGate. In that window, or forever if binding never happens, a user pays 0.5 IMD, the oracle approves, and every execute path reverts inside the hook's beforeSwap. The slot also stays stuck for the five-minute approval window. Reproduced on the real PoolManager and hook with a second, unbound gate. The brief forbids changing the gate, so the remedy is operational: bind immediately after deployment and treat the hook's gate pointer as the go-live condition.\n\n**Finding 2, info.** The tracked launch.json is still the old token-and-hook manifest. It fails the evm_contracts schema and names contracts this launch must not redeploy. The manifest step is expected to replace it, and the constructor, argument order and the thirteen manifest words all check out against the source and the launch rehearsal test.\n\n**What I verified in my area.**\n- Every state-changing gate function has the right guard: owner, requester, intake-of-version, or PoolManager with a consumed capability.\n- The flat constructor matches the brief's order, builds Config with the gate as verifier and bool type 0, and runs the unchanged validation.\n- Both getters the hook's setGate needs exist, and the mock-hook and real-hook tests confirm accept-once and refuse-second.\n- Paired paths are symmetric: buy and sell, one-arg and two-arg execute, approve and reject branches, deadline and approval expiry boundaries.\n- Owner powers (reconfigure, renounce, verifier change) are documented trust assumptions with no unprivileged amplifier.\n\n**Not reachable offline.** Whether the live hook is currently unbound with a reachable owner, and whether the oracle plane accepts the body's consumer key. Both are recorded as unreached rows. The full suite still passes at 147 tests.","treeHash":null,"usage":{"cachedInputTokens":1857947,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":37481,"runtime":"claude","turns":51,"wallClockMs":719794}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"229c8cb0d9067fbe","findings":[{"citation":"resolved","description":"Flow gap (execution x periphery x first principles). _submit checks limits and impact, builds the body and pulls Intake.priceOf (0.5 IMD on mainnet, quoted live from 0x1397434c...) from the user, but never checks that the hook is bound to this gate (hook.gate() == address(this)). Execution runs poolManager.swap, whose beforeSwap/afterSwap call CabalHook._checkSwap, which reverts Unauthorized whenever `sender != gate || gate == address(0)` (src/CabalHook.sol:169). Binding is one-time and owner-only (src/CabalHook.sol:113-121). On the live hook 0xf41b6ff942a082c0d320a0c151310ac2a922a0c0 gate() is zero today (read at block 26145662: initialized true, gate 0x0, owner 0xFc3C962FAD2C1cC77f1a0d46e7B8a2De79A21774), and the brief's launch has an explicit window between the factory deployment and the hook owner's setGate call. During that window, and permanently if the owner binds another gate or never binds, every submission spends the oracle price plus about 575k gas on a request that cannot execute: the oracle's approval, if it arrives, reverts at executeBuy/SellRequest, and the Intake refunds nothing. The guarantee broken is the gate's own: the oracle charge buys a decision that can be acted on in this pool. Severity is bounded (0.5 IMD plus gas per victim, no compounding), hence low; it becomes a permanent fee sink if the hook is ever bound to a different gate. Minimal fix that keeps the oracle struct, body, fees and limits unchanged: in _submit, before pulling the price, `if (hook.gate() != address(this)) revert InvalidConfig();` (one staticcall to the hook's public `gate` getter). If the request flow must stay byte-identical, the operator must bind the gate in the same block as the deployment or withhold the gate address until setGate has been mined, and accept the fee-sink outcome if the hook is bound elsewhere.","line":273,"path":"src/CabalGate.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {ERC20} from \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport {PoolManager} from \"v4-core/src/PoolManager.sol\";\nimport {IHooks} from \"v4-core/src/interfaces/IHooks.sol\";\nimport {PoolKey} from \"v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {ModifyLiquidityParams} from \"v4-core/src/types/PoolOperation.sol\";\nimport {BalanceDelta} from \"v4-core/src/types/BalanceDelta.sol\";\nimport {CabalCoin} from \"src/CabalCoin.sol\";\nimport {CabalHook} from \"src/CabalHook.sol\";\nimport {CabalGate} from \"src/CabalGate.sol\";\nimport {IIntake} from \"src/interfaces/IIntake.sol\";\n\ncontract PlainToken is ERC20 {\n    constructor() ERC20(\"IdentityMD\", \"IMD\") {}\n\n    function mint(address to, uint256 amount) external {\n        _mint(to, amount);\n    }\n}\n\n/// @dev Pulls exactly the price like the live Intake and returns a fresh id.\ncontract PlainIntake is IIntake {\n    uint256 public nonce;\n\n    function priceOf(bytes32, address) external pure returns (uint256) {\n        return 0.5 ether;\n    }\n\n    function request(bytes32, bytes calldata, Callback calldata, address token, uint256 paid)\n        external\n        returns (bytes32)\n    {\n        require(IERC20(token).transferFrom(msg.sender, address(this), paid));\n        return keccak256(abi.encode(block.chainid, address(this), ++nonce));\n    }\n}\n\n/// @notice A gate whose hook is not (or no longer) bound to it must not accept paid submissions, because the\n///         hook refuses every swap from an unbound gate and the oracle price is never refunded.\ncontract UnboundSubmissionProofTest is Test {\n    uint256 constant KEY = 0x123456;\n    address constant ALICE = address(0xA11CE);\n    uint160 constant Q96 = 1 << 96;\n    // beforeInitialize | beforeSwap | afterSwap = 0x20C0 in the low 14 address bits.\n    address constant HOOK_ADDR = address(uint160(0x1234000000000000000000000000000000000000) | uint160(0x20C0));\n\n    PoolManager manager;\n    PlainToken imd;\n    CabalCoin token;\n    CabalHook hook;\n    PlainIntake intake;\n    CabalGate gate;\n    PoolKey key;\n\n    function setUp() public {\n        vm.chainId(1);\n        vm.warp(1_800_000_000);\n        vm.roll(12345);\n        manager = new PoolManager(address(this));\n        imd = new PlainToken();\n        token = new CabalCoin();\n        deployCodeTo(\"CabalHook.sol:CabalHook\", abi.encode(manager, address(this), imd), HOOK_ADDR);\n        hook = CabalHook(HOOK_ADDR);\n        (address c0, address c1) = address(imd) < address(token)\n            ? (address(imd), address(token))\n            : (address(token), address(imd));\n        key = PoolKey(Currency.wrap(c0), Currency.wrap(c1), 12500, 60, IHooks(HOOK_ADDR));\n        manager.initialize(key, Q96);\n        imd.mint(address(this), 100_000_000 ether);\n        manager.unlock(abi.encode(int24(-1200), int24(1200), int256(10_000_000 ether)));\n        intake = new PlainIntake();\n        gate = new CabalGate(\n            hook, address(this), address(intake), address(imd), vm.addr(KEY), bytes32(\"oracle.request@oracle-1\"),\n            1e24, 1e25, 300, 500, 30, 20, 1\n        );\n        // The launch handoff has not happened: hook.gate() is still zero (or could be another gate).\n        assertEq(hook.gate(), address(0));\n        imd.mint(ALICE, 1000 ether);\n        vm.prank(ALICE);\n        imd.approve(address(gate), type(uint256).max);\n    }\n\n    function unlockCallback(bytes calldata data) external returns (bytes memory) {\n        require(msg.sender == address(manager));\n        (int24 lower, int24 upper, int256 liquidity) = abi.decode(data, (int24, int24, int256));\n        (BalanceDelta delta,) = manager.modifyLiquidity(key, ModifyLiquidityParams(lower, upper, liquidity, 0), \"\");\n        _settle(key.currency0, delta.amount0());\n        _settle(key.currency1, delta.amount1());\n        return \"\";\n    }\n\n    function _settle(Currency currency, int128 delta) internal {\n        if (delta < 0) {\n            manager.sync(currency);\n            IERC20(Currency.unwrap(currency)).transfer(address(manager), uint256(-int256(delta)));\n            manager.settle();\n        }\n    }\n\n    /// @notice While hook.gate() != address(gate), a submission must be refused so the user keeps the oracle\n    ///         price. On the current code it is accepted, 0.5 IMD is spent, and the approved request can never\n    ///         execute because CabalHook.beforeSwap reverts Unauthorized for an unbound sender.\n    function test_submissionRefusedWhileHookIsNotBoundToThisGate() public {\n        uint256 before = imd.balanceOf(ALICE);\n        vm.prank(ALICE);\n        vm.expectRevert();\n        gate.submitBuyRequest(1 ether, \"Fund my community research for October\");\n        assertEq(imd.balanceOf(ALICE), before, \"oracle price was charged for a request that cannot execute\");\n        assertEq(gate.activeRequest(ALICE), bytes32(0));\n    }\n}","reproduction":"State: CabalGate deployed with the manifest words against an initialized CabalHook whose gate() is address(0) (the post-deployment, pre-setGate state; also the state if the hook owner binds another gate). 1) Alice approves IMD to the gate and calls submitBuyRequest(1e18, \"Fund my community research for October\"). Actual: succeeds, Alice's IMD balance drops by 0.5e18, activeRequest[Alice]=id, status Pending. 2) The Intake delivers a valid true attestation for id -> status Approved, approvedUntil = now+300. 3) Alice calls executeBuyRequest(id, 1). Actual: reverts (PoolManager bubbles CabalHook.Unauthorized from beforeSwap). Alice's 0.5 IMD is gone; after approvedUntil she can only clearRequest(id). Expected: step 1 refuses the submission (or the gate cannot take payment) while hook.gate() != address(gate). Demonstrated on the current code by test/scratch/UnboundSubmission.t.sol::test_demonstrateApprovedRequestCannotExecuteAndFeeIsLost (passes, showing the loss) and by the proof below, which fails on the current code (`next call did not revert as expected`) and passes with the one-line check added to _submit (verified against a scratch copy of the gate).","severity":"low","snippet":"        _pullExact(payment, msg.sender, price);","title":"Gate accepts and charges oracle requests while the hook is not bound to it, so the paid request can never execute"},{"citation":"resolved","description":"The brief launches only CabalGate through the contracts-only recipe, and the canonical LaunchManifest requires kind \"evm_contracts\", a contracts array and notes, with no other properties. The file in the tree has kind univ4_hook, hook/token/pool objects and no contracts array, so it fails the schema on the kind constant, on additionalProperties and on the required contracts field; and its content describes exactly the second token/hook/pool launch the brief forbids (\"do not launch any token or cabal hook again, only cabalgate\"). ADAPTATION.md and docs/DEPLOYMENT.md say the separate manifest assignment replaces it; nothing in the tree yet carries the thirteen constructor words. For the record, the brief's words are consistent with the flat constructor and pass _configure: deploying CabalGate with (0xf41b6ff9..., owner, 0x1397434c..., 0xd34a99bc..., 0x5598aa91..., 0x6f7261636c652e72657175657374406f7261636c652d31000000000000000000, 1e24, 1e25, 300, 500, 30, 20, 1) succeeded on a mainnet fork at block 26145662 (hook initialized, hook.imd() == 0xD34a99Bc..., Intake and IMD have code, priceOf == 0.5 IMD, hook.cabal() == 0x450e5910...), and a buy/sell round trip executed after hook.setGate. The expected manifest is {\"kind\":\"evm_contracts\",\"contracts\":[{\"contract\":\"CabalGate\",\"constructorArgs\":[\"0xf41b6ff942a082c0d320a0c151310ac2a922a0c0\",\"$owner\",\"0x1397434cd35e8a9c8ac312a61d3a285eb31dea56\",\"0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7\",\"0x5598aa9146215bc13eb26f2c692ad1461fd32982\",\"0x6f7261636c652e72657175657374406f7261636c652d31000000000000000000\",\"1000000000000000000000000\",\"10000000000000000000000000\",\"300\",\"500\",\"30\",\"20\",\"1\"]}],\"notes\":\"...\"}.","line":2,"path":"launch.json","reproduction":"Run `python3 -c \"import json;d=json.load(open('launch.json'));print(d['kind'],'contracts' in d,sorted(d))\"` in the repository root. Actual: `univ4_hook False ['hook','kind','notes','pool','token']`. Expected for this launch: kind evm_contracts with a single CabalGate entry carrying the thirteen words above. Validating the file with LaunchManifest rejects it (kind const mismatch, unknown properties hook/token/pool, missing contracts).","severity":"low","snippet":"  \"kind\": \"univ4_hook\",","title":"launch.json in the tree is the previous univ4_hook token+hook manifest; it fails the evm_contracts schema and, if consumed, would redeploy CabalCoin and CabalHook"},{"citation":"resolved","description":"Not a code defect: evidence the deployer's gasCeilingWei simulation needs. With the manifest words, the CREATE2 itself costs 7,145,645 gas and the factory's deploy call 7,781,071 gas (measured in test/scratch/DeployGas.t.sol); add the 21,000 base and roughly 0.6M for 37,135 calldata bytes and the launch transaction lands near 8.4M gas before the real factory's own bookkeeping. The constructor creates QuestionBuilder and ImpactEstimator (lines 147-148), which is most of the cost beyond the 23,630-byte gate runtime (946 bytes under EIP-170; init code 37,035 bytes, under EIP-3860's 49,152). If the policy ceiling converts to fewer than about 8.5M gas at the simulated gas price, the launch is refused at simulation.","line":147,"path":"src/CabalGate.sol","reproduction":"forge test --match-path test/scratch/DeployGas.t.sol -vv logs: init code bytes 37035, create2 gas (inner) 7145645, factory call gas 7781071, gate runtime bytes 23630. Compare against the pinned launch policy's gas ceiling.","severity":"info","snippet":"        questionBuilder = new QuestionBuilder();","title":"Gate deployment needs about 7.8M gas at the factory call (37,035-byte init code, two helpers created in the constructor); confirm it fits the pinned policy gas ceiling"}],"hash":"dd925ef1cb6d714aadcdfa6869f9747455c3c40d69ae588cd610aae5dc979c67","nodeId":"ff9e50f7-4082-458e-9c0f-3d1f199ba39b","outcome":"completed","summary":"Review complete. The findings file is at `.imd-findings.json` in the repository root, with three findings and coverage rows for all 27 listed entry points plus four invariant rows.\n\n**What I found**\n\n- **Low, with proof:** the gate charges the oracle price for submissions while the hook is not bound to it. Submission never checks that the hook's gate is this contract, and the hook refuses every swap from an unbound sender, so an approved request reverts at execution and the 0.5 IMD is never refunded. The live hook is unbound today, so this state exists for every launch until the owner's binding call, and permanently if the hook is ever bound elsewhere. The proof under `test/scratch/UnboundSubmissionProof.t.sol` fails on the current code and passes against a scratch copy of the gate with a one-line check added to the submit path.\n- **Low:** the tree's manifest is still the previous univ4_hook token and hook launch. It fails the evm_contracts schema and describes exactly the redeployment the brief forbids. The brief's thirteen constructor words themselves are correct: they deployed and traded successfully on a mainnet fork.\n- **Info:** deployment measures about 7.8M gas at the factory call with a 37,035-byte init code, because the constructor creates two helper contracts. The pinned policy's gas ceiling is the evidence still needed.\n\n**What held up**\n\nThe buy and sell paths, fee legs, holdings accounting, drift and impact caps, approval window, clearing, and the unlock callback all trace cleanly. The gate retains no tokens after any flow. The existing suite passes with 147 tests. Live chain reads confirm the handoff preconditions: hook initialized, unbound, owned by 0xFc3C..., paired with IMD as currency1, Intake quoting 0.5 IMD, and the live hook bytecode matches the local build byte for byte outside immutables. A fork rehearsal at block 26145662 deployed the gate, bound it, bought 20 IMD with the estimate matching the executed movement exactly, compounded the resulting protocol position, and sold back. The 300 bps cap admits roughly 28 IMD per buy, and sells are refused until price enters the seed range, as the earlier audit recorded. A live oracle request answered an 11-member panel in 85 seconds, so the compiled one-hour deadline has headroom.\n\n**Not reached**\n\nThe policy gas ceiling, the oracle service's acceptance of a 30-member panel and the body's consumer field, and the full semantics of the 45 KB ownable IMD token are outside what I could verify locally.","treeHash":null,"usage":{"cachedInputTokens":3743128,"inputTokens":578,"model":"claude-fable-5-1","outputTokens":99464,"runtime":"claude","turns":60,"wallClockMs":2208070}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"fdeac05268aded13","findings":[],"hash":"de936568127567b996f3fa6d7bc09252b216cbb05d95ca1b9ceaa961ccbb4d92","nodeId":"3d2c9d11-a0b0-4f90-9fe0-34162bc91516","outcome":"failed","summary":"Your workspace is out of credits. Ask your workspace owner to refill in order to continue.","treeHash":null,"usage":{"cachedInputTokens":0,"inputTokens":0,"model":"gpt-6-astra","outputTokens":0,"runtime":"codex","turns":24,"wallClockMs":2547418}},{"artifacts":[],"attempt":1,"bundleHash":"a8b644cb47618766be93df75223e1ca1ffbfe396dc2b95b197ce2d6d71d8dd87","device":"1d142f9c9d30c62a","findings":[],"hash":"deded3b6aca8bab2eccb0e4ea0c55baf745d67c3c327af311f78f46e3d19788e","nodeId":"c21f2976-094c-4923-b7be-f4770c7ae531","outcome":"completed","summary":"Fixed the reproduced fee-loss issue: CabalGate now rejects submissions before charging unless the hook is bound to it.\n\n`forge build` and `forge test` pass: 153 tests, including the supplied proof.\n\nUpdated `ADAPTATION.md` and recorded all eight finding responses in `.imd-responses.json`. CabalHook and CabalCoin are unchanged. Nothing was deployed.","treeHash":"81450031b66df73415dbb9cca65db72cbb3046f8","usage":{"cachedInputTokens":1838976,"inputTokens":107212,"model":"gpt-6-astra","outputTokens":11163,"runtime":"codex","turns":6,"wallClockMs":442369}},{"artifacts":[],"attempt":1,"bundleHash":"6efe443420d3837e12b67428b812aa2f8b20a3f7a37c9d0312bcbb4b3988b827","device":"f3c310dfe443399d","findings":[],"hash":"ea764158832ed1c5c3c044acf055dca6bc9c1c568b36bca858dbc8adf303b589","nodeId":"1adeb774-86b0-4a6d-a566-2f034f88a8da","outcome":"completed","summary":"Updated only `launch.json` to deploy CabalGate with the exact 13 arguments, `$owner`, and notes for the hook owner’s one-time binding.\n\nValidation passed: schema and compiled ABI checks, offline build, all 147 tests, and a second fuzz seed with 1,024 runs.","treeHash":"fa696ed82239fa619104df10698747d795ee7dd6","usage":{"cachedInputTokens":947456,"inputTokens":59582,"model":"gpt-6-astra","outputTokens":6444,"runtime":"codex","turns":7,"wallClockMs":354001}},{"artifacts":[],"attempt":1,"bundleHash":"3a356fab725b23467eb43b0263b1b8691ec75839b132b213ec4482d82b163022","device":"40aae51ff9854f9f","findings":[{"description":"The task requires an evm_contracts launch containing only CabalGate, attached to the already initialized hook at 0xf41b6ff942a082c0d320a0c151310ac2a922a0c0. The current manifest instead has kind=univ4_hook, hook.contract=CabalHook and token.contract=CabalCoin, and no contracts entry for CabalGate. Using it cannot produce the requested gate-only launch and selects the expressly forbidden hook/token launch mode. The constructor itself accepts the required thirteen flat arguments; the new tests exercise those words directly. A tests-only contributor cannot repair the launch manifest.","line":2,"path":"launch.json","reproduction":"Read launch.json with Python: m=json.load(open(\"launch.json\")); assert m[\"kind\"] == \"evm_contracts\" and len(m[\"contracts\"]) == 1 and m[\"contracts\"][0][\"contract\"] == \"CabalGate\". This check was run locally and fails at kind. Actual values are kind=\"univ4_hook\", hook.contract=\"CabalHook\", token.contract=\"CabalCoin\", contracts absent. Expected: kind=\"evm_contracts\" and exactly one CabalGate entry with constructorArgs [\"0xf41b6ff942a082c0d320a0c151310ac2a922a0c0\", \"$owner\", \"0x1397434cd35e8a9c8ac312a61d3a285eb31dea56\", \"0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7\", \"0x5598aa9146215bc13eb26f2c692ad1461fd32982\", \"0x6f7261636c652e72657175657374406f7261636c652d31000000000000000000\", \"1000000000000000000000000\", \"10000000000000000000000000\", \"300\", \"500\", \"30\", \"20\", \"1\"]. No on-chain transaction is needed to reproduce this manifest mismatch.","severity":"high","title":"Launch manifest still selects a new CabalHook and CabalCoin instead of only CabalGate"}],"hash":"f27a23e18cf194bb6ad3666a0f3dc36a56146cd37835e788e18de0b29b0d7ed9","nodeId":"3d2c9d11-a0b0-4f90-9fe0-34162bc91516","outcome":"completed","summary":"Added constructor, failure-path, oracle-vector, and randomized accounting tests.\n\n- `forge build`: passed.\n- `forge test`: 157 passed, zero failures or skips.\n- Slither completed; 35 alerts reviewed.\n- Aderyn unavailable.\n\nReported a high-severity defect in `.imd-findings.json`: `launch.json` still selects CabalHook/CabalCoin deployment instead of only CabalGate.\n\nProduction contracts and configuration remain unchanged.","treeHash":"9b3fe2d15557950f50f5fc2223d987886f5f4c88","usage":{"cachedInputTokens":2133376,"inputTokens":131024,"model":"gpt-6-astra","outputTokens":22277,"runtime":"codex","turns":7,"wallClockMs":738859}}],"verification":[{"checks":[{"durationMs":124485,"exitCode":0,"name":"build","output":"Compiling 118 files with Solc 0.8.26\nSolc 0.8.26 finished in 124.25s\nCompiler run successful!\nwarning[unsafe-typecast]: typecast can truncate values\n  ╭▸ src/libraries/MainnetDefaults.sol:9:54\n  │\n9 │     address internal constant IDENTITY_NFT = address(bytes20(hex\"0000ec93127baa929e58e97dd0095a2bfb38ec1d\"));\n  │                                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n  │\n  ├ note: consider disabling this lint if you're certain the cast is safe\n  │       \n  │       // casting to 'bytes20' is safe because [explain why]\n  │       // forge-lint: disable-next-line(unsafe-typecast)\n  │       \n  │       \n  ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/MainnetDefaults.sol:10:40\n   │\n10 │     bytes32 internal constant ACTION = bytes32(\"oracle.request@oracle-1\");\n   │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:71:83\n   │\n71 │             if (compressed < minCompressed || compressed > maxCompressed) return (false, 0);\n   │                                                                                   ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/QuestionBuilder.sol:98:16\n    │\n 98 │           body = abi.encodePacked(\n    │ ┏━━━━━━━━━━━━━━━━┛\n 99 │ ┃             '{\"answerType\":\"bool\",\"chainId\":1,\"consumer\":{\"chainId\":1,\"verifyingContract\":\"',\n100 │ ┃             c.verifier.toHexString(),\n101 │ ┃             '\"},\"definitions\":{',\n    ‡ ┃\n112 │ ┃             \"}}\"\n113 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:78:29\n   │\n78 │                     return (true, (compressed - int24(uint24(bitPos - BitMath.mostSignificantBit(masked)))) * spacing);\n   │                             ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:84:29\n   │\n84 │                     return (true, (compressed + int24(uint24(BitMath.leastSignificantBit(masked) - bitPos))) * spacing);\n   │                             ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n   ╭▸ src/libraries/CanonicalRequest.sol:21:13\n   │\n21 │ ┏             abi.encodePacked(\n22 │ ┃                 '{\"answerType\":\"bool\",\"chainId\":1,\"definitions\":{',\n23 │ ┃                 definitions,\n24 │ ┃                 '},\"evidence\":\"panel\",\"question\":\"',\n   ‡ ┃\n30 │ ┃                 \"}}\"\n31 │ ┃             )\n   │ ┗━━━━━━━━━━━━━┛\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:89:17\n   │\n89 │         return (false, 0);\n   │                 ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:44:31\n   │\n44 │                 if (c < 0x20) revert ForbiddenCharacter();\n   │                               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:56:22\n   │\n56 │                 else revert InvalidUTF8();\n   │                      ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:57:36\n   │\n57 │                 if (src + n > end) revert InvalidUTF8();\n   │                                    ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:59:43\n   │\n59 │                 if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                           ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:61:64\n   │\n61 │                     if (c == 0xc2 && (d == 0xab || d == 0xbb)) revert ForbiddenCharacter();\n   │                                                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:66:23\n   │\n66 │                     ) revert InvalidUTF8();\n   │                       ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:68:47\n   │\n68 │                     if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:71:51\n   │\n71 │                         if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                                   ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:45:25\n   │\n45 │             liquidity = uint128(uint256(entered));\n   │                         ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:45:33\n   │\n45 │             liquidity = uint128(uint256(entered));\n   │                                 ━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:59:46\n   │\n59 │         return PriceMath.movement(sqrtPrice, uint160(end));\n   │                                              ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/libraries/Json.sol:92:16\n   │\n92 │         while (i < s.length) {\n   │                ━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:72:29\n   │\n72 │             int16 wordPos = int16(compressed >> 8);\n   │                             ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:73:34\n   │\n73 │             uint8 bitPos = uint8(uint256(int256(compressed)) & 0xff);\n   │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:99:18\n   │\n99 │             else revert InvalidUTF8();\n   │                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:100:35\n    │\n100 │             if (i + n > s.length) revert InvalidUTF8();\n    │                                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:103:43\n    │\n103 │                 if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n    │                                           ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:110:19\n    │\n110 │                 ) revert InvalidUTF8();\n    │                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/libraries/Json.sol:127:21\n    │\n127 │                 out[k++] = \"\\\\\";\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[missing-events-access-control]: `_executing` is changed without an event but is used for access control\n    ╭▸ src/CabalGate.sol:421:9\n    │\n421 │         _executing = false;\n    │         ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:225:9\n    │\n225 │         emit Configured(configVersion, cfg);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/CabalGate.sol:210:64\n    │\n210 │     function configure(Config calldata cfg) external onlyOwner nonReentrant {\n    │                                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/CabalHook.sol:113:22\n    │\n113 │     function setGate(address candidate) external onlyOwner {\n    │                      ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:219:65\n    │\n219 │                 || cfg.maxSellAmount == 0 || cfg.maxBuyAmount > uint128(type(int128).max)\n    │                                                                 ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:220:40\n    │\n220 │                 || cfg.maxSellAmount > uint128(type(int128).max) || cfg.maxImpactBps == 0 || cfg.maxImpactBps > 5000\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `activeRequest` is updated\n    ╭▸ src/CabalGate.sol:275:14\n    │\n275 │           id = IIntake(cfg.intake)\n    │ ┏━━━━━━━━━━━━━━┛\n276 │ ┃             .request(cfg.action, body, IIntake.Callback(address(this), this.onOracleResult.selector), cfg.imd, price);\n    │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:294:9\n    │\n294 │         emit RequestSubmitted(id, msg.sender, buy, amount, question, body);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalGate.sol:278:13\n    │\n278 │         if (payment.balanceOf(address(this)) != beforePayment) revert UnsupportedToken();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:284:24\n    │\n284 │             createdAt: uint64(block.timestamp),\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:285:23\n    │\n285 │             deadline: uint64(block.timestamp + REQUEST_TIMEOUT),\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:288:21\n    │\n288 │             amount: uint128(amount),\n    │                     ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/CabalHook.sol:126:31\n    │\n126 │     function beforeInitialize(address sender, PoolKey calldata key, uint160) external onlyManager returns (bytes4) {\n    │                               ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:305:35\n    │\n305 │         if (block.chainid != 1 || block.timestamp >= r.deadline) revert Expired();\n    │                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:311:74\n    │\n311 │                 || a.agreed > a.panelSize || a.issuedAt < r.createdAt || a.issuedAt > block.timestamp + CLOCK_TOLERANCE\n    │                                                                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:312:20\n    │\n312 │                 || a.expiresAt <= block.timestamp || a.expiresAt <= a.issuedAt\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:327:38\n    │\n327 │             r.approvedUntil = uint64(until < a.expiresAt ? until : a.expiresAt);\n    │                                      ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:332:9\n    │\n332 │         emit OracleResult(requestId, a.requestId, approved, r.approvedUntil);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:327:31\n    │\n327 │             r.approvedUntil = uint64(until < a.expiresAt ? until : a.expiresAt);\n    │                               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:349:33\n    │\n349 │             if (!staleConfig && block.timestamp < r.deadline) revert InvalidRequest();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:351:33\n    │\n351 │             if (!staleConfig && block.timestamp < r.approvedUntil) revert InvalidRequest();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:163:19\n    │\n163 │         feeBase = uint256(amount < 0 ? -amount : amount);\n    │                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:176:16\n    │\n176 │         return (volume / 400) * 2;\n    │                ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:383:13\n    │\n383 │         if (block.timestamp >= r.approvedUntil) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:413:9\n    │\n413 │         emit RequestExecuted(id, r.amount, output, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:405:44\n    │\n405 │             if (h.units == 0) h.firstBuy = uint64(block.timestamp);\n    │                                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:235:13\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:249:13\n    │\n249 │             poolManager.take(currency, address(this), uint128(delta));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:252:13\n    │\n252 │             poolManager.sync(currency);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:254:17\n    │\n254 │             if (poolManager.settle() != owed) revert UnsupportedToken();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:183:15\n    │\n183 │         fee = half * 2;\n    │               ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/CabalHook.sol:179:45\n    │\n179 │     function finishSwap() external onlyGate nonReentrant returns (uint256 fee) {\n    │                                             ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalHook.sol:195:9\n    │\n195 │         emit FeePaid(volume, half, half);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalHook.sol:189:17\n    │\n189 │             if (imd.balanceOf(address(this)) != beforeBalance + fee) revert UnsupportedToken();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:202:9\n    │\n202 │         poolManager.unlock(abi.encode(lower, upper));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:202:9\n    │\n202 │         poolManager.unlock(abi.encode(lower, upper));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:445:26\n    │\n445 │         uint256 output = uint256(outputDelta);\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalGate.sol:477:13\n    │\n477 │         if (token.balanceOf(address(this)) != beforeBalance + amount) revert UnsupportedToken();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/CabalGate.sol:497:13\n    │\n497 │             IDENTITY_NFT.staticcall{gas: 30000}(abi.encodeWithSignature(\"balanceOf(address)\", user));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalHook.sol:237:9\n    │\n237 │ ┏         emit ProtocolLiquidityAdded(\n238 │ ┃             lower, upper, uint128(liquidity), Currency.unwrap(token0 ? _key.currency0 : _key.currency1), amount\n239 │ ┃         );\n    │ ┗━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:209:33\n    │\n209 │         (BalanceDelta delta,) = poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, 0, 0), \"\");\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:221:22\n    │\n221 │         int24 grid = tick / 60 * 60;\n    │                      ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:233:25\n    │\n233 │         if (liquidity > uint256(uint128(type(int128).max))) revert InvalidRange();\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:233:33\n    │\n233 │         if (liquidity > uint256(uint128(type(int128).max))) revert InvalidRange();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:235:13\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:235:83\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │                                                                                   ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:238:27\n    │\n238 │             lower, upper, uint128(liquidity), Currency.unwrap(token0 ? _key.currency0 : _key.currency1), amount\n    │                           ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:249:55\n    │\n249 │             poolManager.take(currency, address(this), uint128(delta));\n    │                                                       ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:251:28\n    │\n251 │             uint256 owed = uint256(-int256(delta));\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\n","passed":true},{"durationMs":8401,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/OracleLiveVector.t.sol:OracleLiveVectorTest\n[PASS] test_livePayloadDecodesAndSignatureRecoversToBriefSigner() (gas: 50913)\n[PASS] test_liveQuestionHashIsCanonicalKeccak() (gas: 189084)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 626.29µs (746.04µs CPU time)\n\nRan 1 test for test/Trading.t.sol:ReverseTokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5190176)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.37ms (3.72ms CPU time)\n\nRan 2 tests for test/SubmissionGas.t.sol:SubmissionGasTest\n[PASS] test_longestReasonStaysUnderBudget() (gas: 1239827)\n[PASS] test_shortBuyAndSellStayUnderBudget() (gas: 1090419)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 68.46ms (1.47ms CPU time)\n\nRan 1 test for test/OracleSigner.t.sol:OracleSignerTest\n[PASS] test_registrySignatureIsNotAnEOASignatureForTheConfiguredSigner() (gas: 4973110)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 70.34ms (2.05ms CPU time)\n\nRan 1 test for test/Oracle.t.sol:OracleGasTest\n[PASS] test_callbackFitsBelow200kColdTransaction() (gas: 2041545)\nLogs:\n  callback gas including external call: 78063\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 71.28ms (2.97ms CPU time)\n\nRan 1 test for test/Trading.t.sol:TokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5187043)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 83.98ms (2.69ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64769)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 78629)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9516946)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8020785)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 80854255)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 87.41ms (53.90ms CPU time)\n\nRan 5 tests for test/HookBinding.t.sol:HookBindingTest\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5608092)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 592405)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 13503744)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 4759785)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 14839190)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 96.87ms (22.09ms CPU time)\n\nRan 22 tests for test/Oracle.t.sol:OracleTest\n[PASS] testFuzz_attestationFieldsAreBound(uint8) (runs: 256, μ: 4469660, ~: 4466866)\nLogs:\n  Bound result 11\n\n[PASS] test_280UnicodeCharactersAccepted281Rejected() (gas: 7520888)\n[PASS] test_approvalNeverOutlivesAttestation() (gas: 4514522)\n[PASS] test_attestationCannotBeReusedForAnotherRequest() (gas: 7796718)\n[PASS] test_badSignerDomainAndTampering() (gas: 4795409)\n[PASS] test_bodyIsCanonicalJsonWithConsumerAndStoredEscapedQuestion() (gas: 14348105)\n[PASS] test_configuredPanelParametersFlowIntoBodyAndChecks() (gas: 4951241)\n[PASS] test_controlCharactersAndGuillemetsRejected() (gas: 3853513)\n[PASS] test_intakeFailureUnderpaymentDuplicateIdAndReentry() (gas: 7769060)\n[PASS] test_liveFormatDeliveryWithDistinctOracleIdApproves() (gas: 4536271)\n[PASS] test_malformedUTF8Rejected() (gas: 218846)\n[PASS] test_oldPendingUsesSnapshotIntakeSignerAndDomain() (gas: 5784231)\n[PASS] test_onlyIntakeOnlyPendingReplayAndUnknownIds() (gas: 4629131)\n[PASS] test_oracleClockMayRunSlightlyAheadAndValidityMayBeLong() (gas: 4514418)\n[PASS] test_ownerConfigSnapshotsInvalidatesOldExecutionAndCanClear() (gas: 6115673)\n[PASS] test_questionHashMustMatchStoredQuestionAndWindow() (gas: 6918252)\n[PASS] test_quotesInsideReasonCannotCloseTheDelimiter() (gas: 4365557)\n[PASS] test_sellQuestionIncludesHoldingsPriceBasisTimeNftAndReason() (gas: 11299808)\n[PASS] test_submitPaysExactlyQuotedPriceAndRevokesAllowance() (gas: 3463083)\n[PASS] test_timeoutClearsNoLateCallbackNoTradeFundsEscrowed() (gas: 6624575)\n[PASS] test_trueApprovesForFiveMinutesAndFalseRejects() (gas: 7761569)\n[PASS] test_wrongChainAndSizeAndConcurrentRequestRejected() (gas: 3542586)\nSuite result: ok. 22 passed; 0 failed; 0 skipped; finished in 580.64ms (520.91ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:ReverseOrderLaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64769)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 79085)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9551491)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8021013)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 193196633)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 774.72ms (109.53ms CPU time)\n\nRan 20 tests for test/Trading.t.sol:TradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9596968, ~: 9601115)\nLogs:\n  Bound result 999000000000000003851\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 9969589)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 232918)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23703655)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5169603)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10552150)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5198943)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4621615)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5512376)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13091068)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 57084043)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5319672)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5883916)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117029)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10159129)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5315069)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100513)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 327209)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11437751)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 905.81ms (937.34ms CPU time)\n\nRan 16 tests for test/AdversarialOracle.t.sol:AdversarialOracleTest\n[PASS] testFuzz_malformedSignatureLengthCannotConsumeRequest(uint8) (runs: 1000, μ: 4493313, ~: 4493167)\nLogs:\n  Bound result 4\n\n[PASS] test_attestationIssuedBeforeSubmissionIsRefused() (gas: 4573494)\n[PASS] test_callbackHasNoDependencyOnTokenNftIntakeOrPoolReads() (gas: 4617456)\n[PASS] test_configurationRejectsEveryInvalidBoundaryWithoutAdvancingVersion() (gas: 1831229)\n[PASS] test_everySignedFieldRejectsPostSignatureMutation() (gas: 22113390)\n[PASS] test_explicitVerifierReplacesGateInDomainAndBody() (gas: 4976513)\n[PASS] test_failedOraclePaymentLeavesNoRequestAndCanRetry() (gas: 3855762)\n[PASS] test_identicalReasonFromAnotherUserDoesNotShareAttestation() (gas: 6624945)\n[PASS] test_mainnetDefaultsMatchAssignment() (gas: 24713)\n[PASS] test_rejectedAndClearedIdsCannotReplayOrAlterNewActiveRequest() (gas: 10939614)\n[PASS] test_rejectionReleasesSlotAndResubmissionNeedsFreshDecision() (gas: 7663092)\n[PASS] test_signatureRejectsHighSAndInvalidV() (gas: 4668262)\n[PASS] test_signatureRejectsWrongNameVersionAndDomainChain() (gas: 4845196)\n[PASS] test_timeoutAndApprovalBoundaryAtLastPermittedSecond() (gas: 5204695)\n[PASS] test_zeroOraclePriceAndZeroReturnedIdAreHandledAtomically() (gas: 3777096)\n[PASS] test_zeroVerifierMeansThisGateAndIsStoredResolved() (gas: 3732901)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 918.67ms (864.63ms CPU time)\n\nRan 20 tests for test/Trading.t.sol:ReverseOrderTradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9631743, ~: 9635687)\nLogs:\n  Bound result 999000000000000005878\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 10003938)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 233390)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23835344)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5203570)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10632542)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5233193)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4621550)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5551392)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13124762)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 15956781)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5327365)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5959729)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117294)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10253921)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5349475)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100508)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 327161)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11541711)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.01s (1.10s CPU time)\n\nRan 3 tests for test/OracleLatency.t.sol:OracleLatencyTest\n[PASS] test_deliveryAtOldExpiryRetainsFullApproval() (gas: 5314564)\n[PASS] test_deliveryJustBeforeOldExpiryRetainsFullApproval() (gas: 5314652)\n[PASS] test_deliveryJustBeforeRequestDeadlineRetainsFullApproval() (gas: 5314718)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 1.08s (7.46ms CPU time)\n\nRan 5 tests for test/CabalCoin.t.sol:CabalCoinTest\n[PASS] testFuzz_transferConservesSupply(uint256) (runs: 256, μ: 83060, ~: 83387)\nLogs:\n  Bound result 829915077014370586957893081\n\n[PASS] test_allowanceAndInsufficientBalances() (gas: 197125)\n[PASS] test_launchSupplyMetadataAndPlainTransfer() (gas: 119450)\n[PASS] test_noAdministrativeMint() (gas: 36108)\n[PASS] test_runtimeNoEscapeHatches() (gas: 625143)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 1.32s (6.82ms CPU time)\n\nRan 7 tests for test/QuestionProperties.t.sol:QuestionPropertiesTest\n[PASS] testFuzz_jsonRoundTripsUntrustedPrintableAscii(bytes,bool,uint128) (runs: 1000, μ: 5039617, ~: 5542631)\n[PASS] test_emptyReasonIsQuotedAndLeftForPanelJudgment() (gas: 9346155)\n[PASS] test_everyAsciiControlCharacterRefusedQuoteBackslashAndDelSurvive() (gas: 15890019)\n[PASS] test_guillemetsRefusedAnywhereOtherLatin1Accepted() (gas: 9970465)\n[PASS] test_invalidUtf8NeverEntersOracleJson() (gas: 243913)\n[PASS] test_questionNeverExceedsTwoThousandCharactersAtMaximalValues() (gas: 2373470)\n[PASS] test_unicodeScalarLimitsIncludeAllUtf8Widths() (gas: 67874956)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.32s (1.51s CPU time)\n\nRan 5 tests for test/HookBinding.t.sol:ReverseOrderHookBindingTest\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5642382)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 593641)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 24678373)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 15426281)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 26017928)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 1.32s (65.13ms CPU time)\n\nRan 6 tests for test/GateLaunch.t.sol:GateLaunchTest\n[PASS] test_constructorRejectsZeroOwner() (gas: 730734)\n[PASS] test_constructorRequiresHookInitializedAndDependencyCode() (gas: 14947638)\n[PASS] test_existingHookOwnerBindsGateOnceAndRefusesSecondGate() (gas: 15817491)\n[PASS] test_explicitOwnerControlsConfigurationInsteadOfFactory() (gas: 8122802)\n[PASS] test_factoryDeploysOnlyGateWithAllThirteenManifestWords() (gas: 27487936)\n[PASS] test_flatConstructorRetainsEveryConfigurationValidation() (gas: 63231961)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 1.32s (49.41ms CPU time)\n\nRan 9 tests for test/EconomicProperties.t.sol:EconomicPropertiesTest\n[PASS] testFuzz_feeCannotExceedHalfPercentAndRoundingIsBounded(uint256) (runs: 1000, μ: 17505, ~: 17678)\n[PASS] testFuzz_priceMovementSymmetricMonotoneAndBounded(uint160,uint160,uint160) (runs: 1000, μ: 51370, ~: 51343)\nLogs:\n  Bound result 820091117953006440880257\n  Bound result 1461501637330902918203684012625165066745918441391\n  Bound result 1461501637330902918203684520681715273306582008123\n\n[PASS] testFuzz_repeatedBuySellCannotCreateImd(uint256,uint8) (runs: 1000, μ: 16305663, ~: 17403300)\nLogs:\n  Bound result 999999999999999999997\n  Bound result 3\n\n[PASS] test_feeAndPriceKnownBoundaries() (gas: 58513)\n[PASS] test_insufficientExecutionAllowancePreservesApprovalAndCanRetry() (gas: 5457591)\n[PASS] test_realTradesAtFeeRoundingEdges() (gas: 23272282)\n[PASS] test_sellApprovalSurvivesBalanceDropAndExecutesOnceRestored() (gas: 9860655)\n[PASS] test_sellLargerThanTrackedHoldingsClearsTheRecordWithoutUnderflow() (gas: 9647937)\n[PASS] test_sellSlippageFailureRollsBackFeePositionAndCostBasis() (gas: 10229670)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.32s (1.29s CPU time)\n\nRan 7 tests for test/ReasonEscaping.t.sol:ReasonEscapingTest\n[PASS] testFuzz_arbitraryBytesAreJudgedLikeAnIndependentDecoder(bytes) (runs: 1000, μ: 16509, ~: 12712)\n[PASS] testFuzz_oneCorruptedByteIsJudgedLikeAnIndependentDecoder(bytes32,uint16,uint16,uint8) (runs: 1000, μ: 290039, ~: 178501)\nLogs:\n  Bound result 80\n  Bound result 66\n\n[PASS] testFuzz_wellFormedTextOfEveryWidthIsCountedEscapedAndQuotedExactly(bytes32,uint16) (runs: 1000, μ: 2079472, ~: 1844372)\nLogs:\n  Bound result 3\n\n[PASS] test_byteBoundBeforeContentAndScalarBoundAfterIt() (gas: 1479560)\n[PASS] test_escapedQuestionHashesLikeTheParsedBody() (gas: 2977892)\n[PASS] test_quotesAndBackslashesAreEscapedBetweenMultibyteText() (gas: 32360)\n[PASS] test_truncatedLeadByteAtTheEndIsRefusedWhateverFollowsInMemory() (gas: 28243)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.32s (3.72s CPU time)\n\nRan 2 tests for test/invariant/CabalInvariant.t.sol:CabalInvariantTest\n[PASS] invariant_conservationSettlementLifecycleAndLockedPol() (runs: 256, calls: 16384, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| CabalHandler | advance            | 1523  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1456  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1478  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1466  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1472  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1494  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1480  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1533  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1474  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1550  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1458  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 13\n  Bound result 11313284251875313389\n  Bound result 526\n  Bound result 8000000000000000000\n  Bound result 8\n  Bound result 0\n  Bound result 96\n  Bound result 5462\n  Bound result 2287\n  Bound result 25\n  Bound result 2776895893\n  Bound result 0\n  Bound result 7000000000000000000\n  Bound result 19\n  Bound result 1\n  Bound result 13\n  Bound result 200000\n  Bound result 1\n  Bound result 256\n  Bound result 999999999999999999649\n  Bound result 303\n  Bound result 1022\n  Bound result 999999999999999999801\n  Bound result 488536512958415197857\n  Bound result 3\n  Bound result 789\n  Bound result 1\n  Bound result 12\n  Bound result 1\n  Bound result 1\n  Bound result 5\n  Bound result 301500000000000000000\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16299900)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 10000000000000000000\n  Bound result 10000000000000000000\n  Bound result 3601\n  Bound result 10000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 8.29s (8.28s CPU time)\n\nRan 2 tests for test/invariant/CabalInvariant.t.sol:CabalReverseInvariantTest\n[PASS] invariant_conservationSettlementLifecycleAndLockedPol() (runs: 256, calls: 16384, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| CabalHandler | advance            | 1523  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1456  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1478  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1466  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1472  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1494  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1480  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1533  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1474  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1550  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1458  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 13\n  Bound result 11313284251875313389\n  Bound result 179\n  Bound result 8\n  Bound result 0\n  Bound result 96\n  Bound result 9719\n  Bound result 2660\n  Bound result 25\n  Bound result 32769\n  Bound result 0\n  Bound result 7000000000000000000\n  Bound result 19\n  Bound result 1\n  Bound result 9\n  Bound result 200000\n  Bound result 1\n  Bound result 256\n  Bound result 999999999999999999649\n  Bound result 2755\n  Bound result 1022\n  Bound result 999999999999999999801\n  Bound result 488536512958415197857\n  Bound result 3\n  Bound result 789\n  Bound result 4\n  Bound result 12\n  Bound result 1\n  Bound result 1\n  Bound result 5\n  Bound result 301500000000000000000\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16342007)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 10000000000000000000\n  Bound result 10000000000000000000\n  Bound result 3601\n  Bound result 10000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 8.30s (8.30s CPU time)\n\nRan 22 test suites in 8.30s (30.28s CPU time): 147 tests passed, 0 failed, 0 skipped (147 total tests)\n","passed":true},{"durationMs":59,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CabalCoin.approve(address,uint256)\",\"CabalCoin.transfer(address,uint256)\",\"CabalCoin.transferFrom(address,address,uint256)\",\"CabalGate.acceptOwnership()\",\"CabalGate.clearRequest(bytes32)\",\"CabalGate.configure((address,address,address,address,bytes32,uint128,uint128,uint16,uint16,uint16,uint16,uint8,uint8))\",\"CabalGate.executeBuyRequest(bytes32)\",\"CabalGate.executeBuyRequest(bytes32,uint256)\",\"CabalGate.executeSellRequest(bytes32)\",\"CabalGate.executeSellRequest(bytes32,uint256)\",\"CabalGate.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"CabalGate.renounceOwnership()\",\"CabalGate.setSlippageLimit(bytes32,uint256)\",\"CabalGate.submitBuyRequest(uint256,string)\",\"CabalGate.submitSellRequest(uint256,string)\",\"CabalGate.transferOwnership(address)\",\"CabalGate.unlockCallback(bytes)\",\"CabalHook.acceptOwnership()\",\"CabalHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CabalHook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"CabalHook.compound(int24,int24)\",\"CabalHook.finishSwap()\",\"CabalHook.renounceOwnership()\",\"CabalHook.setGate(address)\",\"CabalHook.setIMD(address)\",\"CabalHook.transferOwnership(address)\",\"CabalHook.unlockCallback(bytes)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":95,\"README.md\":59,\"docs/DEPLOYMENT.md\":70,\"docs/ORACLE.md\":97,\"docs/SECURITY.md\":29,\"docs/dependencies.json\":26,\"foundry.toml\":20,\"launch.json\":29,\"script/HookSaltMiner.sol\":23,\"src/CabalCoin.sol\":11,\"src/CabalGate.sol\":501,\"src/CabalHook.sol\":257,\"src/HookFlags.sol\":29,\"src/ImpactEstimator.sol\":91,\"src/QuestionBuilder.sol\":124,\"src/interfaces/IIntake.sol\":41,\"src/libraries/CanonicalRequest.sol\":34,\"src/libraries/DataStore.sol\":27,\"src/libraries/Json.sol\":145,\"src/libraries/MainnetDefaults.sol\":11,\"src/libraries/OracleSignature.sol\":42,\"src/libraries/PriceMath.sol\":14,\"test/AdversarialOracle.t.sol\":334,\"test/CabalCoin.t.sol\":62,\"test/CabalFixture.sol\":353,\"test/EconomicProperties.t.sol\":188,\"test/GateLaunch.t.sol\":234,\"test/HookBinding.t.sol\":294,\"test/Launch.t.sol\":137,\"test/Oracle.t.sol\":439,\"test/OracleLatency.t.sol\":44,\"test/OracleLiveVector.t.sol\":81,\"test/OracleSigner.t.sol\":41,\"test/QuestionProperties.t.sol\":264,\"test/README.md\":21,\"test/ReasonEscaping.t.sol\":373,\"test/SubmissionGas.t.sol\":67,\"test/Trading.t.sol\":493,\"test/invariant/CabalHandler.sol\":355,\"test/invariant/CabalInvariant.t.sol\":75,\"test/mocks/MockERC20.sol\":13,\"test/mocks/MockIntake.sol\":93},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":8150,"exitCode":0,"name":"slither","output":"[high/medium] reentrancy-balance at src/CabalGate.sol:236: Reentrancy in CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#236-295):\n[high/medium] reentrancy-balance at src/CabalGate.sol:236: Reentrancy in CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#236-295):\n[medium/medium] divide-before-multiply at src/CabalHook.sol:218: CabalHook._addSingleSided(bool,uint256) (src/CabalHook.sol#218-240) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/CabalHook.sol:179: CabalHook.finishSwap() (src/CabalHook.sol#179-196) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/CabalHook.sol:175: CabalHook.feeFor(uint256) (src/CabalHook.sol#175-177) performs a multiplication on the result of a division:\n[medium/high] incorrect-equality at src/CabalGate.sol:236: CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#236-295) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalGate.sol:485: CabalGate._reduceHolding(CabalGate.Holding,uint256) (src/CabalGate.sol#485-493) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalHook.sol:218: CabalHook._addSingleSided(bool,uint256) (src/CabalHook.sol#218-240) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalGate.sol:485: CabalGate._reduceHolding(CabalGate.Holding,uint256) (src/CabalGate.sol#485-493) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalHook.sol:218: CabalHook._addSingleSided(bool,uint256) (src/CabalHook.sol#218-240) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/CabalGate.sol:236: Reentrancy in CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#236-295):\n[medium/medium] reentrancy-no-eth at src/CabalGate.sol:378: Reentrancy in CabalGate._execute(bytes32,bool,uint256) (src/CabalGate.sol#378-414):\n[medium/medium] unused-return at src/CabalGate.sol:416: CabalGate.unlockCallback(bytes) (src/CabalGate.sol#416-454) ignores return value by (afterPrice,None,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalGate.sol#442)\n[medium/medium] unused-return at src/CabalHook.sol:218: CabalHook._addSingleSided(bool,uint256) (src/CabalHook.sol#218-240) ignores return value by (None,tick,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalHook.sol#220)\n[medium/medium] unused-return at src/CabalGate.sol:378: CabalGate._execute(bytes32,bool,uint256) (src/CabalGate.sol#378-414) ignores return value by (current,None,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalGate.sol#390)\n[medium/medium] unused-return at src/CabalHook.sol:206: CabalHook.unlockCallback(bytes) (src/CabalHook.sol#206-214) ignores return value by (delta,None) = poolManager.modifyLiquidity(_key,ModifyLiquidityParams(lower,upper,0,0),) (src/CabalHook.sol#209)\n[medium/medium] unused-return at src/ImpactEstimator.sol:33: ImpactEstimator.estimate(bool,uint256) (src/ImpactEstimator.sol#33-60) ignores return value by (sqrtPrice,tick,None,None) = poolManager.getSlot0(poolId) (src/ImpactEstimator.sol#35)\n[medium/medium] unused-return at src/CabalHook.sol:199: CabalHook.compound(int24,int24) (src/CabalHook.sol#199-204) ignores return value by poolManager.unlock(abi.encode(lower,upper)) (src/CabalHook.sol#202)\n[medium/medium] unused-return at src/CabalGate.sol:416: CabalGate.unlockCallback(bytes) (src/CabalGate.sol#416-454) ignores return value by (beforePrice,None,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalGate.sol#431)\n[medium/medium] unused-return at src/ImpactEstimator.sol:33: ImpactEstimator.estimate(bool,uint256) (src/ImpactEstimator.sol#33-60) ignores return value by (None,liquidityNet) = poolManager.getTickLiquidity(poolId,next) (src/ImpactEstimator.sol#41)\n[medium/medium] unused-return at src/CabalHook.sol:218: CabalHook._addSingleSided(bool,uint256) (src/CabalHook.sol#218-240) ignores return value by (delta,None) = poolManager.modifyLiquidity(_key,ModifyLiquidityParams(lower,upper,int256(liquidity),0),) (src/CabalHook.sol#234-235)\n[medium/medium] unused-return at src/CabalGate.sol:236: CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#236-295) ignores return value by (sqrtPrice,None,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalGate.sol#245)\n[low/medium] missing-zero-check at src/CabalHook.sol:126: CabalHook.beforeInitialize(address,PoolKey,uint160).sender (src/CabalHook.sol#126) lacks a zero-check on :\n[low/medium] reentrancy-benign at src/CabalGate.sol:378: Reentrancy in CabalGate._execute(bytes32,bool,uint256) (src/CabalGate.sol#378-414):\n[low/medium] reentrancy-benign at src/CabalHook.sol:199: Reentrancy in CabalHook.compound(int24,int24) (src/CabalHook.sol#199-204):\n[low/medium] reentrancy-benign at src/CabalGate.sol:236: Reentrancy in CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#236-295):\n[low/medium] reentrancy-events at src/CabalHook.sol:206: Reentrancy in CabalHook.unlockCallback(bytes) (src/CabalHook.sol#206-214):\n[low/medium] reentrancy-events at src/CabalHook.sol:218: Reentrancy in CabalHook._addSingleSided(bool,uint256) (src/CabalHook.sol#218-240):\n[low/medium] reentrancy-events at src/CabalHook.sol:206: Reentrancy in CabalHook.unlockCallback(bytes) (src/CabalHook.sol#206-214):\n[low/medium] timestamp at src/CabalGate.sol:301: CabalGate.onOracleResult(bytes32,Attestation,bytes) (src/CabalGate.sol#301-333) uses timestamp for comparisons\n[low/medium] timestamp at src/CabalGate.sol:378: CabalGate._execute(bytes32,bool,uint256) (src/CabalGate.sol#378-414) uses timestamp for comparisons\n[low/medium] timestamp at src/CabalGate.sol:344: CabalGate.clearRequest(bytes32) (src/CabalGate.sol#344-358) uses timestamp for comparisons\n[low/medium] timestamp at src/CabalGate.sol:236: CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#236-295) uses timestamp for comparisons","passed":true},{"durationMs":709,"exitCode":0,"name":"aderyn","output":"[high] abi-encode-packed-hash-collision at src/QuestionBuilder.sol:98: `abi.encodePacked()` Hash Collision (3 places)\n[high] reentrancy-state-change at src/CabalGate.sol:142: Reentrancy: State change after external call (9 places)\n[low] centralization-risk at src/CabalGate.sol:28: Centralization Risk (5 places)\n[low] division-before-multiplication at src/CabalHook.sol:221: Incorrect Order of Division and Multiplication\n[low] internal-function-used-once at src/HookFlags.sol:22: Internal Function Used Only Once\n[low] large-numeric-literal at src/CabalCoin.sol:9: Large Numeric Literal (12 places)\n[low] literal-instead-of-constant at src/CabalGate.sol:220: Literal Instead of Constant (78 places)\n[low] modifier-used-only-once at src/CabalHook.sol:91: Modifier Invoked Only Once\n[low] non-reentrant-not-first at src/CabalGate.sol:210: `nonReentrant` is Not the First Modifier (2 places)\n[low] require-revert-in-loop at src/ImpactEstimator.sol:70: Loop Contains `require`/`revert` (2 places)\n[low] state-change-without-event at src/CabalGate.sol:416: State Change Without Event (3 places)\n[low] state-no-address-check at src/CabalHook.sol:135: Address State Variable Set Without Checks\n[low] unchecked-return at src/CabalHook.sol:202: Unchecked Return\n[low] uninitialized-local-variable at src/ImpactEstimator.sol:70: Uninitialized Local Variable (2 places)\n[low] unused-public-function at src/CabalHook.sol:175: Public Function Not Used Internally","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"37629c235286cf66b0590c9eda67cbaf682e43a30a9bc9b87295a04049570da8","verifiedTreeHash":"db0b7fd29c290c681f9b63ed169e8068ce276f55","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":116638,"exitCode":0,"name":"build","output":"Compiling 120 files with Solc 0.8.26\nSolc 0.8.26 finished in 116.41s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n   --> test/GateFactoryEdges.t.sol:210:5:\n    |\n210 |     function test_protocolVectorPinsAllFifteenFieldsTypeStringAndDomain() public {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nwarning[unsafe-typecast]: typecast can truncate values\n  ╭▸ src/libraries/MainnetDefaults.sol:9:54\n  │\n9 │     address internal constant IDENTITY_NFT = address(bytes20(hex\"0000ec93127baa929e58e97dd0095a2bfb38ec1d\"));\n  │                                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n  │\n  ├ note: consider disabling this lint if you're certain the cast is safe\n  │       \n  │       // casting to 'bytes20' is safe because [explain why]\n  │       // forge-lint: disable-next-line(unsafe-typecast)\n  │       \n  │       \n  ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:71:83\n   │\n71 │             if (compressed < minCompressed || compressed > maxCompressed) return (false, 0);\n   │                                                                                   ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/MainnetDefaults.sol:10:40\n   │\n10 │     bytes32 internal constant ACTION = bytes32(\"oracle.request@oracle-1\");\n   │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:78:29\n   │\n78 │                     return (true, (compressed - int24(uint24(bitPos - BitMath.mostSignificantBit(masked)))) * spacing);\n   │                             ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n   ╭▸ src/libraries/CanonicalRequest.sol:21:13\n   │\n21 │ ┏             abi.encodePacked(\n22 │ ┃                 '{\"answerType\":\"bool\",\"chainId\":1,\"definitions\":{',\n23 │ ┃                 definitions,\n24 │ ┃                 '},\"evidence\":\"panel\",\"question\":\"',\n   ‡ ┃\n30 │ ┃                 \"}}\"\n31 │ ┃             )\n   │ ┗━━━━━━━━━━━━━┛\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:84:29\n   │\n84 │                     return (true, (compressed + int24(uint24(BitMath.leastSignificantBit(masked) - bitPos))) * spacing);\n   │                             ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:89:17\n   │\n89 │         return (false, 0);\n   │                 ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:44:31\n   │\n44 │                 if (c < 0x20) revert ForbiddenCharacter();\n   │                               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:56:22\n   │\n56 │                 else revert InvalidUTF8();\n   │                      ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:57:36\n   │\n57 │                 if (src + n > end) revert InvalidUTF8();\n   │                                    ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:59:43\n   │\n59 │                 if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                           ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:61:64\n   │\n61 │                     if (c == 0xc2 && (d == 0xab || d == 0xbb)) revert ForbiddenCharacter();\n   │                                                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:66:23\n   │\n66 │                     ) revert InvalidUTF8();\n   │                       ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:68:47\n   │\n68 │                     if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:71:51\n   │\n71 │                         if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                                   ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:45:25\n   │\n45 │             liquidity = uint128(uint256(entered));\n   │                         ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:45:33\n   │\n45 │             liquidity = uint128(uint256(entered));\n   │                                 ━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:59:46\n   │\n59 │         return PriceMath.movement(sqrtPrice, uint160(end));\n   │                                              ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/libraries/Json.sol:92:16\n   │\n92 │         while (i < s.length) {\n   │                ━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:72:29\n   │\n72 │             int16 wordPos = int16(compressed >> 8);\n   │                             ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:73:34\n   │\n73 │             uint8 bitPos = uint8(uint256(int256(compressed)) & 0xff);\n   │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:99:18\n   │\n99 │             else revert InvalidUTF8();\n   │                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:100:35\n    │\n100 │             if (i + n > s.length) revert InvalidUTF8();\n    │                                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:103:43\n    │\n103 │                 if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n    │                                           ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:110:19\n    │\n110 │                 ) revert InvalidUTF8();\n    │                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[missing-events-access-control]: `_executing` is changed without an event but is used for access control\n    ╭▸ src/CabalGate.sol:422:9\n    │\n422 │         _executing = false;\n    │         ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/libraries/Json.sol:127:21\n    │\n127 │                 out[k++] = \"\\\\\";\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/QuestionBuilder.sol:98:16\n    │\n 98 │           body = abi.encodePacked(\n    │ ┏━━━━━━━━━━━━━━━━┛\n 99 │ ┃             '{\"answerType\":\"bool\",\"chainId\":1,\"consumer\":{\"chainId\":1,\"verifyingContract\":\"',\n100 │ ┃             c.verifier.toHexString(),\n101 │ ┃             '\"},\"definitions\":{',\n    ‡ ┃\n112 │ ┃             \"}}\"\n113 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:225:9\n    │\n225 │         emit Configured(configVersion, cfg);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/CabalGate.sol:210:64\n    │\n210 │     function configure(Config calldata cfg) external onlyOwner nonReentrant {\n    │                                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:219:65\n    │\n219 │                 || cfg.maxSellAmount == 0 || cfg.maxBuyAmount > uint128(type(int128).max)\n    │                                                                 ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:220:40\n    │\n220 │                 || cfg.maxSellAmount > uint128(type(int128).max) || cfg.maxImpactBps == 0 || cfg.maxImpactBps > 5000\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `activeRequest` is updated\n    ╭▸ src/CabalGate.sol:276:14\n    │\n276 │           id = IIntake(cfg.intake)\n    │ ┏━━━━━━━━━━━━━━┛\n277 │ ┃             .request(cfg.action, body, IIntake.Callback(address(this), this.onOracleResult.selector), cfg.imd, price);\n    │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:295:9\n    │\n295 │         emit RequestSubmitted(id, msg.sender, buy, amount, question, body);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalGate.sol:279:13\n    │\n279 │         if (payment.balanceOf(address(this)) != beforePayment) revert UnsupportedToken();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:285:24\n    │\n285 │             createdAt: uint64(block.timestamp),\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:286:23\n    │\n286 │             deadline: uint64(block.timestamp + REQUEST_TIMEOUT),\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:289:21\n    │\n289 │             amount: uint128(amount),\n    │                     ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/CabalHook.sol:113:22\n    │\n113 │     function setGate(address candidate) external onlyOwner {\n    │                      ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:306:35\n    │\n306 │         if (block.chainid != 1 || block.timestamp >= r.deadline) revert Expired();\n    │                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:312:74\n    │\n312 │                 || a.agreed > a.panelSize || a.issuedAt < r.createdAt || a.issuedAt > block.timestamp + CLOCK_TOLERANCE\n    │                                                                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:313:20\n    │\n313 │                 || a.expiresAt <= block.timestamp || a.expiresAt <= a.issuedAt\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:328:38\n    │\n328 │             r.approvedUntil = uint64(until < a.expiresAt ? until : a.expiresAt);\n    │                                      ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:333:9\n    │\n333 │         emit OracleResult(requestId, a.requestId, approved, r.approvedUntil);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:328:31\n    │\n328 │             r.approvedUntil = uint64(until < a.expiresAt ? until : a.expiresAt);\n    │                               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:350:33\n    │\n350 │             if (!staleConfig && block.timestamp < r.deadline) revert InvalidRequest();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:352:33\n    │\n352 │             if (!staleConfig && block.timestamp < r.approvedUntil) revert InvalidRequest();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:384:13\n    │\n384 │         if (block.timestamp >= r.approvedUntil) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:414:9\n    │\n414 │         emit RequestExecuted(id, r.amount, output, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:406:44\n    │\n406 │             if (h.units == 0) h.firstBuy = uint64(block.timestamp);\n    │                                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/CabalHook.sol:126:31\n    │\n126 │     function beforeInitialize(address sender, PoolKey calldata key, uint160) external onlyManager returns (bytes4) {\n    │                               ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:446:26\n    │\n446 │         uint256 output = uint256(outputDelta);\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:163:19\n    │\n163 │         feeBase = uint256(amount < 0 ? -amount : amount);\n    │                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalGate.sol:478:13\n    │\n478 │         if (token.balanceOf(address(this)) != beforeBalance + amount) revert UnsupportedToken();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:176:16\n    │\n176 │         return (volume / 400) * 2;\n    │                ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/CabalGate.sol:498:13\n    │\n498 │             IDENTITY_NFT.staticcall{gas: 30000}(abi.encodeWithSignature(\"balanceOf(address)\", user));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:235:13\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:249:13\n    │\n249 │             poolManager.take(currency, address(this), uint128(delta));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:252:13\n    │\n252 │             poolManager.sync(currency);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:254:17\n    │\n254 │             if (poolManager.settle() != owed) revert UnsupportedToken();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:183:15\n    │\n183 │         fee = half * 2;\n    │               ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/CabalHook.sol:179:45\n    │\n179 │     function finishSwap() external onlyGate nonReentrant returns (uint256 fee) {\n    │                                             ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalHook.sol:195:9\n    │\n195 │         emit FeePaid(volume, half, half);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalHook.sol:189:17\n    │\n189 │             if (imd.balanceOf(address(this)) != beforeBalance + fee) revert UnsupportedToken();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:202:9\n    │\n202 │         poolManager.unlock(abi.encode(lower, upper));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:202:9\n    │\n202 │         poolManager.unlock(abi.encode(lower, upper));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalHook.sol:237:9\n    │\n237 │ ┏         emit ProtocolLiquidityAdded(\n238 │ ┃             lower, upper, uint128(liquidity), Currency.unwrap(token0 ? _key.currency0 : _key.currency1), amount\n239 │ ┃         );\n    │ ┗━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:209:33\n    │\n209 │         (BalanceDelta delta,) = poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, 0, 0), \"\");\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:221:22\n    │\n221 │         int24 grid = tick / 60 * 60;\n    │                      ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:233:25\n    │\n233 │         if (liquidity > uint256(uint128(type(int128).max))) revert InvalidRange();\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:233:33\n    │\n233 │         if (liquidity > uint256(uint128(type(int128).max))) revert InvalidRange();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:235:13\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:235:83\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │                                                                                   ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:238:27\n    │\n238 │             lower, upper, uint128(liquidity), Currency.unwrap(token0 ? _key.currency0 : _key.currency1), amount\n    │                           ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:249:55\n    │\n249 │             poolManager.take(currency, address(this), uint128(delta));\n    │                                                       ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:251:28\n    │\n251 │             uint256 owed = uint256(-int256(delta));\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/invariant/GateOnlyRequests.t.sol:108:45\n    │\n108 │         if (r.version == expectedVersion && block.timestamp < expiry) return;\n    │                                             ━━━━━━━━━━━━━━━\n    ‡\n117 │         vm.warp(block.timestamp + bound(secondsSeed, 0, 3601));\n    │         ────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/invariant/GateOnlyRequests.t.sol:86:13\n    │\n 86 │         if (block.timestamp >= r.deadline) return;\n    │             ━━━━━━━━━━━━━━━\n    ‡\n117 │         vm.warp(block.timestamp + bound(secondsSeed, 0, 3601));\n    │         ────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/invariant/GateOnlyRequests.t.sol:247:29\n    │\n117 │         vm.warp(block.timestamp + bound(secondsSeed, 0, 3601));\n    │         ────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    ‡\n247 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/invariant/GateOnlyRequests.t.sol:248:30\n    │\n117 │         vm.warp(block.timestamp + bound(secondsSeed, 0, 3601));\n    │         ────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    ‡\n248 │         a.expiresAt = uint64(block.timestamp + 900);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/invariant/GateOnlyRequests.t.sol:93:57\n    │\n 93 │             assertEq(gate.getRequest(id).approvedUntil, block.timestamp + 300);\n    │                                                         ━━━━━━━━━━━━━━━\n    ‡\n117 │         vm.warp(block.timestamp + bound(secondsSeed, 0, 3601));\n    │         ────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/invariant/GateOnlyRequests.t.sol:117:17\n    │\n117 │         vm.warp(block.timestamp + bound(secondsSeed, 0, 3601));\n    │         ────────━━━━━━━━━━━━━━━─────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":8110,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/Trading.t.sol:ReverseTokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5193153)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.49ms (4.20ms CPU time)\n\nRan 2 tests for test/OracleLiveVector.t.sol:OracleLiveVectorTest\n[PASS] test_livePayloadDecodesAndSignatureRecoversToBriefSigner() (gas: 50913)\n[PASS] test_liveQuestionHashIsCanonicalKeccak() (gas: 189084)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 46.68ms (1.03ms CPU time)\n\nRan 1 test for test/Trading.t.sol:TokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5190020)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 69.63ms (2.31ms CPU time)\n\nRan 3 tests for test/OracleLatency.t.sol:OracleLatencyTest\n[PASS] test_deliveryAtOldExpiryRetainsFullApproval() (gas: 5317541)\n[PASS] test_deliveryJustBeforeOldExpiryRetainsFullApproval() (gas: 5317629)\n[PASS] test_deliveryJustBeforeRequestDeadlineRetainsFullApproval() (gas: 5317695)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 71.43ms (7.27ms CPU time)\n\nRan 1 test for test/OracleSigner.t.sol:OracleSignerTest\n[PASS] test_registrySignatureIsNotAnEOASignatureForTheConfiguredSigner() (gas: 4976087)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 73.10ms (2.08ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:ReverseOrderLaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64769)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 79085)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9557444)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8094174)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 193196633)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 77.01ms (73.02ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64769)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 78629)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9522899)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8093946)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 80854255)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 81.06ms (44.80ms CPU time)\n\nRan 9 tests for test/GateFactoryEdges.t.sol:GateFactoryEdgesTest\n[PASS] testFuzz_flatWordsPreserveValidConfiguration(uint128,uint128,uint16,uint16,uint16,uint16,uint8) (runs: 256, μ: 7978629, ~: 7978618)\nLogs:\n  Bound result 68854365435881040935\n  Bound result 2410\n  Bound result 6\n  Bound result 624\n  Bound result 11\n  Bound result 3\n  Bound result 14\n\n[PASS] test_constructorRejectsDirtyHighBitsInEveryNarrowWord() (gas: 11831201)\n[PASS] test_constructorRejectsTruncatedStaticArguments() (gas: 13080153)\n[PASS] test_factoryOwnerHandoverRequiresAcceptanceAndPreservesBinding() (gas: 8470396)\n[PASS] test_failedConfigurationRollsBackHelpersAndSameDeploymentCanRetry() (gas: 10943482)\n[PASS] test_helpersAreCreatedByEachGateAndExistingDependenciesStayIntact() (gas: 15969833)\n[PASS] test_hookRejectsMissingCodeWrongHookWrongCabalAndDuplicateBinding() (gas: 8087711)\n[PASS] test_pinnedValidNumericEdges() (gas: 15907691)\n[PASS] test_protocolVectorPinsAllFifteenFieldsTypeStringAndDomain() (gas: 15427)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 93.66ms (101.25ms CPU time)\n\nRan 2 tests for test/SubmissionGas.t.sol:SubmissionGasTest\n[PASS] test_longestReasonStaysUnderBudget() (gas: 1242804)\n[PASS] test_shortBuyAndSellStayUnderBudget() (gas: 1096371)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 111.49ms (2.44ms CPU time)\n\nRan 1 test for test/Oracle.t.sol:OracleGasTest\n[PASS] test_callbackFitsBelow200kColdTransaction() (gas: 2041545)\nLogs:\n  callback gas including external call: 78063\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 117.89ms (5.17ms CPU time)\n\nRan 7 tests for test/HookBinding.t.sol:ReverseOrderHookBindingTest\n[PASS] test_buySubmissionRequiresHookHandoffBeforeCharging() (gas: 39410941)\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5645309)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 593624)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 24760048)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 15426303)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 26099613)\n[PASS] test_sellSubmissionRequiresHookHandoffBeforeCharging() (gas: 39962943)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 121.18ms (123.05ms CPU time)\n\nRan 7 tests for test/HookBinding.t.sol:HookBindingTest\n[PASS] test_buySubmissionRequiresHookHandoffBeforeCharging() (gas: 27596129)\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5610984)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 592316)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 13580588)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 4759768)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 14916045)\n[PASS] test_sellSubmissionRequiresHookHandoffBeforeCharging() (gas: 28133235)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 129.79ms (43.72ms CPU time)\n\nRan 22 tests for test/Oracle.t.sol:OracleTest\n[PASS] testFuzz_attestationFieldsAreBound(uint8) (runs: 256, μ: 4472221, ~: 4469843)\nLogs:\n  Bound result 2\n\n[PASS] test_280UnicodeCharactersAccepted281Rejected() (gas: 7526841)\n[PASS] test_approvalNeverOutlivesAttestation() (gas: 4517499)\n[PASS] test_attestationCannotBeReusedForAnotherRequest() (gas: 7802672)\n[PASS] test_badSignerDomainAndTampering() (gas: 4798386)\n[PASS] test_bodyIsCanonicalJsonWithConsumerAndStoredEscapedQuestion() (gas: 14351081)\n[PASS] test_configuredPanelParametersFlowIntoBodyAndChecks() (gas: 4954218)\n[PASS] test_controlCharactersAndGuillemetsRejected() (gas: 3871369)\n[PASS] test_intakeFailureUnderpaymentDuplicateIdAndReentry() (gas: 7780965)\n[PASS] test_liveFormatDeliveryWithDistinctOracleIdApproves() (gas: 4539248)\n[PASS] test_malformedUTF8Rejected() (gas: 224798)\n[PASS] test_oldPendingUsesSnapshotIntakeSignerAndDomain() (gas: 5787208)\n[PASS] test_onlyIntakeOnlyPendingReplayAndUnknownIds() (gas: 4632108)\n[PASS] test_oracleClockMayRunSlightlyAheadAndValidityMayBeLong() (gas: 4517395)\n[PASS] test_ownerConfigSnapshotsInvalidatesOldExecutionAndCanClear() (gas: 6118650)\n[PASS] test_questionHashMustMatchStoredQuestionAndWindow() (gas: 6921229)\n[PASS] test_quotesInsideReasonCannotCloseTheDelimiter() (gas: 4368533)\n[PASS] test_sellQuestionIncludesHoldingsPriceBasisTimeNftAndReason() (gas: 11305761)\n[PASS] test_submitPaysExactlyQuotedPriceAndRevokesAllowance() (gas: 3466060)\n[PASS] test_timeoutClearsNoLateCallbackNoTradeFundsEscrowed() (gas: 6630529)\n[PASS] test_trueApprovesForFiveMinutesAndFalseRejects() (gas: 7767522)\n[PASS] test_wrongChainAndSizeAndConcurrentRequestRejected() (gas: 3567483)\nSuite result: ok. 22 passed; 0 failed; 0 skipped; finished in 1.10s (514.92ms CPU time)\n\nRan 5 tests for test/CabalCoin.t.sol:CabalCoinTest\n[PASS] testFuzz_transferConservesSupply(uint256) (runs: 256, μ: 83138, ~: 83375)\nLogs:\n  Bound result 14588763398566037642958\n\n[PASS] test_allowanceAndInsufficientBalances() (gas: 197125)\n[PASS] test_launchSupplyMetadataAndPlainTransfer() (gas: 119450)\n[PASS] test_noAdministrativeMint() (gas: 36108)\n[PASS] test_runtimeNoEscapeHatches() (gas: 625143)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 1.15s (10.16ms CPU time)\n\nRan 20 tests for test/Trading.t.sol:ReverseOrderTradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9637307, ~: 9641640)\nLogs:\n  Bound result 592579549530099699034\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 10009891)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 233390)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23853202)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5206547)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10638495)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5236170)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4624527)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5554369)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13133692)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 15956781)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5330342)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5962706)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117294)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10262850)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5352452)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100508)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 330137)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11550642)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.20s (1.27s CPU time)\n\nRan 6 tests for test/GateLaunch.t.sol:GateLaunchTest\n[PASS] test_constructorRejectsZeroOwner() (gas: 736951)\n[PASS] test_constructorRequiresHookInitializedAndDependencyCode() (gas: 15042159)\n[PASS] test_existingHookOwnerBindsGateOnceAndRefusesSecondGate() (gas: 15965768)\n[PASS] test_explicitOwnerControlsConfigurationInsteadOfFactory() (gas: 8196539)\n[PASS] test_factoryDeploysOnlyGateWithAllThirteenManifestWords() (gas: 27753926)\n[PASS] test_flatConstructorRetainsEveryConfigurationValidation() (gas: 63502251)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 1.23s (62.91ms CPU time)\n\nRan 7 tests for test/ReasonEscaping.t.sol:ReasonEscapingTest\n[PASS] testFuzz_arbitraryBytesAreJudgedLikeAnIndependentDecoder(bytes) (runs: 1000, μ: 15430, ~: 12700)\n[PASS] testFuzz_oneCorruptedByteIsJudgedLikeAnIndependentDecoder(bytes32,uint16,uint16,uint8) (runs: 1000, μ: 295945, ~: 198629)\nLogs:\n  Bound result 170\n  Bound result 301\n\n[PASS] testFuzz_wellFormedTextOfEveryWidthIsCountedEscapedAndQuotedExactly(bytes32,uint16) (runs: 1000, μ: 2037812, ~: 1802463)\nLogs:\n  Bound result 109\n\n[PASS] test_byteBoundBeforeContentAndScalarBoundAfterIt() (gas: 1479560)\n[PASS] test_escapedQuestionHashesLikeTheParsedBody() (gas: 2977892)\n[PASS] test_quotesAndBackslashesAreEscapedBetweenMultibyteText() (gas: 32360)\n[PASS] test_truncatedLeadByteAtTheEndIsRefusedWhateverFollowsInMemory() (gas: 28243)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.23s (3.62s CPU time)\n\nRan 7 tests for test/QuestionProperties.t.sol:QuestionPropertiesTest\n[PASS] testFuzz_jsonRoundTripsUntrustedPrintableAscii(bytes,bool,uint128) (runs: 1000, μ: 5063599, ~: 5557906)\n[PASS] test_emptyReasonIsQuotedAndLeftForPanelJudgment() (gas: 9346155)\n[PASS] test_everyAsciiControlCharacterRefusedQuoteBackslashAndDelSurvive() (gas: 15890019)\n[PASS] test_guillemetsRefusedAnywhereOtherLatin1Accepted() (gas: 9970465)\n[PASS] test_invalidUtf8NeverEntersOracleJson() (gas: 243913)\n[PASS] test_questionNeverExceedsTwoThousandCharactersAtMaximalValues() (gas: 2373470)\n[PASS] test_unicodeScalarLimitsIncludeAllUtf8Widths() (gas: 67874956)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.23s (1.44s CPU time)\n\nRan 16 tests for test/AdversarialOracle.t.sol:AdversarialOracleTest\n[PASS] testFuzz_malformedSignatureLengthCannotConsumeRequest(uint8) (runs: 1000, μ: 4496295, ~: 4496144)\nLogs:\n  Bound result 23\n\n[PASS] test_attestationIssuedBeforeSubmissionIsRefused() (gas: 4576471)\n[PASS] test_callbackHasNoDependencyOnTokenNftIntakeOrPoolReads() (gas: 4620433)\n[PASS] test_configurationRejectsEveryInvalidBoundaryWithoutAdvancingVersion() (gas: 1831229)\n[PASS] test_everySignedFieldRejectsPostSignatureMutation() (gas: 22116367)\n[PASS] test_explicitVerifierReplacesGateInDomainAndBody() (gas: 4979490)\n[PASS] test_failedOraclePaymentLeavesNoRequestAndCanRetry() (gas: 3861715)\n[PASS] test_identicalReasonFromAnotherUserDoesNotShareAttestation() (gas: 6630899)\n[PASS] test_mainnetDefaultsMatchAssignment() (gas: 24713)\n[PASS] test_rejectedAndClearedIdsCannotReplayOrAlterNewActiveRequest() (gas: 10948545)\n[PASS] test_rejectionReleasesSlotAndResubmissionNeedsFreshDecision() (gas: 7669046)\n[PASS] test_signatureRejectsHighSAndInvalidV() (gas: 4671239)\n[PASS] test_signatureRejectsWrongNameVersionAndDomainChain() (gas: 4848173)\n[PASS] test_timeoutAndApprovalBoundaryAtLastPermittedSecond() (gas: 5207672)\n[PASS] test_zeroOraclePriceAndZeroReturnedIdAreHandledAtomically() (gas: 3783049)\n[PASS] test_zeroVerifierMeansThisGateAndIsStoredResolved() (gas: 3735878)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 1.23s (1.19s CPU time)\n\nRan 20 tests for test/Trading.t.sol:TradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9602979, ~: 9607069)\nLogs:\n  Bound result 592579549530099699034\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 9975542)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 232918)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23721513)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5172580)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10558103)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5201920)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4624592)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5515353)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13099998)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 57084043)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5322649)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5886893)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117029)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10168058)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5318046)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100513)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 330185)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11446682)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.23s (1.23s CPU time)\n\nRan 9 tests for test/EconomicProperties.t.sol:EconomicPropertiesTest\n[PASS] testFuzz_feeCannotExceedHalfPercentAndRoundingIsBounded(uint256) (runs: 1000, μ: 17498, ~: 17678)\n[PASS] testFuzz_priceMovementSymmetricMonotoneAndBounded(uint160,uint160,uint160) (runs: 1000, μ: 51391, ~: 51343)\nLogs:\n  Bound result 251038531629376460206669354338728700125320\n  Bound result 166202438531429935574321954135143056157337853319\n  Bound result 1295299198799472992999073147229314212500275119162\n\n[PASS] testFuzz_repeatedBuySellCannotCreateImd(uint256,uint8) (runs: 1000, μ: 16254247, ~: 17415194)\nLogs:\n  Bound result 171937950822430606221\n  Bound result 2\n\n[PASS] test_feeAndPriceKnownBoundaries() (gas: 58513)\n[PASS] test_insufficientExecutionAllowancePreservesApprovalAndCanRetry() (gas: 5460568)\n[PASS] test_realTradesAtFeeRoundingEdges() (gas: 23290138)\n[PASS] test_sellApprovalSurvivesBalanceDropAndExecutesOnceRestored() (gas: 9866608)\n[PASS] test_sellLargerThanTrackedHoldingsClearsTheRecordWithoutUnderflow() (gas: 9653890)\n[PASS] test_sellSlippageFailureRollsBackFeePositionAndCostBasis() (gas: 10235623)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.23s (1.20s CPU time)\n\nRan 2 tests for test/invariant/GateOnlyRequests.t.sol:GateOnlyRequestsInvariantTest\n[PASS]\nGateOnlyRequestsInvariantTest invariants:\n[PASS] invariant_gatePreservesDonationsAndChargesOnlyTheRequester\n[PASS] invariant_requestStatesSnapshotsAndBindingRemainConsistent\n GateOnlyRequestsInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭------------------------+--------------------+-------+---------+----------╮\n| Contract               | Selector           | Calls | Reverts | Discards |\n+==========================================================================+\n| GateOnlyRequestHandler | advance            | 1723  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | clear              | 1632  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | cycle              | 1637  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | donate             | 1508  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | reconfigure        | 1652  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refuseCallback     | 1653  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refusePayment      | 1605  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refuseUnauthorized | 1631  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | request            | 1683  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | resolve            | 1660  | 0       | 0        |\n╰------------------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 3203\n  Bound result 3600\n  Bound result 9\n  Bound result 92240510829748332\n  Bound result 586518566121102895\n  Bound result 406036525702149503\n  Bound result 15955\n  Bound result 2675\n  Bound result 10246\n  Bound result 7594\n  Bound result 3117\n  Bound result 402\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 1\n  Bound result 216667089502803431\n  Bound result 5950899573280\n  Bound result 19\n  Bound result 17\n  Bound result 167\n  Bound result 6436\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 24\n  Bound result 6\n  Bound result 24\n  Bound result 123\n  Bound result 9\n  Bound result 23\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 187\n  Bound result 17\n  Bound result 4458\n  Bound result 426071013350187566\n  Bound result 20\n  Bound result 1\n  Bound result 312714317690749557\n  Bound result 2019\n  Bound result 24\n  Bound result 3\n\n[PASS] test_handlerExercisesPaymentsFailuresBothAnswersAndClearing() (gas: 18723540)\nLogs:\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 0\n  Bound result 1\n  Bound result 300\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 3600\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 24\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 6.89s (6.90s CPU time)\n\nRan 2 tests for test/invariant/CabalInvariant.t.sol:CabalInvariantTest\n[PASS] invariant_conservationSettlementLifecycleAndLockedPol() (runs: 256, calls: 16384, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| CabalHandler | advance            | 1441  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1450  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1545  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1434  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1568  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1444  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1502  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1468  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1496  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1533  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1503  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 803807044930534603\n  Bound result 3060\n  Bound result 16283\n  Bound result 1381\n  Bound result 378320602744392854\n  Bound result 0\n  Bound result 48879\n  Bound result 3359\n  Bound result 555263895861367721458\n  Bound result 999999999999000000\n  Bound result 900\n  Bound result 318\n  Bound result 1\n  Bound result 971\n  Bound result 500639960887892817159\n  Bound result 1000000\n  Bound result 548293032989699437601\n  Bound result 0\n  Bound result 71\n  Bound result 173183087271055207\n  Bound result 11\n  Bound result 18\n  Bound result 15706\n  Bound result 14\n  Bound result 14\n  Bound result 399000\n  Bound result 999999999999999999606\n  Bound result 12\n  Bound result 17934\n  Bound result 14\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16309807)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 10000000000000000000\n  Bound result 10000000000000000000\n  Bound result 3601\n  Bound result 10000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 7.94s (7.93s CPU time)\n\nRan 2 tests for test/invariant/CabalInvariant.t.sol:CabalReverseInvariantTest\n[PASS] invariant_conservationSettlementLifecycleAndLockedPol() (runs: 256, calls: 16384, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| CabalHandler | advance            | 1441  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1450  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1545  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1434  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1568  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1444  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1502  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1468  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1496  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1533  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1503  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 803807044930534603\n  Bound result 1554\n  Bound result 16667\n  Bound result 1381\n  Bound result 378320602744392854\n  Bound result 0\n  Bound result 48879\n  Bound result 1507\n  Bound result 555263895861367721458\n  Bound result 999999999999000000\n  Bound result 900\n  Bound result 445\n  Bound result 1\n  Bound result 971\n  Bound result 2416\n  Bound result 4294967295\n  Bound result 1000000\n  Bound result 7169\n  Bound result 447193698706982064077\n  Bound result 2410\n  Bound result 11\n  Bound result 224\n  Bound result 6563\n  Bound result 14\n  Bound result 14\n  Bound result 399000\n  Bound result 57057627015884126434\n  Bound result 999999999999999999606\n  Bound result 12\n  Bound result 19147\n  Bound result 14\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16351914)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 10000000000000000000\n  Bound result 10000000000000000000\n  Bound result 3601\n  Bound result 10000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 8.02s (8.02s CPU time)\n\nRan 24 test suites in 8.02s (34.68s CPU time): 162 tests passed, 0 failed, 0 skipped (162 total tests)\n","passed":true},{"durationMs":67,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CabalCoin.approve(address,uint256)\",\"CabalCoin.transfer(address,uint256)\",\"CabalCoin.transferFrom(address,address,uint256)\",\"CabalGate.acceptOwnership()\",\"CabalGate.clearRequest(bytes32)\",\"CabalGate.configure((address,address,address,address,bytes32,uint128,uint128,uint16,uint16,uint16,uint16,uint8,uint8))\",\"CabalGate.executeBuyRequest(bytes32)\",\"CabalGate.executeBuyRequest(bytes32,uint256)\",\"CabalGate.executeSellRequest(bytes32)\",\"CabalGate.executeSellRequest(bytes32,uint256)\",\"CabalGate.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"CabalGate.renounceOwnership()\",\"CabalGate.setSlippageLimit(bytes32,uint256)\",\"CabalGate.submitBuyRequest(uint256,string)\",\"CabalGate.submitSellRequest(uint256,string)\",\"CabalGate.transferOwnership(address)\",\"CabalGate.unlockCallback(bytes)\",\"CabalHook.acceptOwnership()\",\"CabalHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CabalHook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"CabalHook.compound(int24,int24)\",\"CabalHook.finishSwap()\",\"CabalHook.renounceOwnership()\",\"CabalHook.setGate(address)\",\"CabalHook.setIMD(address)\",\"CabalHook.transferOwnership(address)\",\"CabalHook.unlockCallback(bytes)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":128,\"README.md\":59,\"docs/DEPLOYMENT.md\":74,\"docs/ORACLE.md\":97,\"docs/SECURITY.md\":29,\"docs/dependencies.json\":26,\"foundry.toml\":20,\"launch.json\":29,\"script/HookSaltMiner.sol\":23,\"src/CabalCoin.sol\":11,\"src/CabalGate.sol\":502,\"src/CabalHook.sol\":257,\"src/HookFlags.sol\":29,\"src/ImpactEstimator.sol\":91,\"src/QuestionBuilder.sol\":124,\"src/interfaces/IIntake.sol\":41,\"src/libraries/CanonicalRequest.sol\":34,\"src/libraries/DataStore.sol\":27,\"src/libraries/Json.sol\":145,\"src/libraries/MainnetDefaults.sol\":11,\"src/libraries/OracleSignature.sol\":42,\"src/libraries/PriceMath.sol\":14,\"test/AdversarialOracle.t.sol\":334,\"test/CabalCoin.t.sol\":62,\"test/CabalFixture.sol\":353,\"test/EconomicProperties.t.sol\":188,\"test/GateFactoryEdges.t.sol\":248,\"test/GateLaunch.t.sol\":236,\"test/GateLaunchChecks.md\":52,\"test/HookBinding.t.sol\":359,\"test/Launch.t.sol\":137,\"test/Oracle.t.sol\":439,\"test/OracleLatency.t.sol\":44,\"test/OracleLiveVector.t.sol\":81,\"test/OracleSigner.t.sol\":41,\"test/QuestionProperties.t.sol\":264,\"test/README.md\":23,\"test/ReasonEscaping.t.sol\":373,\"test/SubmissionGas.t.sol\":67,\"test/Trading.t.sol\":493,\"test/invariant/CabalHandler.sol\":355,\"test/invariant/CabalInvariant.t.sol\":75,\"test/invariant/GateOnlyRequests.t.sol\":400,\"test/mocks/MockERC20.sol\":13,\"test/mocks/MockIntake.sol\":93},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"c8dfcd05af07598bedad181e07935bf4ac9f1c15ee966957ffb8ab48125bde59","verifiedTreeHash":"39da5f9a11a40d86c7ea2a055f942c3795cf0920","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":112052,"exitCode":0,"name":"build","output":"Compiling 118 files with Solc 0.8.26\nSolc 0.8.26 finished in 111.84s\nCompiler run successful!\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:71:83\n   │\n71 │             if (compressed < minCompressed || compressed > maxCompressed) return (false, 0);\n   │                                                                                   ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n  ╭▸ src/libraries/MainnetDefaults.sol:9:54\n  │\n9 │     address internal constant IDENTITY_NFT = address(bytes20(hex\"0000ec93127baa929e58e97dd0095a2bfb38ec1d\"));\n  │                                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n  │\n  ├ note: consider disabling this lint if you're certain the cast is safe\n  │       \n  │       // casting to 'bytes20' is safe because [explain why]\n  │       // forge-lint: disable-next-line(unsafe-typecast)\n  │       \n  │       \n  ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/MainnetDefaults.sol:10:40\n   │\n10 │     bytes32 internal constant ACTION = bytes32(\"oracle.request@oracle-1\");\n   │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:78:29\n   │\n78 │                     return (true, (compressed - int24(uint24(bitPos - BitMath.mostSignificantBit(masked)))) * spacing);\n   │                             ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:84:29\n   │\n84 │                     return (true, (compressed + int24(uint24(BitMath.leastSignificantBit(masked) - bitPos))) * spacing);\n   │                             ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:89:17\n   │\n89 │         return (false, 0);\n   │                 ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n   ╭▸ src/libraries/CanonicalRequest.sol:21:13\n   │\n21 │ ┏             abi.encodePacked(\n22 │ ┃                 '{\"answerType\":\"bool\",\"chainId\":1,\"definitions\":{',\n23 │ ┃                 definitions,\n24 │ ┃                 '},\"evidence\":\"panel\",\"question\":\"',\n   ‡ ┃\n30 │ ┃                 \"}}\"\n31 │ ┃             )\n   │ ┗━━━━━━━━━━━━━┛\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:44:31\n   │\n44 │                 if (c < 0x20) revert ForbiddenCharacter();\n   │                               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:56:22\n   │\n56 │                 else revert InvalidUTF8();\n   │                      ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:57:36\n   │\n57 │                 if (src + n > end) revert InvalidUTF8();\n   │                                    ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:59:43\n   │\n59 │                 if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                           ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:61:64\n   │\n61 │                     if (c == 0xc2 && (d == 0xab || d == 0xbb)) revert ForbiddenCharacter();\n   │                                                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:66:23\n   │\n66 │                     ) revert InvalidUTF8();\n   │                       ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:68:47\n   │\n68 │                     if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:71:51\n   │\n71 │                         if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                                   ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:45:25\n   │\n45 │             liquidity = uint128(uint256(entered));\n   │                         ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:45:33\n   │\n45 │             liquidity = uint128(uint256(entered));\n   │                                 ━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:59:46\n   │\n59 │         return PriceMath.movement(sqrtPrice, uint160(end));\n   │                                              ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/libraries/Json.sol:92:16\n   │\n92 │         while (i < s.length) {\n   │                ━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:72:29\n   │\n72 │             int16 wordPos = int16(compressed >> 8);\n   │                             ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:99:18\n   │\n99 │             else revert InvalidUTF8();\n   │                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:100:35\n    │\n100 │             if (i + n > s.length) revert InvalidUTF8();\n    │                                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:103:43\n    │\n103 │                 if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n    │                                           ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:110:19\n    │\n110 │                 ) revert InvalidUTF8();\n    │                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:73:34\n   │\n73 │             uint8 bitPos = uint8(uint256(int256(compressed)) & 0xff);\n   │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/libraries/Json.sol:127:21\n    │\n127 │                 out[k++] = \"\\\\\";\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[missing-events-access-control]: `_executing` is changed without an event but is used for access control\n    ╭▸ src/CabalGate.sol:422:9\n    │\n422 │         _executing = false;\n    │         ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:225:9\n    │\n225 │         emit Configured(configVersion, cfg);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/CabalGate.sol:210:64\n    │\n210 │     function configure(Config calldata cfg) external onlyOwner nonReentrant {\n    │                                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:219:65\n    │\n219 │                 || cfg.maxSellAmount == 0 || cfg.maxBuyAmount > uint128(type(int128).max)\n    │                                                                 ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:220:40\n    │\n220 │                 || cfg.maxSellAmount > uint128(type(int128).max) || cfg.maxImpactBps == 0 || cfg.maxImpactBps > 5000\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `activeRequest` is updated\n    ╭▸ src/CabalGate.sol:276:14\n    │\n276 │           id = IIntake(cfg.intake)\n    │ ┏━━━━━━━━━━━━━━┛\n277 │ ┃             .request(cfg.action, body, IIntake.Callback(address(this), this.onOracleResult.selector), cfg.imd, price);\n    │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:295:9\n    │\n295 │         emit RequestSubmitted(id, msg.sender, buy, amount, question, body);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/CabalHook.sol:113:22\n    │\n113 │     function setGate(address candidate) external onlyOwner {\n    │                      ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalGate.sol:279:13\n    │\n279 │         if (payment.balanceOf(address(this)) != beforePayment) revert UnsupportedToken();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:285:24\n    │\n285 │             createdAt: uint64(block.timestamp),\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:286:23\n    │\n286 │             deadline: uint64(block.timestamp + REQUEST_TIMEOUT),\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:289:21\n    │\n289 │             amount: uint128(amount),\n    │                     ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:306:35\n    │\n306 │         if (block.chainid != 1 || block.timestamp >= r.deadline) revert Expired();\n    │                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:312:74\n    │\n312 │                 || a.agreed > a.panelSize || a.issuedAt < r.createdAt || a.issuedAt > block.timestamp + CLOCK_TOLERANCE\n    │                                                                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:313:20\n    │\n313 │                 || a.expiresAt <= block.timestamp || a.expiresAt <= a.issuedAt\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:328:38\n    │\n328 │             r.approvedUntil = uint64(until < a.expiresAt ? until : a.expiresAt);\n    │                                      ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:333:9\n    │\n333 │         emit OracleResult(requestId, a.requestId, approved, r.approvedUntil);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:328:31\n    │\n328 │             r.approvedUntil = uint64(until < a.expiresAt ? until : a.expiresAt);\n    │                               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:350:33\n    │\n350 │             if (!staleConfig && block.timestamp < r.deadline) revert InvalidRequest();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:352:33\n    │\n352 │             if (!staleConfig && block.timestamp < r.approvedUntil) revert InvalidRequest();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:384:13\n    │\n384 │         if (block.timestamp >= r.approvedUntil) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:414:9\n    │\n414 │         emit RequestExecuted(id, r.amount, output, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:406:44\n    │\n406 │             if (h.units == 0) h.firstBuy = uint64(block.timestamp);\n    │                                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/CabalHook.sol:126:31\n    │\n126 │     function beforeInitialize(address sender, PoolKey calldata key, uint160) external onlyManager returns (bytes4) {\n    │                               ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:163:19\n    │\n163 │         feeBase = uint256(amount < 0 ? -amount : amount);\n    │                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:176:16\n    │\n176 │         return (volume / 400) * 2;\n    │                ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:446:26\n    │\n446 │         uint256 output = uint256(outputDelta);\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalGate.sol:478:13\n    │\n478 │         if (token.balanceOf(address(this)) != beforeBalance + amount) revert UnsupportedToken();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/CabalGate.sol:498:13\n    │\n498 │             IDENTITY_NFT.staticcall{gas: 30000}(abi.encodeWithSignature(\"balanceOf(address)\", user));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/QuestionBuilder.sol:98:16\n    │\n 98 │           body = abi.encodePacked(\n    │ ┏━━━━━━━━━━━━━━━━┛\n 99 │ ┃             '{\"answerType\":\"bool\",\"chainId\":1,\"consumer\":{\"chainId\":1,\"verifyingContract\":\"',\n100 │ ┃             c.verifier.toHexString(),\n101 │ ┃             '\"},\"definitions\":{',\n    ‡ ┃\n112 │ ┃             \"}}\"\n113 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:235:13\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:249:13\n    │\n249 │             poolManager.take(currency, address(this), uint128(delta));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:252:13\n    │\n252 │             poolManager.sync(currency);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:254:17\n    │\n254 │             if (poolManager.settle() != owed) revert UnsupportedToken();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:183:15\n    │\n183 │         fee = half * 2;\n    │               ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/CabalHook.sol:179:45\n    │\n179 │     function finishSwap() external onlyGate nonReentrant returns (uint256 fee) {\n    │                                             ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalHook.sol:195:9\n    │\n195 │         emit FeePaid(volume, half, half);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalHook.sol:189:17\n    │\n189 │             if (imd.balanceOf(address(this)) != beforeBalance + fee) revert UnsupportedToken();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:202:9\n    │\n202 │         poolManager.unlock(abi.encode(lower, upper));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:202:9\n    │\n202 │         poolManager.unlock(abi.encode(lower, upper));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalHook.sol:237:9\n    │\n237 │ ┏         emit ProtocolLiquidityAdded(\n238 │ ┃             lower, upper, uint128(liquidity), Currency.unwrap(token0 ? _key.currency0 : _key.currency1), amount\n239 │ ┃         );\n    │ ┗━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:209:33\n    │\n209 │         (BalanceDelta delta,) = poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, 0, 0), \"\");\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:221:22\n    │\n221 │         int24 grid = tick / 60 * 60;\n    │                      ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:233:25\n    │\n233 │         if (liquidity > uint256(uint128(type(int128).max))) revert InvalidRange();\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:233:33\n    │\n233 │         if (liquidity > uint256(uint128(type(int128).max))) revert InvalidRange();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:235:13\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:235:83\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │                                                                                   ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:238:27\n    │\n238 │             lower, upper, uint128(liquidity), Currency.unwrap(token0 ? _key.currency0 : _key.currency1), amount\n    │                           ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:249:55\n    │\n249 │             poolManager.take(currency, address(this), uint128(delta));\n    │                                                       ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:251:28\n    │\n251 │             uint256 owed = uint256(-int256(delta));\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\n","passed":true},{"durationMs":7504,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/Trading.t.sol:ReverseTokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5193153)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 13.58ms (3.23ms CPU time)\n\nRan 6 tests for test/GateLaunch.t.sol:GateLaunchTest\n[PASS] test_constructorRejectsZeroOwner() (gas: 736951)\n[PASS] test_constructorRequiresHookInitializedAndDependencyCode() (gas: 15042159)\n[PASS] test_existingHookOwnerBindsGateOnceAndRefusesSecondGate() (gas: 15965768)\n[PASS] test_explicitOwnerControlsConfigurationInsteadOfFactory() (gas: 8196539)\n[PASS] test_factoryDeploysOnlyGateWithAllThirteenManifestWords() (gas: 27753926)\n[PASS] test_flatConstructorRetainsEveryConfigurationValidation() (gas: 63502251)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 64.10ms (63.47ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64769)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 78629)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9522899)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8093946)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 80854255)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 69.74ms (39.79ms CPU time)\n\nRan 2 tests for test/SubmissionGas.t.sol:SubmissionGasTest\n[PASS] test_longestReasonStaysUnderBudget() (gas: 1242804)\n[PASS] test_shortBuyAndSellStayUnderBudget() (gas: 1096371)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 69.66ms (1.47ms CPU time)\n\nRan 1 test for test/Trading.t.sol:TokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5190020)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 71.75ms (2.53ms CPU time)\n\nRan 1 test for test/Oracle.t.sol:OracleGasTest\n[PASS] test_callbackFitsBelow200kColdTransaction() (gas: 2041545)\nLogs:\n  callback gas including external call: 78063\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 89.53ms (2.84ms CPU time)\n\nRan 2 tests for test/OracleLiveVector.t.sol:OracleLiveVectorTest\n[PASS] test_livePayloadDecodesAndSignatureRecoversToBriefSigner() (gas: 50913)\n[PASS] test_liveQuestionHashIsCanonicalKeccak() (gas: 189084)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 111.88ms (1.38ms CPU time)\n\nRan 3 tests for test/OracleLatency.t.sol:OracleLatencyTest\n[PASS] test_deliveryAtOldExpiryRetainsFullApproval() (gas: 5317541)\n[PASS] test_deliveryJustBeforeOldExpiryRetainsFullApproval() (gas: 5317629)\n[PASS] test_deliveryJustBeforeRequestDeadlineRetainsFullApproval() (gas: 5317695)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 112.90ms (11.43ms CPU time)\n\nRan 1 test for test/OracleSigner.t.sol:OracleSignerTest\n[PASS] test_registrySignatureIsNotAnEOASignatureForTheConfiguredSigner() (gas: 4976087)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 117.56ms (3.45ms CPU time)\n\nRan 22 tests for test/Oracle.t.sol:OracleTest\n[PASS] testFuzz_attestationFieldsAreBound(uint8) (runs: 256, μ: 4472585, ~: 4469623)\nLogs:\n  Bound result 16\n\n[PASS] test_280UnicodeCharactersAccepted281Rejected() (gas: 7526841)\n[PASS] test_approvalNeverOutlivesAttestation() (gas: 4517499)\n[PASS] test_attestationCannotBeReusedForAnotherRequest() (gas: 7802672)\n[PASS] test_badSignerDomainAndTampering() (gas: 4798386)\n[PASS] test_bodyIsCanonicalJsonWithConsumerAndStoredEscapedQuestion() (gas: 14351081)\n[PASS] test_configuredPanelParametersFlowIntoBodyAndChecks() (gas: 4954218)\n[PASS] test_controlCharactersAndGuillemetsRejected() (gas: 3871369)\n[PASS] test_intakeFailureUnderpaymentDuplicateIdAndReentry() (gas: 7780965)\n[PASS] test_liveFormatDeliveryWithDistinctOracleIdApproves() (gas: 4539248)\n[PASS] test_malformedUTF8Rejected() (gas: 224798)\n[PASS] test_oldPendingUsesSnapshotIntakeSignerAndDomain() (gas: 5787208)\n[PASS] test_onlyIntakeOnlyPendingReplayAndUnknownIds() (gas: 4632108)\n[PASS] test_oracleClockMayRunSlightlyAheadAndValidityMayBeLong() (gas: 4517395)\n[PASS] test_ownerConfigSnapshotsInvalidatesOldExecutionAndCanClear() (gas: 6118650)\n[PASS] test_questionHashMustMatchStoredQuestionAndWindow() (gas: 6921229)\n[PASS] test_quotesInsideReasonCannotCloseTheDelimiter() (gas: 4368533)\n[PASS] test_sellQuestionIncludesHoldingsPriceBasisTimeNftAndReason() (gas: 11305761)\n[PASS] test_submitPaysExactlyQuotedPriceAndRevokesAllowance() (gas: 3466060)\n[PASS] test_timeoutClearsNoLateCallbackNoTradeFundsEscrowed() (gas: 6630529)\n[PASS] test_trueApprovesForFiveMinutesAndFalseRejects() (gas: 7767522)\n[PASS] test_wrongChainAndSizeAndConcurrentRequestRejected() (gas: 3567483)\nSuite result: ok. 22 passed; 0 failed; 0 skipped; finished in 711.31ms (702.00ms CPU time)\n\nRan 20 tests for test/Trading.t.sol:TradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9603613, ~: 9607069)\nLogs:\n  Bound result 224140745797475812902\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 9975542)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 232918)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23721513)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5172580)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10558103)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5201920)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4624592)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5515353)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13099998)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 57084043)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5322649)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5886893)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117029)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10168058)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5318046)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100513)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 330185)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11446682)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.10s (1.11s CPU time)\n\nRan 7 tests for test/HookBinding.t.sol:ReverseOrderHookBindingTest\n[PASS] test_buySubmissionRequiresHookHandoffBeforeCharging() (gas: 39410941)\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5645309)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 593624)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 24760048)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 15426303)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 26099613)\n[PASS] test_sellSubmissionRequiresHookHandoffBeforeCharging() (gas: 39962943)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.11s (108.02ms CPU time)\n\nRan 7 tests for test/HookBinding.t.sol:HookBindingTest\n[PASS] test_buySubmissionRequiresHookHandoffBeforeCharging() (gas: 27596129)\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5610984)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 592316)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 13580588)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 4759768)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 14916045)\n[PASS] test_sellSubmissionRequiresHookHandoffBeforeCharging() (gas: 28133235)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.16s (61.99ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:ReverseOrderLaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64769)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 79085)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9557444)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8094174)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 193196633)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 1.17s (108.75ms CPU time)\n\nRan 20 tests for test/Trading.t.sol:ReverseOrderTradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9638168, ~: 9641641)\nLogs:\n  Bound result 999000000004242970872\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 10009891)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 233390)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23853202)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5206547)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10638495)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5236170)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4624527)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5554369)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13133692)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 15956781)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5330342)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5962706)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117294)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10262850)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5352452)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100508)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 330137)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11550642)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.17s (1.25s CPU time)\n\nRan 7 tests for test/ReasonEscaping.t.sol:ReasonEscapingTest\n[PASS] testFuzz_arbitraryBytesAreJudgedLikeAnIndependentDecoder(bytes) (runs: 1000, μ: 15034, ~: 12700)\n[PASS] testFuzz_oneCorruptedByteIsJudgedLikeAnIndependentDecoder(bytes32,uint16,uint16,uint8) (runs: 1000, μ: 285375, ~: 170814)\nLogs:\n  Bound result 61\n  Bound result 0\n\n[PASS] testFuzz_wellFormedTextOfEveryWidthIsCountedEscapedAndQuotedExactly(bytes32,uint16) (runs: 1000, μ: 2042110, ~: 1789624)\nLogs:\n  Bound result 0\n\n[PASS] test_byteBoundBeforeContentAndScalarBoundAfterIt() (gas: 1479560)\n[PASS] test_escapedQuestionHashesLikeTheParsedBody() (gas: 2977892)\n[PASS] test_quotesAndBackslashesAreEscapedBetweenMultibyteText() (gas: 32360)\n[PASS] test_truncatedLeadByteAtTheEndIsRefusedWhateverFollowsInMemory() (gas: 28243)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.17s (2.94s CPU time)\n\nRan 5 tests for test/CabalCoin.t.sol:CabalCoinTest\n[PASS] testFuzz_transferConservesSupply(uint256) (runs: 256, μ: 83013, ~: 83387)\nLogs:\n  Bound result 865115588728177937189823058\n\n[PASS] test_allowanceAndInsufficientBalances() (gas: 197125)\n[PASS] test_launchSupplyMetadataAndPlainTransfer() (gas: 119450)\n[PASS] test_noAdministrativeMint() (gas: 36108)\n[PASS] test_runtimeNoEscapeHatches() (gas: 625143)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 1.17s (829.88ms CPU time)\n\nRan 16 tests for test/AdversarialOracle.t.sol:AdversarialOracleTest\n[PASS] testFuzz_malformedSignatureLengthCannotConsumeRequest(uint8) (runs: 1000, μ: 4496299, ~: 4496144)\nLogs:\n  Bound result 2\n\n[PASS] test_attestationIssuedBeforeSubmissionIsRefused() (gas: 4576471)\n[PASS] test_callbackHasNoDependencyOnTokenNftIntakeOrPoolReads() (gas: 4620433)\n[PASS] test_configurationRejectsEveryInvalidBoundaryWithoutAdvancingVersion() (gas: 1831229)\n[PASS] test_everySignedFieldRejectsPostSignatureMutation() (gas: 22116367)\n[PASS] test_explicitVerifierReplacesGateInDomainAndBody() (gas: 4979490)\n[PASS] test_failedOraclePaymentLeavesNoRequestAndCanRetry() (gas: 3861715)\n[PASS] test_identicalReasonFromAnotherUserDoesNotShareAttestation() (gas: 6630899)\n[PASS] test_mainnetDefaultsMatchAssignment() (gas: 24713)\n[PASS] test_rejectedAndClearedIdsCannotReplayOrAlterNewActiveRequest() (gas: 10948545)\n[PASS] test_rejectionReleasesSlotAndResubmissionNeedsFreshDecision() (gas: 7669046)\n[PASS] test_signatureRejectsHighSAndInvalidV() (gas: 4671239)\n[PASS] test_signatureRejectsWrongNameVersionAndDomainChain() (gas: 4848173)\n[PASS] test_timeoutAndApprovalBoundaryAtLastPermittedSecond() (gas: 5207672)\n[PASS] test_zeroOraclePriceAndZeroReturnedIdAreHandledAtomically() (gas: 3783049)\n[PASS] test_zeroVerifierMeansThisGateAndIsStoredResolved() (gas: 3735878)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 1.23s (1.17s CPU time)\n\nRan 7 tests for test/QuestionProperties.t.sol:QuestionPropertiesTest\n[PASS] testFuzz_jsonRoundTripsUntrustedPrintableAscii(bytes,bool,uint128) (runs: 1000, μ: 5048233, ~: 5532371)\n[PASS] test_emptyReasonIsQuotedAndLeftForPanelJudgment() (gas: 9346155)\n[PASS] test_everyAsciiControlCharacterRefusedQuoteBackslashAndDelSurvive() (gas: 15890019)\n[PASS] test_guillemetsRefusedAnywhereOtherLatin1Accepted() (gas: 9970465)\n[PASS] test_invalidUtf8NeverEntersOracleJson() (gas: 243913)\n[PASS] test_questionNeverExceedsTwoThousandCharactersAtMaximalValues() (gas: 2373470)\n[PASS] test_unicodeScalarLimitsIncludeAllUtf8Widths() (gas: 67874956)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.24s (1.44s CPU time)\n\nRan 9 tests for test/EconomicProperties.t.sol:EconomicPropertiesTest\n[PASS] testFuzz_feeCannotExceedHalfPercentAndRoundingIsBounded(uint256) (runs: 1000, μ: 17479, ~: 17678)\n[PASS] testFuzz_priceMovementSymmetricMonotoneAndBounded(uint160,uint160,uint160) (runs: 1000, μ: 51383, ~: 51343)\nLogs:\n  Bound result 1461501637330902918203684832716283019655932542975\n  Bound result 1461501637330902918203684832716283019655932542975\n  Bound result 1461501637330902918203684832716283019655932542975\n\n[PASS] testFuzz_repeatedBuySellCannotCreateImd(uint256,uint8) (runs: 1000, μ: 16577975, ~: 17415218)\nLogs:\n  Bound result 999999999999999999997\n  Bound result 2\n\n[PASS] test_feeAndPriceKnownBoundaries() (gas: 58513)\n[PASS] test_insufficientExecutionAllowancePreservesApprovalAndCanRetry() (gas: 5460568)\n[PASS] test_realTradesAtFeeRoundingEdges() (gas: 23290138)\n[PASS] test_sellApprovalSurvivesBalanceDropAndExecutesOnceRestored() (gas: 9866608)\n[PASS] test_sellLargerThanTrackedHoldingsClearsTheRecordWithoutUnderflow() (gas: 9653890)\n[PASS] test_sellSlippageFailureRollsBackFeePositionAndCostBasis() (gas: 10235623)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.24s (1.21s CPU time)\n\nRan 2 tests for test/invariant/CabalInvariant.t.sol:CabalInvariantTest\n[PASS] invariant_conservationSettlementLifecycleAndLockedPol() (runs: 256, calls: 16384, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| CabalHandler | advance            | 1523  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1492  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1585  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1486  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1500  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1475  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1576  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1443  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1447  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1382  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1475  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 8192\n  Bound result 20475\n  Bound result 237\n  Bound result 10\n  Bound result 2960\n  Bound result 999999999999999999630\n  Bound result 39681005748391858412\n  Bound result 27\n  Bound result 4\n  Bound result 15\n  Bound result 10\n  Bound result 10403\n  Bound result 2318\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 0\n  Bound result 10747\n  Bound result 39184839630769614997\n  Bound result 1111054142802401198\n  Bound result 625377078278911623\n  Bound result 0\n  Bound result 9357\n  Bound result 276959498108531128\n  Bound result 2038\n  Bound result 24\n  Bound result 19\n  Bound result 18365\n  Bound result 2570\n  Bound result 2\n  Bound result 4\n  Bound result 8192\n  Bound result 4452449361974713242211\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16309807)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 10000000000000000000\n  Bound result 10000000000000000000\n  Bound result 3601\n  Bound result 10000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 7.38s (7.36s CPU time)\n\nRan 2 tests for test/invariant/CabalInvariant.t.sol:CabalReverseInvariantTest\n[PASS] invariant_conservationSettlementLifecycleAndLockedPol() (runs: 256, calls: 16384, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| CabalHandler | advance            | 1523  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1492  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1585  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1486  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1500  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1475  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1576  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1443  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1447  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1382  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1475  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 8192\n  Bound result 15929\n  Bound result 0\n  Bound result 4\n  Bound result 2050\n  Bound result 999999999999999999630\n  Bound result 27\n  Bound result 4\n  Bound result 999999999999999999921\n  Bound result 4\n  Bound result 13\n  Bound result 0\n  Bound result 3472\n  Bound result 0\n  Bound result 0\n  Bound result 29552\n  Bound result 24\n  Bound result 14379\n  Bound result 1111054142802401198\n  Bound result 20810\n  Bound result 0\n  Bound result 116122191446920149\n  Bound result 2203\n  Bound result 11\n  Bound result 22\n  Bound result 178543448052955647353\n  Bound result 2408\n  Bound result 2\n  Bound result 7\n  Bound result 8192\n  Bound result 3285126348393730082655\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16351914)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 10000000000000000000\n  Bound result 10000000000000000000\n  Bound result 3601\n  Bound result 10000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 7.41s (7.41s CPU time)\n\nRan 22 test suites in 7.41s (27.98s CPU time): 151 tests passed, 0 failed, 0 skipped (151 total tests)\n","passed":true},{"durationMs":73,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CabalCoin.approve(address,uint256)\",\"CabalCoin.transfer(address,uint256)\",\"CabalCoin.transferFrom(address,address,uint256)\",\"CabalGate.acceptOwnership()\",\"CabalGate.clearRequest(bytes32)\",\"CabalGate.configure((address,address,address,address,bytes32,uint128,uint128,uint16,uint16,uint16,uint16,uint8,uint8))\",\"CabalGate.executeBuyRequest(bytes32)\",\"CabalGate.executeBuyRequest(bytes32,uint256)\",\"CabalGate.executeSellRequest(bytes32)\",\"CabalGate.executeSellRequest(bytes32,uint256)\",\"CabalGate.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"CabalGate.renounceOwnership()\",\"CabalGate.setSlippageLimit(bytes32,uint256)\",\"CabalGate.submitBuyRequest(uint256,string)\",\"CabalGate.submitSellRequest(uint256,string)\",\"CabalGate.transferOwnership(address)\",\"CabalGate.unlockCallback(bytes)\",\"CabalHook.acceptOwnership()\",\"CabalHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CabalHook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"CabalHook.compound(int24,int24)\",\"CabalHook.finishSwap()\",\"CabalHook.renounceOwnership()\",\"CabalHook.setGate(address)\",\"CabalHook.setIMD(address)\",\"CabalHook.transferOwnership(address)\",\"CabalHook.unlockCallback(bytes)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":128,\"README.md\":59,\"docs/DEPLOYMENT.md\":74,\"docs/ORACLE.md\":97,\"docs/SECURITY.md\":29,\"docs/dependencies.json\":26,\"foundry.toml\":20,\"launch.json\":24,\"script/HookSaltMiner.sol\":23,\"src/CabalCoin.sol\":11,\"src/CabalGate.sol\":502,\"src/CabalHook.sol\":257,\"src/HookFlags.sol\":29,\"src/ImpactEstimator.sol\":91,\"src/QuestionBuilder.sol\":124,\"src/interfaces/IIntake.sol\":41,\"src/libraries/CanonicalRequest.sol\":34,\"src/libraries/DataStore.sol\":27,\"src/libraries/Json.sol\":145,\"src/libraries/MainnetDefaults.sol\":11,\"src/libraries/OracleSignature.sol\":42,\"src/libraries/PriceMath.sol\":14,\"test/AdversarialOracle.t.sol\":334,\"test/CabalCoin.t.sol\":62,\"test/CabalFixture.sol\":353,\"test/EconomicProperties.t.sol\":188,\"test/GateLaunch.t.sol\":234,\"test/HookBinding.t.sol\":359,\"test/Launch.t.sol\":137,\"test/Oracle.t.sol\":439,\"test/OracleLatency.t.sol\":44,\"test/OracleLiveVector.t.sol\":81,\"test/OracleSigner.t.sol\":41,\"test/QuestionProperties.t.sol\":264,\"test/README.md\":21,\"test/ReasonEscaping.t.sol\":373,\"test/SubmissionGas.t.sol\":67,\"test/Trading.t.sol\":493,\"test/invariant/CabalHandler.sol\":355,\"test/invariant/CabalInvariant.t.sol\":75,\"test/mocks/MockERC20.sol\":13,\"test/mocks/MockIntake.sol\":93},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"d567a4e235cca9fe844192330ecbeb38da17af7df69c22d0db93f062a717f324","verifiedTreeHash":"7085ccb3c1c501e3965fc43d117d4d0c66e76955","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":125332,"exitCode":0,"name":"build","output":"Compiling 118 files with Solc 0.8.26\nSolc 0.8.26 finished in 125.09s\nCompiler run successful!\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n   ╭▸ src/libraries/CanonicalRequest.sol:21:13\n   │\n21 │ ┏             abi.encodePacked(\n22 │ ┃                 '{\"answerType\":\"bool\",\"chainId\":1,\"definitions\":{',\n23 │ ┃                 definitions,\n24 │ ┃                 '},\"evidence\":\"panel\",\"question\":\"',\n   ‡ ┃\n30 │ ┃                 \"}}\"\n31 │ ┃             )\n   │ ┗━━━━━━━━━━━━━┛\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[unsafe-typecast]: typecast can truncate values\n  ╭▸ src/libraries/MainnetDefaults.sol:9:54\n  │\n9 │     address internal constant IDENTITY_NFT = address(bytes20(hex\"0000ec93127baa929e58e97dd0095a2bfb38ec1d\"));\n  │                                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n  │\n  ├ note: consider disabling this lint if you're certain the cast is safe\n  │       \n  │       // casting to 'bytes20' is safe because [explain why]\n  │       // forge-lint: disable-next-line(unsafe-typecast)\n  │       \n  │       \n  ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:44:31\n   │\n44 │                 if (c < 0x20) revert ForbiddenCharacter();\n   │                               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:56:22\n   │\n56 │                 else revert InvalidUTF8();\n   │                      ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/QuestionBuilder.sol:98:16\n    │\n 98 │           body = abi.encodePacked(\n    │ ┏━━━━━━━━━━━━━━━━┛\n 99 │ ┃             '{\"answerType\":\"bool\",\"chainId\":1,\"consumer\":{\"chainId\":1,\"verifyingContract\":\"',\n100 │ ┃             c.verifier.toHexString(),\n101 │ ┃             '\"},\"definitions\":{',\n    ‡ ┃\n112 │ ┃             \"}}\"\n113 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:57:36\n   │\n57 │                 if (src + n > end) revert InvalidUTF8();\n   │                                    ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:59:43\n   │\n59 │                 if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                           ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:61:64\n   │\n61 │                     if (c == 0xc2 && (d == 0xab || d == 0xbb)) revert ForbiddenCharacter();\n   │                                                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:66:23\n   │\n66 │                     ) revert InvalidUTF8();\n   │                       ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/MainnetDefaults.sol:10:40\n   │\n10 │     bytes32 internal constant ACTION = bytes32(\"oracle.request@oracle-1\");\n   │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:68:47\n   │\n68 │                     if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:71:51\n   │\n71 │                         if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                                   ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/libraries/Json.sol:92:16\n   │\n92 │         while (i < s.length) {\n   │                ━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:99:18\n   │\n99 │             else revert InvalidUTF8();\n   │                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:100:35\n    │\n100 │             if (i + n > s.length) revert InvalidUTF8();\n    │                                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:103:43\n    │\n103 │                 if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n    │                                           ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:110:19\n    │\n110 │                 ) revert InvalidUTF8();\n    │                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/libraries/Json.sol:127:21\n    │\n127 │                 out[k++] = \"\\\\\";\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[missing-events-access-control]: `_executing` is changed without an event but is used for access control\n    ╭▸ src/CabalGate.sol:422:9\n    │\n422 │         _executing = false;\n    │         ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:225:9\n    │\n225 │         emit Configured(configVersion, cfg);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/CabalGate.sol:210:64\n    │\n210 │     function configure(Config calldata cfg) external onlyOwner nonReentrant {\n    │                                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:219:65\n    │\n219 │                 || cfg.maxSellAmount == 0 || cfg.maxBuyAmount > uint128(type(int128).max)\n    │                                                                 ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:220:40\n    │\n220 │                 || cfg.maxSellAmount > uint128(type(int128).max) || cfg.maxImpactBps == 0 || cfg.maxImpactBps > 5000\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/CabalHook.sol:113:22\n    │\n113 │     function setGate(address candidate) external onlyOwner {\n    │                      ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-no-eth]: external call can be reentered before `activeRequest` is updated\n    ╭▸ src/CabalGate.sol:276:14\n    │\n276 │           id = IIntake(cfg.intake)\n    │ ┏━━━━━━━━━━━━━━┛\n277 │ ┃             .request(cfg.action, body, IIntake.Callback(address(this), this.onOracleResult.selector), cfg.imd, price);\n    │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:295:9\n    │\n295 │         emit RequestSubmitted(id, msg.sender, buy, amount, question, body);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalGate.sol:279:13\n    │\n279 │         if (payment.balanceOf(address(this)) != beforePayment) revert UnsupportedToken();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:285:24\n    │\n285 │             createdAt: uint64(block.timestamp),\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:286:23\n    │\n286 │             deadline: uint64(block.timestamp + REQUEST_TIMEOUT),\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:289:21\n    │\n289 │             amount: uint128(amount),\n    │                     ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:306:35\n    │\n306 │         if (block.chainid != 1 || block.timestamp >= r.deadline) revert Expired();\n    │                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:312:74\n    │\n312 │                 || a.agreed > a.panelSize || a.issuedAt < r.createdAt || a.issuedAt > block.timestamp + CLOCK_TOLERANCE\n    │                                                                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:313:20\n    │\n313 │                 || a.expiresAt <= block.timestamp || a.expiresAt <= a.issuedAt\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:328:38\n    │\n328 │             r.approvedUntil = uint64(until < a.expiresAt ? until : a.expiresAt);\n    │                                      ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/CabalHook.sol:126:31\n    │\n126 │     function beforeInitialize(address sender, PoolKey calldata key, uint160) external onlyManager returns (bytes4) {\n    │                               ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:333:9\n    │\n333 │         emit OracleResult(requestId, a.requestId, approved, r.approvedUntil);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:328:31\n    │\n328 │             r.approvedUntil = uint64(until < a.expiresAt ? until : a.expiresAt);\n    │                               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:350:33\n    │\n350 │             if (!staleConfig && block.timestamp < r.deadline) revert InvalidRequest();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:352:33\n    │\n352 │             if (!staleConfig && block.timestamp < r.approvedUntil) revert InvalidRequest();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:384:13\n    │\n384 │         if (block.timestamp >= r.approvedUntil) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:414:9\n    │\n414 │         emit RequestExecuted(id, r.amount, output, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:163:19\n    │\n163 │         feeBase = uint256(amount < 0 ? -amount : amount);\n    │                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:406:44\n    │\n406 │             if (h.units == 0) h.firstBuy = uint64(block.timestamp);\n    │                                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:176:16\n    │\n176 │         return (volume / 400) * 2;\n    │                ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:235:13\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:249:13\n    │\n249 │             poolManager.take(currency, address(this), uint128(delta));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:252:13\n    │\n252 │             poolManager.sync(currency);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:254:17\n    │\n254 │             if (poolManager.settle() != owed) revert UnsupportedToken();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:183:15\n    │\n183 │         fee = half * 2;\n    │               ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/CabalHook.sol:179:45\n    │\n179 │     function finishSwap() external onlyGate nonReentrant returns (uint256 fee) {\n    │                                             ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalHook.sol:195:9\n    │\n195 │         emit FeePaid(volume, half, half);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalHook.sol:189:17\n    │\n189 │             if (imd.balanceOf(address(this)) != beforeBalance + fee) revert UnsupportedToken();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:202:9\n    │\n202 │         poolManager.unlock(abi.encode(lower, upper));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:202:9\n    │\n202 │         poolManager.unlock(abi.encode(lower, upper));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:446:26\n    │\n446 │         uint256 output = uint256(outputDelta);\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalGate.sol:478:13\n    │\n478 │         if (token.balanceOf(address(this)) != beforeBalance + amount) revert UnsupportedToken();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/CabalGate.sol:498:13\n    │\n498 │             IDENTITY_NFT.staticcall{gas: 30000}(abi.encodeWithSignature(\"balanceOf(address)\", user));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalHook.sol:237:9\n    │\n237 │ ┏         emit ProtocolLiquidityAdded(\n238 │ ┃             lower, upper, uint128(liquidity), Currency.unwrap(token0 ? _key.currency0 : _key.currency1), amount\n239 │ ┃         );\n    │ ┗━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:209:33\n    │\n209 │         (BalanceDelta delta,) = poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, 0, 0), \"\");\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:71:83\n   │\n71 │             if (compressed < minCompressed || compressed > maxCompressed) return (false, 0);\n   │                                                                                   ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:78:29\n   │\n78 │                     return (true, (compressed - int24(uint24(bitPos - BitMath.mostSignificantBit(masked)))) * spacing);\n   │                             ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:84:29\n   │\n84 │                     return (true, (compressed + int24(uint24(BitMath.leastSignificantBit(masked) - bitPos))) * spacing);\n   │                             ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:89:17\n   │\n89 │         return (false, 0);\n   │                 ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:45:25\n   │\n45 │             liquidity = uint128(uint256(entered));\n   │                         ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:45:33\n   │\n45 │             liquidity = uint128(uint256(entered));\n   │                                 ━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:59:46\n   │\n59 │         return PriceMath.movement(sqrtPrice, uint160(end));\n   │                                              ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:72:29\n   │\n72 │             int16 wordPos = int16(compressed >> 8);\n   │                             ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:73:34\n   │\n73 │             uint8 bitPos = uint8(uint256(int256(compressed)) & 0xff);\n   │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:221:22\n    │\n221 │         int24 grid = tick / 60 * 60;\n    │                      ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:233:25\n    │\n233 │         if (liquidity > uint256(uint128(type(int128).max))) revert InvalidRange();\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:233:33\n    │\n233 │         if (liquidity > uint256(uint128(type(int128).max))) revert InvalidRange();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:235:13\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:235:83\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │                                                                                   ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:238:27\n    │\n238 │             lower, upper, uint128(liquidity), Currency.unwrap(token0 ? _key.currency0 : _key.currency1), amount\n    │                           ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:249:55\n    │\n249 │             poolManager.take(currency, address(this), uint128(delta));\n    │                                                       ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:251:28\n    │\n251 │             uint256 owed = uint256(-int256(delta));\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\n","passed":true},{"durationMs":8393,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/OracleLiveVector.t.sol:OracleLiveVectorTest\n[PASS] test_livePayloadDecodesAndSignatureRecoversToBriefSigner() (gas: 50913)\n[PASS] test_liveQuestionHashIsCanonicalKeccak() (gas: 189084)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 6.72ms (1.10ms CPU time)\n\nRan 1 test for test/Trading.t.sol:ReverseTokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5193153)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 7.99ms (3.44ms CPU time)\n\nRan 2 tests for test/SubmissionGas.t.sol:SubmissionGasTest\n[PASS] test_longestReasonStaysUnderBudget() (gas: 1242804)\n[PASS] test_shortBuyAndSellStayUnderBudget() (gas: 1096371)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 65.93ms (1.44ms CPU time)\n\nRan 1 test for test/OracleSigner.t.sol:OracleSignerTest\n[PASS] test_registrySignatureIsNotAnEOASignatureForTheConfiguredSigner() (gas: 4976087)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 66.96ms (2.12ms CPU time)\n\nRan 1 test for test/Oracle.t.sol:OracleGasTest\n[PASS] test_callbackFitsBelow200kColdTransaction() (gas: 2041545)\nLogs:\n  callback gas including external call: 78063\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 69.86ms (4.27ms CPU time)\n\nRan 1 test for test/Trading.t.sol:TokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5190020)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 69.99ms (2.59ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64769)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 78629)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9522899)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8093946)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 80854255)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 86.35ms (57.70ms CPU time)\n\nRan 7 tests for test/HookBinding.t.sol:HookBindingTest\n[PASS] test_buySubmissionRequiresHookHandoffBeforeCharging() (gas: 27596129)\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5610984)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 592316)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 13580588)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 4759768)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 14916045)\n[PASS] test_sellSubmissionRequiresHookHandoffBeforeCharging() (gas: 28133235)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 120.91ms (49.30ms CPU time)\n\nRan 6 tests for test/GateLaunch.t.sol:GateLaunchTest\n[PASS] test_constructorRejectsZeroOwner() (gas: 736951)\n[PASS] test_constructorRequiresHookInitializedAndDependencyCode() (gas: 15042159)\n[PASS] test_existingHookOwnerBindsGateOnceAndRefusesSecondGate() (gas: 15965768)\n[PASS] test_explicitOwnerControlsConfigurationInsteadOfFactory() (gas: 8196539)\n[PASS] test_factoryDeploysOnlyGateWithAllThirteenManifestWords() (gas: 27753926)\n[PASS] test_flatConstructorRetainsEveryConfigurationValidation() (gas: 63502251)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 573.79ms (47.98ms CPU time)\n\nRan 22 tests for test/Oracle.t.sol:OracleTest\n[PASS] testFuzz_attestationFieldsAreBound(uint8) (runs: 256, μ: 4471787, ~: 4469691)\nLogs:\n  Bound result 4\n\n[PASS] test_280UnicodeCharactersAccepted281Rejected() (gas: 7526841)\n[PASS] test_approvalNeverOutlivesAttestation() (gas: 4517499)\n[PASS] test_attestationCannotBeReusedForAnotherRequest() (gas: 7802672)\n[PASS] test_badSignerDomainAndTampering() (gas: 4798386)\n[PASS] test_bodyIsCanonicalJsonWithConsumerAndStoredEscapedQuestion() (gas: 14351081)\n[PASS] test_configuredPanelParametersFlowIntoBodyAndChecks() (gas: 4954218)\n[PASS] test_controlCharactersAndGuillemetsRejected() (gas: 3871369)\n[PASS] test_intakeFailureUnderpaymentDuplicateIdAndReentry() (gas: 7780965)\n[PASS] test_liveFormatDeliveryWithDistinctOracleIdApproves() (gas: 4539248)\n[PASS] test_malformedUTF8Rejected() (gas: 224798)\n[PASS] test_oldPendingUsesSnapshotIntakeSignerAndDomain() (gas: 5787208)\n[PASS] test_onlyIntakeOnlyPendingReplayAndUnknownIds() (gas: 4632108)\n[PASS] test_oracleClockMayRunSlightlyAheadAndValidityMayBeLong() (gas: 4517395)\n[PASS] test_ownerConfigSnapshotsInvalidatesOldExecutionAndCanClear() (gas: 6118650)\n[PASS] test_questionHashMustMatchStoredQuestionAndWindow() (gas: 6921229)\n[PASS] test_quotesInsideReasonCannotCloseTheDelimiter() (gas: 4368533)\n[PASS] test_sellQuestionIncludesHoldingsPriceBasisTimeNftAndReason() (gas: 11305761)\n[PASS] test_submitPaysExactlyQuotedPriceAndRevokesAllowance() (gas: 3466060)\n[PASS] test_timeoutClearsNoLateCallbackNoTradeFundsEscrowed() (gas: 6630529)\n[PASS] test_trueApprovesForFiveMinutesAndFalseRejects() (gas: 7767522)\n[PASS] test_wrongChainAndSizeAndConcurrentRequestRejected() (gas: 3567483)\nSuite result: ok. 22 passed; 0 failed; 0 skipped; finished in 657.71ms (663.45ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:ReverseOrderLaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64769)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 79085)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9557444)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8094174)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 193196633)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 753.36ms (92.08ms CPU time)\n\nRan 16 tests for test/AdversarialOracle.t.sol:AdversarialOracleTest\n[PASS] testFuzz_malformedSignatureLengthCannotConsumeRequest(uint8) (runs: 1000, μ: 4496292, ~: 4496144)\nLogs:\n  Bound result 0\n\n[PASS] test_attestationIssuedBeforeSubmissionIsRefused() (gas: 4576471)\n[PASS] test_callbackHasNoDependencyOnTokenNftIntakeOrPoolReads() (gas: 4620433)\n[PASS] test_configurationRejectsEveryInvalidBoundaryWithoutAdvancingVersion() (gas: 1831229)\n[PASS] test_everySignedFieldRejectsPostSignatureMutation() (gas: 22116367)\n[PASS] test_explicitVerifierReplacesGateInDomainAndBody() (gas: 4979490)\n[PASS] test_failedOraclePaymentLeavesNoRequestAndCanRetry() (gas: 3861715)\n[PASS] test_identicalReasonFromAnotherUserDoesNotShareAttestation() (gas: 6630899)\n[PASS] test_mainnetDefaultsMatchAssignment() (gas: 24713)\n[PASS] test_rejectedAndClearedIdsCannotReplayOrAlterNewActiveRequest() (gas: 10948545)\n[PASS] test_rejectionReleasesSlotAndResubmissionNeedsFreshDecision() (gas: 7669046)\n[PASS] test_signatureRejectsHighSAndInvalidV() (gas: 4671239)\n[PASS] test_signatureRejectsWrongNameVersionAndDomainChain() (gas: 4848173)\n[PASS] test_timeoutAndApprovalBoundaryAtLastPermittedSecond() (gas: 5207672)\n[PASS] test_zeroOraclePriceAndZeroReturnedIdAreHandledAtomically() (gas: 3783049)\n[PASS] test_zeroVerifierMeansThisGateAndIsStoredResolved() (gas: 3735878)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 883.14ms (860.51ms CPU time)\n\nRan 5 tests for test/CabalCoin.t.sol:CabalCoinTest\n[PASS] testFuzz_transferConservesSupply(uint256) (runs: 256, μ: 83348, ~: 83363)\nLogs:\n  Bound result 26143263\n\n[PASS] test_allowanceAndInsufficientBalances() (gas: 197125)\n[PASS] test_launchSupplyMetadataAndPlainTransfer() (gas: 119450)\n[PASS] test_noAdministrativeMint() (gas: 36108)\n[PASS] test_runtimeNoEscapeHatches() (gas: 625143)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 1.14s (1.14s CPU time)\n\nRan 20 tests for test/Trading.t.sol:TradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9604001, ~: 9607069)\nLogs:\n  Bound result 892592639094495566288\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 9975542)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 232918)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23721513)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5172580)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10558103)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5201920)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4624592)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5515353)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13099998)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 57084043)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5322649)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5886893)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117029)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10168058)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5318046)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100513)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 330185)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11446682)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.15s (1.23s CPU time)\n\nRan 3 tests for test/OracleLatency.t.sol:OracleLatencyTest\n[PASS] test_deliveryAtOldExpiryRetainsFullApproval() (gas: 5317541)\n[PASS] test_deliveryJustBeforeOldExpiryRetainsFullApproval() (gas: 5317629)\n[PASS] test_deliveryJustBeforeRequestDeadlineRetainsFullApproval() (gas: 5317695)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 1.44s (7.20ms CPU time)\n\nRan 20 tests for test/Trading.t.sol:ReverseOrderTradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9638516, ~: 9641640)\nLogs:\n  Bound result 999000000000026143264\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 10009891)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 233390)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23853202)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5206547)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10638495)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5236170)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4624527)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5554369)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13133692)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 15956781)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5330342)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5962706)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117294)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10262850)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5352452)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100508)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 330137)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11550642)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.44s (1.54s CPU time)\n\nRan 7 tests for test/HookBinding.t.sol:ReverseOrderHookBindingTest\n[PASS] test_buySubmissionRequiresHookHandoffBeforeCharging() (gas: 39410941)\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5645309)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 593624)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 24760048)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 15426303)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 26099613)\n[PASS] test_sellSubmissionRequiresHookHandoffBeforeCharging() (gas: 39962943)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.44s (94.34ms CPU time)\n\nRan 9 tests for test/EconomicProperties.t.sol:EconomicPropertiesTest\n[PASS] testFuzz_feeCannotExceedHalfPercentAndRoundingIsBounded(uint256) (runs: 1000, μ: 17505, ~: 17678)\n[PASS] testFuzz_priceMovementSymmetricMonotoneAndBounded(uint160,uint160,uint160) (runs: 1000, μ: 51370, ~: 51343)\nLogs:\n  Bound result 49068\n  Bound result 49069\n  Bound result 5387954138806663700726636117641967679146348\n\n[PASS] testFuzz_repeatedBuySellCannotCreateImd(uint256,uint8) (runs: 1000, μ: 16443239, ~: 17415218)\nLogs:\n  Bound result 1820409023311\n  Bound result 1\n\n[PASS] test_feeAndPriceKnownBoundaries() (gas: 58513)\n[PASS] test_insufficientExecutionAllowancePreservesApprovalAndCanRetry() (gas: 5460568)\n[PASS] test_realTradesAtFeeRoundingEdges() (gas: 23290138)\n[PASS] test_sellApprovalSurvivesBalanceDropAndExecutesOnceRestored() (gas: 9866608)\n[PASS] test_sellLargerThanTrackedHoldingsClearsTheRecordWithoutUnderflow() (gas: 9653890)\n[PASS] test_sellSlippageFailureRollsBackFeePositionAndCostBasis() (gas: 10235623)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.44s (1.43s CPU time)\n\nRan 7 tests for test/QuestionProperties.t.sol:QuestionPropertiesTest\n[PASS] testFuzz_jsonRoundTripsUntrustedPrintableAscii(bytes,bool,uint128) (runs: 1000, μ: 5045770, ~: 5535076)\n[PASS] test_emptyReasonIsQuotedAndLeftForPanelJudgment() (gas: 9346155)\n[PASS] test_everyAsciiControlCharacterRefusedQuoteBackslashAndDelSurvive() (gas: 15890019)\n[PASS] test_guillemetsRefusedAnywhereOtherLatin1Accepted() (gas: 9970465)\n[PASS] test_invalidUtf8NeverEntersOracleJson() (gas: 243913)\n[PASS] test_questionNeverExceedsTwoThousandCharactersAtMaximalValues() (gas: 2373470)\n[PASS] test_unicodeScalarLimitsIncludeAllUtf8Widths() (gas: 67874956)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.44s (1.71s CPU time)\n\nRan 7 tests for test/ReasonEscaping.t.sol:ReasonEscapingTest\n[PASS] testFuzz_arbitraryBytesAreJudgedLikeAnIndependentDecoder(bytes) (runs: 1000, μ: 15128, ~: 12712)\n[PASS] testFuzz_oneCorruptedByteIsJudgedLikeAnIndependentDecoder(bytes32,uint16,uint16,uint8) (runs: 1000, μ: 279224, ~: 171906)\nLogs:\n  Bound result 276\n  Bound result 340\n\n[PASS] testFuzz_wellFormedTextOfEveryWidthIsCountedEscapedAndQuotedExactly(bytes32,uint16) (runs: 1000, μ: 2034263, ~: 1794093)\nLogs:\n  Bound result 164\n\n[PASS] test_byteBoundBeforeContentAndScalarBoundAfterIt() (gas: 1479560)\n[PASS] test_escapedQuestionHashesLikeTheParsedBody() (gas: 2977892)\n[PASS] test_quotesAndBackslashesAreEscapedBetweenMultibyteText() (gas: 32360)\n[PASS] test_truncatedLeadByteAtTheEndIsRefusedWhateverFollowsInMemory() (gas: 28243)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.44s (3.25s CPU time)\n\nRan 2 tests for test/invariant/CabalInvariant.t.sol:CabalInvariantTest\n[PASS] invariant_conservationSettlementLifecycleAndLockedPol() (runs: 256, calls: 16384, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| CabalHandler | advance            | 1517  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1451  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1480  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1457  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1506  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1433  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1506  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1567  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1531  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1461  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1475  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 152\n  Bound result 2030\n  Bound result 0\n  Bound result 9686\n  Bound result 916461098030585800712\n  Bound result 30000\n  Bound result 19\n  Bound result 7\n  Bound result 456\n  Bound result 12\n  Bound result 240\n  Bound result 17454291160558330\n  Bound result 21\n  Bound result 650335829851491\n  Bound result 301500000000000000000\n  Bound result 21559\n  Bound result 214\n  Bound result 1000000000000000000000\n  Bound result 1537\n  Bound result 828\n  Bound result 255\n  Bound result 16383\n  Bound result 7\n  Bound result 85878298968341232639\n  Bound result 152\n  Bound result 3348\n  Bound result 4594638\n  Bound result 144\n  Bound result 21\n  Bound result 8731882322643402\n  Bound result 999999999999999999733\n  Bound result 6353\n  Bound result 2048\n  Bound result 2142\n  Bound result 255\n  Bound result 1048576\n  Bound result 8213613789608926\n  Bound result 4\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16309807)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 10000000000000000000\n  Bound result 10000000000000000000\n  Bound result 3601\n  Bound result 10000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 8.28s (8.27s CPU time)\n\nRan 2 tests for test/invariant/CabalInvariant.t.sol:CabalReverseInvariantTest\n[PASS] invariant_conservationSettlementLifecycleAndLockedPol() (runs: 256, calls: 16384, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| CabalHandler | advance            | 1517  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1451  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1480  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1457  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1506  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1433  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1506  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1567  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1531  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1461  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1475  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 152\n  Bound result 2280\n  Bound result 0\n  Bound result 0\n  Bound result 916461098030585800712\n  Bound result 30000\n  Bound result 11\n  Bound result 7\n  Bound result 2242\n  Bound result 6\n  Bound result 240\n  Bound result 17454291160558330\n  Bound result 16\n  Bound result 650335829851491\n  Bound result 301500000000000000000\n  Bound result 22742\n  Bound result 52\n  Bound result 1537\n  Bound result 3368\n  Bound result 255\n  Bound result 16383\n  Bound result 7\n  Bound result 152\n  Bound result 2162\n  Bound result 2515079592\n  Bound result 144\n  Bound result 12\n  Bound result 999999999999999801\n  Bound result 9524\n  Bound result 1747\n  Bound result 2048\n  Bound result 1869\n  Bound result 255\n  Bound result 1048576\n  Bound result 999999999000000001\n  Bound result 11\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16351914)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 10000000000000000000\n  Bound result 10000000000000000000\n  Bound result 3601\n  Bound result 10000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 8.29s (8.30s CPU time)\n\nRan 22 test suites in 8.29s (30.88s CPU time): 151 tests passed, 0 failed, 0 skipped (151 total tests)\n","passed":true},{"durationMs":105,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CabalCoin.approve(address,uint256)\",\"CabalCoin.transfer(address,uint256)\",\"CabalCoin.transferFrom(address,address,uint256)\",\"CabalGate.acceptOwnership()\",\"CabalGate.clearRequest(bytes32)\",\"CabalGate.configure((address,address,address,address,bytes32,uint128,uint128,uint16,uint16,uint16,uint16,uint8,uint8))\",\"CabalGate.executeBuyRequest(bytes32)\",\"CabalGate.executeBuyRequest(bytes32,uint256)\",\"CabalGate.executeSellRequest(bytes32)\",\"CabalGate.executeSellRequest(bytes32,uint256)\",\"CabalGate.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"CabalGate.renounceOwnership()\",\"CabalGate.setSlippageLimit(bytes32,uint256)\",\"CabalGate.submitBuyRequest(uint256,string)\",\"CabalGate.submitSellRequest(uint256,string)\",\"CabalGate.transferOwnership(address)\",\"CabalGate.unlockCallback(bytes)\",\"CabalHook.acceptOwnership()\",\"CabalHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CabalHook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"CabalHook.compound(int24,int24)\",\"CabalHook.finishSwap()\",\"CabalHook.renounceOwnership()\",\"CabalHook.setGate(address)\",\"CabalHook.setIMD(address)\",\"CabalHook.transferOwnership(address)\",\"CabalHook.unlockCallback(bytes)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":128,\"README.md\":59,\"docs/DEPLOYMENT.md\":74,\"docs/ORACLE.md\":97,\"docs/SECURITY.md\":29,\"docs/dependencies.json\":26,\"foundry.toml\":20,\"launch.json\":29,\"script/HookSaltMiner.sol\":23,\"src/CabalCoin.sol\":11,\"src/CabalGate.sol\":502,\"src/CabalHook.sol\":257,\"src/HookFlags.sol\":29,\"src/ImpactEstimator.sol\":91,\"src/QuestionBuilder.sol\":124,\"src/interfaces/IIntake.sol\":41,\"src/libraries/CanonicalRequest.sol\":34,\"src/libraries/DataStore.sol\":27,\"src/libraries/Json.sol\":145,\"src/libraries/MainnetDefaults.sol\":11,\"src/libraries/OracleSignature.sol\":42,\"src/libraries/PriceMath.sol\":14,\"test/AdversarialOracle.t.sol\":334,\"test/CabalCoin.t.sol\":62,\"test/CabalFixture.sol\":353,\"test/EconomicProperties.t.sol\":188,\"test/GateLaunch.t.sol\":234,\"test/HookBinding.t.sol\":359,\"test/Launch.t.sol\":137,\"test/Oracle.t.sol\":439,\"test/OracleLatency.t.sol\":44,\"test/OracleLiveVector.t.sol\":81,\"test/OracleSigner.t.sol\":41,\"test/QuestionProperties.t.sol\":264,\"test/README.md\":21,\"test/ReasonEscaping.t.sol\":373,\"test/SubmissionGas.t.sol\":67,\"test/Trading.t.sol\":493,\"test/invariant/CabalHandler.sol\":355,\"test/invariant/CabalInvariant.t.sol\":75,\"test/mocks/MockERC20.sol\":13,\"test/mocks/MockIntake.sol\":93},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true},{"durationMs":8338,"exitCode":0,"name":"slither","output":"[high/medium] reentrancy-balance at src/CabalGate.sol:236: Reentrancy in CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#236-296):\n[high/medium] reentrancy-balance at src/CabalGate.sol:236: Reentrancy in CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#236-296):\n[medium/medium] divide-before-multiply at src/CabalHook.sol:218: CabalHook._addSingleSided(bool,uint256) (src/CabalHook.sol#218-240) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/CabalHook.sol:179: CabalHook.finishSwap() (src/CabalHook.sol#179-196) performs a multiplication on the result of a division:\n[medium/medium] divide-before-multiply at src/CabalHook.sol:175: CabalHook.feeFor(uint256) (src/CabalHook.sol#175-177) performs a multiplication on the result of a division:\n[medium/high] incorrect-equality at src/CabalHook.sol:218: CabalHook._addSingleSided(bool,uint256) (src/CabalHook.sol#218-240) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalGate.sol:486: CabalGate._reduceHolding(CabalGate.Holding,uint256) (src/CabalGate.sol#486-494) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalGate.sol:236: CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#236-296) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalGate.sol:486: CabalGate._reduceHolding(CabalGate.Holding,uint256) (src/CabalGate.sol#486-494) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalHook.sol:218: CabalHook._addSingleSided(bool,uint256) (src/CabalHook.sol#218-240) uses a dangerous strict equality:\n[medium/medium] reentrancy-no-eth at src/CabalGate.sol:236: Reentrancy in CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#236-296):\n[medium/medium] reentrancy-no-eth at src/CabalGate.sol:379: Reentrancy in CabalGate._execute(bytes32,bool,uint256) (src/CabalGate.sol#379-415):\n[medium/medium] unused-return at src/CabalHook.sol:218: CabalHook._addSingleSided(bool,uint256) (src/CabalHook.sol#218-240) ignores return value by (None,tick,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalHook.sol#220)\n[medium/medium] unused-return at src/CabalHook.sol:206: CabalHook.unlockCallback(bytes) (src/CabalHook.sol#206-214) ignores return value by (delta,None) = poolManager.modifyLiquidity(_key,ModifyLiquidityParams(lower,upper,0,0),) (src/CabalHook.sol#209)\n[medium/medium] unused-return at src/CabalGate.sol:236: CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#236-296) ignores return value by (sqrtPrice,None,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalGate.sol#246)\n[medium/medium] unused-return at src/ImpactEstimator.sol:33: ImpactEstimator.estimate(bool,uint256) (src/ImpactEstimator.sol#33-60) ignores return value by (sqrtPrice,tick,None,None) = poolManager.getSlot0(poolId) (src/ImpactEstimator.sol#35)\n[medium/medium] unused-return at src/CabalHook.sol:199: CabalHook.compound(int24,int24) (src/CabalHook.sol#199-204) ignores return value by poolManager.unlock(abi.encode(lower,upper)) (src/CabalHook.sol#202)\n[medium/medium] unused-return at src/CabalGate.sol:417: CabalGate.unlockCallback(bytes) (src/CabalGate.sol#417-455) ignores return value by (beforePrice,None,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalGate.sol#432)\n[medium/medium] unused-return at src/CabalGate.sol:417: CabalGate.unlockCallback(bytes) (src/CabalGate.sol#417-455) ignores return value by (afterPrice,None,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalGate.sol#443)\n[medium/medium] unused-return at src/ImpactEstimator.sol:33: ImpactEstimator.estimate(bool,uint256) (src/ImpactEstimator.sol#33-60) ignores return value by (None,liquidityNet) = poolManager.getTickLiquidity(poolId,next) (src/ImpactEstimator.sol#41)\n[medium/medium] unused-return at src/CabalHook.sol:218: CabalHook._addSingleSided(bool,uint256) (src/CabalHook.sol#218-240) ignores return value by (delta,None) = poolManager.modifyLiquidity(_key,ModifyLiquidityParams(lower,upper,int256(liquidity),0),) (src/CabalHook.sol#234-235)\n[medium/medium] unused-return at src/CabalGate.sol:379: CabalGate._execute(bytes32,bool,uint256) (src/CabalGate.sol#379-415) ignores return value by (current,None,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalGate.sol#391)\n[low/medium] missing-zero-check at src/CabalHook.sol:126: CabalHook.beforeInitialize(address,PoolKey,uint160).sender (src/CabalHook.sol#126) lacks a zero-check on :\n[low/medium] reentrancy-benign at src/CabalGate.sol:236: Reentrancy in CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#236-296):\n[low/medium] reentrancy-benign at src/CabalHook.sol:199: Reentrancy in CabalHook.compound(int24,int24) (src/CabalHook.sol#199-204):\n[low/medium] reentrancy-benign at src/CabalGate.sol:379: Reentrancy in CabalGate._execute(bytes32,bool,uint256) (src/CabalGate.sol#379-415):\n[low/medium] reentrancy-events at src/CabalHook.sol:206: Reentrancy in CabalHook.unlockCallback(bytes) (src/CabalHook.sol#206-214):\n[low/medium] reentrancy-events at src/CabalHook.sol:218: Reentrancy in CabalHook._addSingleSided(bool,uint256) (src/CabalHook.sol#218-240):\n[low/medium] reentrancy-events at src/CabalHook.sol:206: Reentrancy in CabalHook.unlockCallback(bytes) (src/CabalHook.sol#206-214):\n[low/medium] timestamp at src/CabalGate.sol:302: CabalGate.onOracleResult(bytes32,Attestation,bytes) (src/CabalGate.sol#302-334) uses timestamp for comparisons\n[low/medium] timestamp at src/CabalGate.sol:236: CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#236-296) uses timestamp for comparisons\n[low/medium] timestamp at src/CabalGate.sol:379: CabalGate._execute(bytes32,bool,uint256) (src/CabalGate.sol#379-415) uses timestamp for comparisons\n[low/medium] timestamp at src/CabalGate.sol:345: CabalGate.clearRequest(bytes32) (src/CabalGate.sol#345-359) uses timestamp for comparisons","passed":true},{"durationMs":710,"exitCode":0,"name":"aderyn","output":"[high] abi-encode-packed-hash-collision at src/QuestionBuilder.sol:98: `abi.encodePacked()` Hash Collision (3 places)\n[high] reentrancy-state-change at src/CabalGate.sol:142: Reentrancy: State change after external call (9 places)\n[low] centralization-risk at src/CabalGate.sol:28: Centralization Risk (5 places)\n[low] division-before-multiplication at src/CabalHook.sol:221: Incorrect Order of Division and Multiplication\n[low] internal-function-used-once at src/HookFlags.sol:22: Internal Function Used Only Once\n[low] large-numeric-literal at src/CabalCoin.sol:9: Large Numeric Literal (12 places)\n[low] literal-instead-of-constant at src/CabalGate.sol:220: Literal Instead of Constant (78 places)\n[low] modifier-used-only-once at src/CabalHook.sol:91: Modifier Invoked Only Once\n[low] non-reentrant-not-first at src/CabalGate.sol:210: `nonReentrant` is Not the First Modifier (2 places)\n[low] require-revert-in-loop at src/ImpactEstimator.sol:70: Loop Contains `require`/`revert` (2 places)\n[low] state-change-without-event at src/CabalGate.sol:417: State Change Without Event (3 places)\n[low] state-no-address-check at src/CabalHook.sol:135: Address State Variable Set Without Checks\n[low] unchecked-return at src/CabalHook.sol:202: Unchecked Return\n[low] uninitialized-local-variable at src/ImpactEstimator.sol:70: Uninitialized Local Variable (2 places)\n[low] unused-public-function at src/CabalHook.sol:175: Public Function Not Used Internally","passed":true},{"durationMs":23191,"exitCode":0,"name":"proof 0c508e6b061b","output":"Compiling 104 files with Solc 0.8.26\nSolc 0.8.26 finished in 22.53s\nCompiler run successful!\n\nRan 1 test for test/imd-proof-59d633fd/Proof_0c508e6b061b.t.sol:UnboundGateSubmissionTest\n[PASS] test_submissionRefusedWhileHookIsNotBoundToThisGate() (gas: 688839)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 4.55ms (319.57µs CPU time)\n\nRan 1 test suite in 5.12ms (4.55ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)\n","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"deded3b6aca8bab2eccb0e4ea0c55baf745d67c3c327af311f78f46e3d19788e","verifiedTreeHash":"81450031b66df73415dbb9cca65db72cbb3046f8","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":129373,"exitCode":0,"name":"build","output":"Compiling 118 files with Solc 0.8.26\nSolc 0.8.26 finished in 129.13s\nCompiler run successful!\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n   ╭▸ src/libraries/CanonicalRequest.sol:21:13\n   │\n21 │ ┏             abi.encodePacked(\n22 │ ┃                 '{\"answerType\":\"bool\",\"chainId\":1,\"definitions\":{',\n23 │ ┃                 definitions,\n24 │ ┃                 '},\"evidence\":\"panel\",\"question\":\"',\n   ‡ ┃\n30 │ ┃                 \"}}\"\n31 │ ┃             )\n   │ ┗━━━━━━━━━━━━━┛\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[unsafe-typecast]: typecast can truncate values\n  ╭▸ src/libraries/MainnetDefaults.sol:9:54\n  │\n9 │     address internal constant IDENTITY_NFT = address(bytes20(hex\"0000ec93127baa929e58e97dd0095a2bfb38ec1d\"));\n  │                                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n  │\n  ├ note: consider disabling this lint if you're certain the cast is safe\n  │       \n  │       // casting to 'bytes20' is safe because [explain why]\n  │       // forge-lint: disable-next-line(unsafe-typecast)\n  │       \n  │       \n  ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/MainnetDefaults.sol:10:40\n   │\n10 │     bytes32 internal constant ACTION = bytes32(\"oracle.request@oracle-1\");\n   │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/QuestionBuilder.sol:98:16\n    │\n 98 │           body = abi.encodePacked(\n    │ ┏━━━━━━━━━━━━━━━━┛\n 99 │ ┃             '{\"answerType\":\"bool\",\"chainId\":1,\"consumer\":{\"chainId\":1,\"verifyingContract\":\"',\n100 │ ┃             c.verifier.toHexString(),\n101 │ ┃             '\"},\"definitions\":{',\n    ‡ ┃\n112 │ ┃             \"}}\"\n113 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:44:31\n   │\n44 │                 if (c < 0x20) revert ForbiddenCharacter();\n   │                               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:56:22\n   │\n56 │                 else revert InvalidUTF8();\n   │                      ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:57:36\n   │\n57 │                 if (src + n > end) revert InvalidUTF8();\n   │                                    ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:59:43\n   │\n59 │                 if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                           ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:61:64\n   │\n61 │                     if (c == 0xc2 && (d == 0xab || d == 0xbb)) revert ForbiddenCharacter();\n   │                                                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:66:23\n   │\n66 │                     ) revert InvalidUTF8();\n   │                       ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:68:47\n   │\n68 │                     if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:71:51\n   │\n71 │                         if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                                   ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/libraries/Json.sol:92:16\n   │\n92 │         while (i < s.length) {\n   │                ━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:99:18\n   │\n99 │             else revert InvalidUTF8();\n   │                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:100:35\n    │\n100 │             if (i + n > s.length) revert InvalidUTF8();\n    │                                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:103:43\n    │\n103 │                 if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n    │                                           ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:110:19\n    │\n110 │                 ) revert InvalidUTF8();\n    │                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/libraries/Json.sol:127:21\n    │\n127 │                 out[k++] = \"\\\\\";\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[missing-events-access-control]: `_executing` is changed without an event but is used for access control\n    ╭▸ src/CabalGate.sol:421:9\n    │\n421 │         _executing = false;\n    │         ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:225:9\n    │\n225 │         emit Configured(configVersion, cfg);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/CabalGate.sol:210:64\n    │\n210 │     function configure(Config calldata cfg) external onlyOwner nonReentrant {\n    │                                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:219:65\n    │\n219 │                 || cfg.maxSellAmount == 0 || cfg.maxBuyAmount > uint128(type(int128).max)\n    │                                                                 ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:220:40\n    │\n220 │                 || cfg.maxSellAmount > uint128(type(int128).max) || cfg.maxImpactBps == 0 || cfg.maxImpactBps > 5000\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `activeRequest` is updated\n    ╭▸ src/CabalGate.sol:275:14\n    │\n275 │           id = IIntake(cfg.intake)\n    │ ┏━━━━━━━━━━━━━━┛\n276 │ ┃             .request(cfg.action, body, IIntake.Callback(address(this), this.onOracleResult.selector), cfg.imd, price);\n    │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:294:9\n    │\n294 │         emit RequestSubmitted(id, msg.sender, buy, amount, question, body);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalGate.sol:278:13\n    │\n278 │         if (payment.balanceOf(address(this)) != beforePayment) revert UnsupportedToken();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:284:24\n    │\n284 │             createdAt: uint64(block.timestamp),\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:285:23\n    │\n285 │             deadline: uint64(block.timestamp + REQUEST_TIMEOUT),\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:288:21\n    │\n288 │             amount: uint128(amount),\n    │                     ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/CabalHook.sol:113:22\n    │\n113 │     function setGate(address candidate) external onlyOwner {\n    │                      ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:305:35\n    │\n305 │         if (block.chainid != 1 || block.timestamp >= r.deadline) revert Expired();\n    │                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:311:74\n    │\n311 │                 || a.agreed > a.panelSize || a.issuedAt < r.createdAt || a.issuedAt > block.timestamp + CLOCK_TOLERANCE\n    │                                                                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:312:20\n    │\n312 │                 || a.expiresAt <= block.timestamp || a.expiresAt <= a.issuedAt\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:327:38\n    │\n327 │             r.approvedUntil = uint64(until < a.expiresAt ? until : a.expiresAt);\n    │                                      ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:332:9\n    │\n332 │         emit OracleResult(requestId, a.requestId, approved, r.approvedUntil);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:327:31\n    │\n327 │             r.approvedUntil = uint64(until < a.expiresAt ? until : a.expiresAt);\n    │                               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:349:33\n    │\n349 │             if (!staleConfig && block.timestamp < r.deadline) revert InvalidRequest();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:351:33\n    │\n351 │             if (!staleConfig && block.timestamp < r.approvedUntil) revert InvalidRequest();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:383:13\n    │\n383 │         if (block.timestamp >= r.approvedUntil) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:413:9\n    │\n413 │         emit RequestExecuted(id, r.amount, output, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:405:44\n    │\n405 │             if (h.units == 0) h.firstBuy = uint64(block.timestamp);\n    │                                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/CabalHook.sol:126:31\n    │\n126 │     function beforeInitialize(address sender, PoolKey calldata key, uint160) external onlyManager returns (bytes4) {\n    │                               ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:445:26\n    │\n445 │         uint256 output = uint256(outputDelta);\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalGate.sol:477:13\n    │\n477 │         if (token.balanceOf(address(this)) != beforeBalance + amount) revert UnsupportedToken();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/CabalGate.sol:497:13\n    │\n497 │             IDENTITY_NFT.staticcall{gas: 30000}(abi.encodeWithSignature(\"balanceOf(address)\", user));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:71:83\n   │\n71 │             if (compressed < minCompressed || compressed > maxCompressed) return (false, 0);\n   │                                                                                   ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:78:29\n   │\n78 │                     return (true, (compressed - int24(uint24(bitPos - BitMath.mostSignificantBit(masked)))) * spacing);\n   │                             ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:84:29\n   │\n84 │                     return (true, (compressed + int24(uint24(BitMath.leastSignificantBit(masked) - bitPos))) * spacing);\n   │                             ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:89:17\n   │\n89 │         return (false, 0);\n   │                 ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:163:19\n    │\n163 │         feeBase = uint256(amount < 0 ? -amount : amount);\n    │                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:176:16\n    │\n176 │         return (volume / 400) * 2;\n    │                ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:45:25\n   │\n45 │             liquidity = uint128(uint256(entered));\n   │                         ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:45:33\n   │\n45 │             liquidity = uint128(uint256(entered));\n   │                                 ━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:59:46\n   │\n59 │         return PriceMath.movement(sqrtPrice, uint160(end));\n   │                                              ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:72:29\n   │\n72 │             int16 wordPos = int16(compressed >> 8);\n   │                             ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:73:34\n   │\n73 │             uint8 bitPos = uint8(uint256(int256(compressed)) & 0xff);\n   │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:235:13\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:249:13\n    │\n249 │             poolManager.take(currency, address(this), uint128(delta));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:252:13\n    │\n252 │             poolManager.sync(currency);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:254:17\n    │\n254 │             if (poolManager.settle() != owed) revert UnsupportedToken();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:183:15\n    │\n183 │         fee = half * 2;\n    │               ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/CabalHook.sol:179:45\n    │\n179 │     function finishSwap() external onlyGate nonReentrant returns (uint256 fee) {\n    │                                             ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalHook.sol:195:9\n    │\n195 │         emit FeePaid(volume, half, half);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalHook.sol:189:17\n    │\n189 │             if (imd.balanceOf(address(this)) != beforeBalance + fee) revert UnsupportedToken();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:202:9\n    │\n202 │         poolManager.unlock(abi.encode(lower, upper));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:202:9\n    │\n202 │         poolManager.unlock(abi.encode(lower, upper));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalHook.sol:237:9\n    │\n237 │ ┏         emit ProtocolLiquidityAdded(\n238 │ ┃             lower, upper, uint128(liquidity), Currency.unwrap(token0 ? _key.currency0 : _key.currency1), amount\n239 │ ┃         );\n    │ ┗━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:209:33\n    │\n209 │         (BalanceDelta delta,) = poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, 0, 0), \"\");\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:221:22\n    │\n221 │         int24 grid = tick / 60 * 60;\n    │                      ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:233:25\n    │\n233 │         if (liquidity > uint256(uint128(type(int128).max))) revert InvalidRange();\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:233:33\n    │\n233 │         if (liquidity > uint256(uint128(type(int128).max))) revert InvalidRange();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:235:13\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:235:83\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │                                                                                   ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:238:27\n    │\n238 │             lower, upper, uint128(liquidity), Currency.unwrap(token0 ? _key.currency0 : _key.currency1), amount\n    │                           ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:249:55\n    │\n249 │             poolManager.take(currency, address(this), uint128(delta));\n    │                                                       ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:251:28\n    │\n251 │             uint256 owed = uint256(-int256(delta));\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\n","passed":true},{"durationMs":8957,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/Trading.t.sol:ReverseTokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5190176)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 9.19ms (4.59ms CPU time)\n\nRan 1 test for test/Oracle.t.sol:OracleGasTest\n[PASS] test_callbackFitsBelow200kColdTransaction() (gas: 2041545)\nLogs:\n  callback gas including external call: 78063\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 70.32ms (3.28ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64769)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 78629)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9516946)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8020785)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 80854255)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 79.52ms (51.15ms CPU time)\n\nRan 2 tests for test/SubmissionGas.t.sol:SubmissionGasTest\n[PASS] test_longestReasonStaysUnderBudget() (gas: 1239827)\n[PASS] test_shortBuyAndSellStayUnderBudget() (gas: 1090419)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 81.52ms (1.55ms CPU time)\n\nRan 3 tests for test/OracleLatency.t.sol:OracleLatencyTest\n[PASS] test_deliveryAtOldExpiryRetainsFullApproval() (gas: 5314564)\n[PASS] test_deliveryJustBeforeOldExpiryRetainsFullApproval() (gas: 5314652)\n[PASS] test_deliveryJustBeforeRequestDeadlineRetainsFullApproval() (gas: 5314718)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 89.82ms (8.42ms CPU time)\n\nRan 5 tests for test/HookBinding.t.sol:ReverseOrderHookBindingTest\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5642382)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 593641)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 24678373)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 15426281)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 26017928)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 98.00ms (89.62ms CPU time)\n\nRan 1 test for test/OracleSigner.t.sol:OracleSignerTest\n[PASS] test_registrySignatureIsNotAnEOASignatureForTheConfiguredSigner() (gas: 4973110)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 96.89ms (2.82ms CPU time)\n\nRan 1 test for test/Trading.t.sol:TokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5187043)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 115.19ms (4.10ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:ReverseOrderLaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64769)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 79085)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9551491)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8021013)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 193196633)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 124.57ms (119.36ms CPU time)\n\nRan 5 tests for test/HookBinding.t.sol:HookBindingTest\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5608092)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 592405)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 13503744)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 4759785)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 14839190)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 178.06ms (40.06ms CPU time)\n\nRan 22 tests for test/Oracle.t.sol:OracleTest\n[PASS] testFuzz_attestationFieldsAreBound(uint8) (runs: 256, μ: 4468657, ~: 4466866)\nLogs:\n  Bound result 12\n\n[PASS] test_280UnicodeCharactersAccepted281Rejected() (gas: 7520888)\n[PASS] test_approvalNeverOutlivesAttestation() (gas: 4514522)\n[PASS] test_attestationCannotBeReusedForAnotherRequest() (gas: 7796718)\n[PASS] test_badSignerDomainAndTampering() (gas: 4795409)\n[PASS] test_bodyIsCanonicalJsonWithConsumerAndStoredEscapedQuestion() (gas: 14348105)\n[PASS] test_configuredPanelParametersFlowIntoBodyAndChecks() (gas: 4951241)\n[PASS] test_controlCharactersAndGuillemetsRejected() (gas: 3853513)\n[PASS] test_intakeFailureUnderpaymentDuplicateIdAndReentry() (gas: 7769060)\n[PASS] test_liveFormatDeliveryWithDistinctOracleIdApproves() (gas: 4536271)\n[PASS] test_malformedUTF8Rejected() (gas: 218846)\n[PASS] test_oldPendingUsesSnapshotIntakeSignerAndDomain() (gas: 5784231)\n[PASS] test_onlyIntakeOnlyPendingReplayAndUnknownIds() (gas: 4629131)\n[PASS] test_oracleClockMayRunSlightlyAheadAndValidityMayBeLong() (gas: 4514418)\n[PASS] test_ownerConfigSnapshotsInvalidatesOldExecutionAndCanClear() (gas: 6115673)\n[PASS] test_questionHashMustMatchStoredQuestionAndWindow() (gas: 6918252)\n[PASS] test_quotesInsideReasonCannotCloseTheDelimiter() (gas: 4365557)\n[PASS] test_sellQuestionIncludesHoldingsPriceBasisTimeNftAndReason() (gas: 11299808)\n[PASS] test_submitPaysExactlyQuotedPriceAndRevokesAllowance() (gas: 3463083)\n[PASS] test_timeoutClearsNoLateCallbackNoTradeFundsEscrowed() (gas: 6624575)\n[PASS] test_trueApprovesForFiveMinutesAndFalseRejects() (gas: 7761569)\n[PASS] test_wrongChainAndSizeAndConcurrentRequestRejected() (gas: 3542586)\nSuite result: ok. 22 passed; 0 failed; 0 skipped; finished in 759.26ms (763.84ms CPU time)\n\nRan 20 tests for test/Trading.t.sol:TradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9598945, ~: 9601116)\nLogs:\n  Bound result 999000000000000018044\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 9969589)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 232918)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23703655)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5169603)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10552150)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5198943)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4621615)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5512376)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13091068)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 57084043)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5319672)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5883916)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117029)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10159129)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5315069)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100513)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 327209)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11437751)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.12s (1.17s CPU time)\n\nRan 2 tests for test/OracleLiveVector.t.sol:OracleLiveVectorTest\n[PASS] test_livePayloadDecodesAndSignatureRecoversToBriefSigner() (gas: 50913)\n[PASS] test_liveQuestionHashIsCanonicalKeccak() (gas: 189084)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.41s (899.78µs CPU time)\n\nRan 6 tests for test/GateLaunch.t.sol:GateLaunchTest\n[PASS] test_constructorRejectsZeroOwner() (gas: 730734)\n[PASS] test_constructorRequiresHookInitializedAndDependencyCode() (gas: 14947638)\n[PASS] test_existingHookOwnerBindsGateOnceAndRefusesSecondGate() (gas: 15817491)\n[PASS] test_explicitOwnerControlsConfigurationInsteadOfFactory() (gas: 8122802)\n[PASS] test_factoryDeploysOnlyGateWithAllThirteenManifestWords() (gas: 27487936)\n[PASS] test_flatConstructorRetainsEveryConfigurationValidation() (gas: 63231961)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 1.41s (50.47ms CPU time)\n\nRan 7 tests for test/ReasonEscaping.t.sol:ReasonEscapingTest\n[PASS] testFuzz_arbitraryBytesAreJudgedLikeAnIndependentDecoder(bytes) (runs: 1000, μ: 16511, ~: 12712)\n[PASS] testFuzz_oneCorruptedByteIsJudgedLikeAnIndependentDecoder(bytes32,uint16,uint16,uint8) (runs: 1000, μ: 301744, ~: 205554)\nLogs:\n  Bound result 223\n  Bound result 95\n\n[PASS] testFuzz_wellFormedTextOfEveryWidthIsCountedEscapedAndQuotedExactly(bytes32,uint16) (runs: 1000, μ: 2032964, ~: 1796356)\nLogs:\n  Bound result 88\n\n[PASS] test_byteBoundBeforeContentAndScalarBoundAfterIt() (gas: 1479560)\n[PASS] test_escapedQuestionHashesLikeTheParsedBody() (gas: 2977892)\n[PASS] test_quotesAndBackslashesAreEscapedBetweenMultibyteText() (gas: 32360)\n[PASS] test_truncatedLeadByteAtTheEndIsRefusedWhateverFollowsInMemory() (gas: 28243)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.40s (3.40s CPU time)\n\nRan 5 tests for test/CabalCoin.t.sol:CabalCoinTest\n[PASS] testFuzz_transferConservesSupply(uint256) (runs: 256, μ: 83306, ~: 83411)\nLogs:\n  Bound result 426228387284829819361527478\n\n[PASS] test_allowanceAndInsufficientBalances() (gas: 197125)\n[PASS] test_launchSupplyMetadataAndPlainTransfer() (gas: 119450)\n[PASS] test_noAdministrativeMint() (gas: 36108)\n[PASS] test_runtimeNoEscapeHatches() (gas: 625143)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 1.41s (1.41s CPU time)\n\nRan 20 tests for test/Trading.t.sol:ReverseOrderTradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9633503, ~: 9635697)\nLogs:\n  Bound result 999000000000000007467\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 10003938)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 233390)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23835344)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5203570)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10632542)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5233193)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4621550)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5551392)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13124762)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 15956781)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5327365)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5959729)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117294)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10253921)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5349475)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100508)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 327161)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11541711)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.42s (1.52s CPU time)\n\nRan 16 tests for test/AdversarialOracle.t.sol:AdversarialOracleTest\n[PASS] testFuzz_malformedSignatureLengthCannotConsumeRequest(uint8) (runs: 1000, μ: 4493324, ~: 4493167)\nLogs:\n  Bound result 126\n\n[PASS] test_attestationIssuedBeforeSubmissionIsRefused() (gas: 4573494)\n[PASS] test_callbackHasNoDependencyOnTokenNftIntakeOrPoolReads() (gas: 4617456)\n[PASS] test_configurationRejectsEveryInvalidBoundaryWithoutAdvancingVersion() (gas: 1831229)\n[PASS] test_everySignedFieldRejectsPostSignatureMutation() (gas: 22113390)\n[PASS] test_explicitVerifierReplacesGateInDomainAndBody() (gas: 4976513)\n[PASS] test_failedOraclePaymentLeavesNoRequestAndCanRetry() (gas: 3855762)\n[PASS] test_identicalReasonFromAnotherUserDoesNotShareAttestation() (gas: 6624945)\n[PASS] test_mainnetDefaultsMatchAssignment() (gas: 24713)\n[PASS] test_rejectedAndClearedIdsCannotReplayOrAlterNewActiveRequest() (gas: 10939614)\n[PASS] test_rejectionReleasesSlotAndResubmissionNeedsFreshDecision() (gas: 7663092)\n[PASS] test_signatureRejectsHighSAndInvalidV() (gas: 4668262)\n[PASS] test_signatureRejectsWrongNameVersionAndDomainChain() (gas: 4845196)\n[PASS] test_timeoutAndApprovalBoundaryAtLastPermittedSecond() (gas: 5204695)\n[PASS] test_zeroOraclePriceAndZeroReturnedIdAreHandledAtomically() (gas: 3777096)\n[PASS] test_zeroVerifierMeansThisGateAndIsStoredResolved() (gas: 3732901)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 1.52s (1.49s CPU time)\n\nRan 7 tests for test/QuestionProperties.t.sol:QuestionPropertiesTest\n[PASS] testFuzz_jsonRoundTripsUntrustedPrintableAscii(bytes,bool,uint128) (runs: 1000, μ: 5005773, ~: 4435769)\n[PASS] test_emptyReasonIsQuotedAndLeftForPanelJudgment() (gas: 9346155)\n[PASS] test_everyAsciiControlCharacterRefusedQuoteBackslashAndDelSurvive() (gas: 15890019)\n[PASS] test_guillemetsRefusedAnywhereOtherLatin1Accepted() (gas: 9970465)\n[PASS] test_invalidUtf8NeverEntersOracleJson() (gas: 243913)\n[PASS] test_questionNeverExceedsTwoThousandCharactersAtMaximalValues() (gas: 2373470)\n[PASS] test_unicodeScalarLimitsIncludeAllUtf8Widths() (gas: 67874956)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.51s (1.71s CPU time)\n\nRan 9 tests for test/EconomicProperties.t.sol:EconomicPropertiesTest\n[PASS] testFuzz_feeCannotExceedHalfPercentAndRoundingIsBounded(uint256) (runs: 1000, μ: 17432, ~: 17678)\n[PASS] testFuzz_priceMovementSymmetricMonotoneAndBounded(uint160,uint160,uint160) (runs: 1000, μ: 51387, ~: 51343)\nLogs:\n  Bound result 492069\n  Bound result 19814753287648616\n  Bound result 1461501637330902918203684832716265454936910065984\n\n[PASS] testFuzz_repeatedBuySellCannotCreateImd(uint256,uint8) (runs: 1000, μ: 16246638, ~: 17403288)\nLogs:\n  Bound result 3345\n  Bound result 3\n\n[PASS] test_feeAndPriceKnownBoundaries() (gas: 58513)\n[PASS] test_insufficientExecutionAllowancePreservesApprovalAndCanRetry() (gas: 5457591)\n[PASS] test_realTradesAtFeeRoundingEdges() (gas: 23272282)\n[PASS] test_sellApprovalSurvivesBalanceDropAndExecutesOnceRestored() (gas: 9860655)\n[PASS] test_sellLargerThanTrackedHoldingsClearsTheRecordWithoutUnderflow() (gas: 9647937)\n[PASS] test_sellSlippageFailureRollsBackFeePositionAndCostBasis() (gas: 10229670)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.52s (1.43s CPU time)\n\nRan 2 tests for test/invariant/CabalInvariant.t.sol:CabalInvariantTest\n[PASS] invariant_conservationSettlementLifecycleAndLockedPol() (runs: 256, calls: 16384, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| CabalHandler | advance            | 1417  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1506  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1531  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1492  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1383  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1473  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1490  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1496  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1557  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1556  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1483  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 21\n  Bound result 2\n  Bound result 5001\n  Bound result 0\n  Bound result 4\n  Bound result 0\n  Bound result 12\n  Bound result 17165\n  Bound result 999999999999999999620\n  Bound result 0\n  Bound result 7\n  Bound result 606\n  Bound result 650000\n  Bound result 22\n  Bound result 3111\n  Bound result 0\n  Bound result 171\n  Bound result 3000\n  Bound result 0\n  Bound result 3598\n  Bound result 3676\n  Bound result 0\n  Bound result 3202\n  Bound result 1\n  Bound result 999999999999999999833\n  Bound result 18595\n  Bound result 3067\n  Bound result 5\n  Bound result 455\n  Bound result 401\n  Bound result 22\n  Bound result 2262\n  Bound result 18\n  Bound result 232\n  Bound result 3\n  Bound result 3046\n  Bound result 17171\n  Bound result 22\n  Bound result 1275\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16299900)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 10000000000000000000\n  Bound result 10000000000000000000\n  Bound result 3601\n  Bound result 10000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 8.77s (8.75s CPU time)\n\nRan 2 tests for test/invariant/CabalInvariant.t.sol:CabalReverseInvariantTest\n[PASS] invariant_conservationSettlementLifecycleAndLockedPol() (runs: 256, calls: 16384, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| CabalHandler | advance            | 1417  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1506  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1531  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1492  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1383  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1473  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1490  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1496  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1557  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1556  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1483  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 21\n  Bound result 2\n  Bound result 5001\n  Bound result 600\n  Bound result 5\n  Bound result 0\n  Bound result 12\n  Bound result 17970\n  Bound result 999999999999999999620\n  Bound result 0\n  Bound result 2\n  Bound result 3046\n  Bound result 650000\n  Bound result 999999999999999999843\n  Bound result 22\n  Bound result 5587\n  Bound result 0\n  Bound result 171\n  Bound result 3000\n  Bound result 0\n  Bound result 18446744073709551615\n  Bound result 3598\n  Bound result 4718\n  Bound result 4363\n  Bound result 3202\n  Bound result 13\n  Bound result 999999999999999999833\n  Bound result 21235\n  Bound result 5026\n  Bound result 5\n  Bound result 2780\n  Bound result 401\n  Bound result 22\n  Bound result 2195\n  Bound result 24\n  Bound result 232\n  Bound result 3\n  Bound result 2746\n  Bound result 3105\n  Bound result 22\n  Bound result 190\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16342007)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 10000000000000000000\n  Bound result 10000000000000000000\n  Bound result 3601\n  Bound result 10000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 8.85s (8.85s CPU time)\n\nRan 22 test suites in 8.85s (32.03s CPU time): 147 tests passed, 0 failed, 0 skipped (147 total tests)\n","passed":true},{"durationMs":84,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CabalCoin.approve(address,uint256)\",\"CabalCoin.transfer(address,uint256)\",\"CabalCoin.transferFrom(address,address,uint256)\",\"CabalGate.acceptOwnership()\",\"CabalGate.clearRequest(bytes32)\",\"CabalGate.configure((address,address,address,address,bytes32,uint128,uint128,uint16,uint16,uint16,uint16,uint8,uint8))\",\"CabalGate.executeBuyRequest(bytes32)\",\"CabalGate.executeBuyRequest(bytes32,uint256)\",\"CabalGate.executeSellRequest(bytes32)\",\"CabalGate.executeSellRequest(bytes32,uint256)\",\"CabalGate.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"CabalGate.renounceOwnership()\",\"CabalGate.setSlippageLimit(bytes32,uint256)\",\"CabalGate.submitBuyRequest(uint256,string)\",\"CabalGate.submitSellRequest(uint256,string)\",\"CabalGate.transferOwnership(address)\",\"CabalGate.unlockCallback(bytes)\",\"CabalHook.acceptOwnership()\",\"CabalHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CabalHook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"CabalHook.compound(int24,int24)\",\"CabalHook.finishSwap()\",\"CabalHook.renounceOwnership()\",\"CabalHook.setGate(address)\",\"CabalHook.setIMD(address)\",\"CabalHook.transferOwnership(address)\",\"CabalHook.unlockCallback(bytes)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":95,\"README.md\":59,\"docs/DEPLOYMENT.md\":70,\"docs/ORACLE.md\":97,\"docs/SECURITY.md\":29,\"docs/dependencies.json\":26,\"foundry.toml\":20,\"launch.json\":24,\"script/HookSaltMiner.sol\":23,\"src/CabalCoin.sol\":11,\"src/CabalGate.sol\":501,\"src/CabalHook.sol\":257,\"src/HookFlags.sol\":29,\"src/ImpactEstimator.sol\":91,\"src/QuestionBuilder.sol\":124,\"src/interfaces/IIntake.sol\":41,\"src/libraries/CanonicalRequest.sol\":34,\"src/libraries/DataStore.sol\":27,\"src/libraries/Json.sol\":145,\"src/libraries/MainnetDefaults.sol\":11,\"src/libraries/OracleSignature.sol\":42,\"src/libraries/PriceMath.sol\":14,\"test/AdversarialOracle.t.sol\":334,\"test/CabalCoin.t.sol\":62,\"test/CabalFixture.sol\":353,\"test/EconomicProperties.t.sol\":188,\"test/GateLaunch.t.sol\":234,\"test/HookBinding.t.sol\":294,\"test/Launch.t.sol\":137,\"test/Oracle.t.sol\":439,\"test/OracleLatency.t.sol\":44,\"test/OracleLiveVector.t.sol\":81,\"test/OracleSigner.t.sol\":41,\"test/QuestionProperties.t.sol\":264,\"test/README.md\":21,\"test/ReasonEscaping.t.sol\":373,\"test/SubmissionGas.t.sol\":67,\"test/Trading.t.sol\":493,\"test/invariant/CabalHandler.sol\":355,\"test/invariant/CabalInvariant.t.sol\":75,\"test/mocks/MockERC20.sol\":13,\"test/mocks/MockIntake.sol\":93},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"ea764158832ed1c5c3c044acf055dca6bc9c1c568b36bca858dbc8adf303b589","verifiedTreeHash":"fa696ed82239fa619104df10698747d795ee7dd6","verifierVersion":"0.1.0+ad90ce4c"},{"checks":[{"durationMs":155201,"exitCode":0,"name":"build","output":"Compiling 120 files with Solc 0.8.26\nSolc 0.8.26 finished in 154.90s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n   --> test/GateFactoryEdges.t.sol:175:5:\n    |\n175 |     function test_protocolVectorPinsAllFifteenFieldsTypeStringAndDomain() public {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:71:83\n   │\n71 │             if (compressed < minCompressed || compressed > maxCompressed) return (false, 0);\n   │                                                                                   ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n   ╭▸ src/libraries/CanonicalRequest.sol:21:13\n   │\n21 │ ┏             abi.encodePacked(\n22 │ ┃                 '{\"answerType\":\"bool\",\"chainId\":1,\"definitions\":{',\n23 │ ┃                 definitions,\n24 │ ┃                 '},\"evidence\":\"panel\",\"question\":\"',\n   ‡ ┃\n30 │ ┃                 \"}}\"\n31 │ ┃             )\n   │ ┗━━━━━━━━━━━━━┛\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:78:29\n   │\n78 │                     return (true, (compressed - int24(uint24(bitPos - BitMath.mostSignificantBit(masked)))) * spacing);\n   │                             ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:84:29\n   │\n84 │                     return (true, (compressed + int24(uint24(BitMath.leastSignificantBit(masked) - bitPos))) * spacing);\n   │                             ━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[boolean-cst]: misuse of a boolean constant\n   ╭▸ src/ImpactEstimator.sol:89:17\n   │\n89 │         return (false, 0);\n   │                 ━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/boolean-cst\n\nwarning[encode-packed-collision]: `abi.encodePacked()` called with multiple dynamic type arguments; hash collisions possible\n    ╭▸ src/QuestionBuilder.sol:98:16\n    │\n 98 │           body = abi.encodePacked(\n    │ ┏━━━━━━━━━━━━━━━━┛\n 99 │ ┃             '{\"answerType\":\"bool\",\"chainId\":1,\"consumer\":{\"chainId\":1,\"verifyingContract\":\"',\n100 │ ┃             c.verifier.toHexString(),\n101 │ ┃             '\"},\"definitions\":{',\n    ‡ ┃\n112 │ ┃             \"}}\"\n113 │ ┃         );\n    │ ┗━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/encode-packed-collision\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:45:25\n   │\n45 │             liquidity = uint128(uint256(entered));\n   │                         ━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint128' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:45:33\n   │\n45 │             liquidity = uint128(uint256(entered));\n   │                                 ━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:44:31\n   │\n44 │                 if (c < 0x20) revert ForbiddenCharacter();\n   │                               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:56:22\n   │\n56 │                 else revert InvalidUTF8();\n   │                      ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:57:36\n   │\n57 │                 if (src + n > end) revert InvalidUTF8();\n   │                                    ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:59:43\n   │\n59 │                 if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                           ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:59:46\n   │\n59 │         return PriceMath.movement(sqrtPrice, uint160(end));\n   │                                              ━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint160' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:61:64\n   │\n61 │                     if (c == 0xc2 && (d == 0xab || d == 0xbb)) revert ForbiddenCharacter();\n   │                                                                ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:66:23\n   │\n66 │                     ) revert InvalidUTF8();\n   │                       ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:68:47\n   │\n68 │                     if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                               ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:71:51\n   │\n71 │                         if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n   │                                                   ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:72:29\n   │\n72 │             int16 wordPos = int16(compressed >> 8);\n   │                             ━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'int16' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/ImpactEstimator.sol:73:34\n   │\n73 │             uint8 bitPos = uint8(uint256(int256(compressed)) & 0xff);\n   │                                  ━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'uint256' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[uninitialized-local]: local variable is read before being initialized\n   ╭▸ src/libraries/Json.sol:92:16\n   │\n92 │         while (i < s.length) {\n   │                ━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n   ╭▸ src/libraries/Json.sol:99:18\n   │\n99 │             else revert InvalidUTF8();\n   │                  ━━━━━━━━━━━━━━━━━━━━━\n   │\n   ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:100:35\n    │\n100 │             if (i + n > s.length) revert InvalidUTF8();\n    │                                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:103:43\n    │\n103 │                 if (d < 0x80 || d > 0xbf) revert InvalidUTF8();\n    │                                           ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[require-revert-in-loop]: `require` or `revert` inside a loop\n    ╭▸ src/libraries/Json.sol:110:19\n    │\n110 │                 ) revert InvalidUTF8();\n    │                   ━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/require-revert-in-loop\n\nwarning[uninitialized-local]: local variable is read before being initialized\n    ╭▸ src/libraries/Json.sol:127:21\n    │\n127 │                 out[k++] = \"\\\\\";\n    │                     ━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/uninitialized-local\n\nwarning[unsafe-typecast]: typecast can truncate values\n  ╭▸ src/libraries/MainnetDefaults.sol:9:54\n  │\n9 │     address internal constant IDENTITY_NFT = address(bytes20(hex\"0000ec93127baa929e58e97dd0095a2bfb38ec1d\"));\n  │                                                      ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n  │\n  ├ note: consider disabling this lint if you're certain the cast is safe\n  │       \n  │       // casting to 'bytes20' is safe because [explain why]\n  │       // forge-lint: disable-next-line(unsafe-typecast)\n  │       \n  │       \n  ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n   ╭▸ src/libraries/MainnetDefaults.sol:10:40\n   │\n10 │     bytes32 internal constant ACTION = bytes32(\"oracle.request@oracle-1\");\n   │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n   │\n   ├ note: consider disabling this lint if you're certain the cast is safe\n   │       \n   │       // casting to 'bytes32' is safe because [explain why]\n   │       // forge-lint: disable-next-line(unsafe-typecast)\n   │       \n   │       \n   ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-events-access-control]: `_executing` is changed without an event but is used for access control\n    ╭▸ src/CabalGate.sol:421:9\n    │\n421 │         _executing = false;\n    │         ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:225:9\n    │\n225 │         emit Configured(configVersion, cfg);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/CabalGate.sol:210:64\n    │\n210 │     function configure(Config calldata cfg) external onlyOwner nonReentrant {\n    │                                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:219:65\n    │\n219 │                 || cfg.maxSellAmount == 0 || cfg.maxBuyAmount > uint128(type(int128).max)\n    │                                                                 ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:220:40\n    │\n220 │                 || cfg.maxSellAmount > uint128(type(int128).max) || cfg.maxImpactBps == 0 || cfg.maxImpactBps > 5000\n    │                                        ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[reentrancy-no-eth]: external call can be reentered before `activeRequest` is updated\n    ╭▸ src/CabalGate.sol:275:14\n    │\n275 │           id = IIntake(cfg.intake)\n    │ ┏━━━━━━━━━━━━━━┛\n276 │ ┃             .request(cfg.action, body, IIntake.Callback(address(this), this.onOracleResult.selector), cfg.imd, price);\n    │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:294:9\n    │\n294 │         emit RequestSubmitted(id, msg.sender, buy, amount, question, body);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalGate.sol:278:13\n    │\n278 │         if (payment.balanceOf(address(this)) != beforePayment) revert UnsupportedToken();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:284:24\n    │\n284 │             createdAt: uint64(block.timestamp),\n    │                        ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:285:23\n    │\n285 │             deadline: uint64(block.timestamp + REQUEST_TIMEOUT),\n    │                       ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:288:21\n    │\n288 │             amount: uint128(amount),\n    │                     ━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:305:35\n    │\n305 │         if (block.chainid != 1 || block.timestamp >= r.deadline) revert Expired();\n    │                                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:311:74\n    │\n311 │                 || a.agreed > a.panelSize || a.issuedAt < r.createdAt || a.issuedAt > block.timestamp + CLOCK_TOLERANCE\n    │                                                                          ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:312:20\n    │\n312 │                 || a.expiresAt <= block.timestamp || a.expiresAt <= a.issuedAt\n    │                    ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:327:38\n    │\n327 │             r.approvedUntil = uint64(until < a.expiresAt ? until : a.expiresAt);\n    │                                      ━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/CabalHook.sol:113:22\n    │\n113 │     function setGate(address candidate) external onlyOwner {\n    │                      ━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:332:9\n    │\n332 │         emit OracleResult(requestId, a.requestId, approved, r.approvedUntil);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:327:31\n    │\n327 │             r.approvedUntil = uint64(until < a.expiresAt ? until : a.expiresAt);\n    │                               ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:349:33\n    │\n349 │             if (!staleConfig && block.timestamp < r.deadline) revert InvalidRequest();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:351:33\n    │\n351 │             if (!staleConfig && block.timestamp < r.approvedUntil) revert InvalidRequest();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:383:13\n    │\n383 │         if (block.timestamp >= r.approvedUntil) revert Expired();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/block-timestamp\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:413:9\n    │\n413 │         emit RequestExecuted(id, r.amount, output, fee);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:405:44\n    │\n405 │             if (h.units == 0) h.firstBuy = uint64(block.timestamp);\n    │                                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint64' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[missing-zero-check]: address parameter is used in a state write or value transfer without a zero-address check\n    ╭▸ src/CabalHook.sol:126:31\n    │\n126 │     function beforeInitialize(address sender, PoolKey calldata key, uint160) external onlyManager returns (bytes4) {\n    │                               ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-zero-check\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:445:26\n    │\n445 │         uint256 output = uint256(outputDelta);\n    │                          ━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:163:19\n    │\n163 │         feeBase = uint256(amount < 0 ? -amount : amount);\n    │                   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalGate.sol:477:13\n    │\n477 │         if (token.balanceOf(address(this)) != beforeBalance + amount) revert UnsupportedToken();\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:176:16\n    │\n176 │         return (volume / 400) * 2;\n    │                ━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[return-bomb]: external call with a gas limit may copy unbounded return data\n    ╭▸ src/CabalGate.sol:497:13\n    │\n497 │             IDENTITY_NFT.staticcall{gas: 30000}(abi.encodeWithSignature(\"balanceOf(address)\", user));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:235:13\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:249:13\n    │\n249 │             poolManager.take(currency, address(this), uint128(delta));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:252:13\n    │\n252 │             poolManager.sync(currency);\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:254:17\n    │\n254 │             if (poolManager.settle() != owed) revert UnsupportedToken();\n    │                 ━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:183:15\n    │\n183 │         fee = half * 2;\n    │               ━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/CabalHook.sol:179:45\n    │\n179 │     function finishSwap() external onlyGate nonReentrant returns (uint256 fee) {\n    │                                             ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalHook.sol:195:9\n    │\n195 │         emit FeePaid(volume, half, half);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalHook.sol:189:17\n    │\n189 │             if (imd.balanceOf(address(this)) != beforeBalance + fee) revert UnsupportedToken();\n    │                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/incorrect-strict-equality\n\nwarning[reentrancy-no-eth]: external call can be reentered before `_status` is updated\n    ╭▸ src/CabalHook.sol:202:9\n    │\n202 │         poolManager.unlock(abi.encode(lower, upper));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-no-eth\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:202:9\n    │\n202 │         poolManager.unlock(abi.encode(lower, upper));\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalHook.sol:237:9\n    │\n237 │ ┏         emit ProtocolLiquidityAdded(\n238 │ ┃             lower, upper, uint128(liquidity), Currency.unwrap(token0 ? _key.currency0 : _key.currency1), amount\n239 │ ┃         );\n    │ ┗━━━━━━━━━━┛\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:209:33\n    │\n209 │         (BalanceDelta delta,) = poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, 0, 0), \"\");\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[divide-before-multiply]: division before multiplication may lose precision\n    ╭▸ src/CabalHook.sol:221:22\n    │\n221 │         int24 grid = tick / 60 * 60;\n    │                      ━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/divide-before-multiply\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:233:25\n    │\n233 │         if (liquidity > uint256(uint128(type(int128).max))) revert InvalidRange();\n    │                         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:233:33\n    │\n233 │         if (liquidity > uint256(uint128(type(int128).max))) revert InvalidRange();\n    │                                 ━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unused-return]: return value of an external call is not used\n    ╭▸ src/CabalHook.sol:235:13\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/unused-return\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:235:83\n    │\n235 │             poolManager.modifyLiquidity(_key, ModifyLiquidityParams(lower, upper, int256(liquidity), 0), \"\");\n    │                                                                                   ━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:238:27\n    │\n238 │             lower, upper, uint128(liquidity), Currency.unwrap(token0 ? _key.currency0 : _key.currency1), amount\n    │                           ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:249:55\n    │\n249 │             poolManager.take(currency, address(this), uint128(delta));\n    │                                                       ━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint128' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalHook.sol:251:28\n    │\n251 │             uint256 owed = uint256(-int256(delta));\n    │                            ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint256' is safe because [explain why]\n    │       // forge-lint: disable-next-line(unsafe-typecast)\n    │       \n    │       \n    ╰ help: https://getfoundry.sh/forge/linting/unsafe-typecast\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/invariant/GateOnlyRequests.t.sol:108:45\n    │\n108 │         if (r.version == expectedVersion && block.timestamp < expiry) return;\n    │                                             ━━━━━━━━━━━━━━━\n    ‡\n117 │         vm.warp(block.timestamp + bound(secondsSeed, 0, 3601));\n    │         ────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/invariant/GateOnlyRequests.t.sol:86:13\n    │\n 86 │         if (block.timestamp >= r.deadline) return;\n    │             ━━━━━━━━━━━━━━━\n    ‡\n117 │         vm.warp(block.timestamp + bound(secondsSeed, 0, 3601));\n    │         ────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/invariant/GateOnlyRequests.t.sol:247:29\n    │\n117 │         vm.warp(block.timestamp + bound(secondsSeed, 0, 3601));\n    │         ────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    ‡\n247 │         a.issuedAt = uint64(block.timestamp);\n    │                             ━━━━━━━━━━━━━━━\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/invariant/GateOnlyRequests.t.sol:248:30\n    │\n117 │         vm.warp(block.timestamp + bound(secondsSeed, 0, 3601));\n    │         ────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    ‡\n248 │         a.expiresAt = uint64(block.timestamp + 900);\n    │                              ━━━━━━━━━━━━━━━\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/invariant/GateOnlyRequests.t.sol:93:57\n    │\n 93 │             assertEq(gate.getRequest(id).approvedUntil, block.timestamp + 300);\n    │                                                         ━━━━━━━━━━━━━━━\n    ‡\n117 │         vm.warp(block.timestamp + bound(secondsSeed, 0, 3601));\n    │         ────────────────────────────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\nwarning[environment-read-across-mutation]: `block.timestamp` may be reused across `vm.warp`\n    ╭▸ test/invariant/GateOnlyRequests.t.sol:117:17\n    │\n117 │         vm.warp(block.timestamp + bound(secondsSeed, 0, 3601));\n    │         ────────━━━━━━━━━━━━━━━─────────────────────────────── `vm.warp` changes this environment here\n    │\n    ├ help: capture it with `vm.getBlockTimestamp()` instead\n    ╰ help: https://getfoundry.sh/forge/linting/environment-read-across-mutation\n\n","passed":true},{"durationMs":9725,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/Trading.t.sol:ReverseTokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5190176)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 9.38ms (4.41ms CPU time)\n\nRan 2 tests for test/OracleLiveVector.t.sol:OracleLiveVectorTest\n[PASS] test_livePayloadDecodesAndSignatureRecoversToBriefSigner() (gas: 50913)\n[PASS] test_liveQuestionHashIsCanonicalKeccak() (gas: 189084)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 51.65ms (1.07ms CPU time)\n\nRan 1 test for test/OracleSigner.t.sol:OracleSignerTest\n[PASS] test_registrySignatureIsNotAnEOASignatureForTheConfiguredSigner() (gas: 4973110)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 95.83ms (2.43ms CPU time)\n\nRan 1 test for test/Oracle.t.sol:OracleGasTest\n[PASS] test_callbackFitsBelow200kColdTransaction() (gas: 2041545)\nLogs:\n  callback gas including external call: 78063\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 100.64ms (3.52ms CPU time)\n\nRan 5 tests for test/HookBinding.t.sol:HookBindingTest\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5608092)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 592405)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 13503744)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 4759785)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 14839190)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 119.33ms (28.38ms CPU time)\n\nRan 1 test for test/Trading.t.sol:TokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5187043)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 130.19ms (4.19ms CPU time)\n\nRan 2 tests for test/SubmissionGas.t.sol:SubmissionGasTest\n[PASS] test_longestReasonStaysUnderBudget() (gas: 1239827)\n[PASS] test_shortBuyAndSellStayUnderBudget() (gas: 1090419)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 132.64ms (1.49ms CPU time)\n\nRan 3 tests for test/OracleLatency.t.sol:OracleLatencyTest\n[PASS] test_deliveryAtOldExpiryRetainsFullApproval() (gas: 5314564)\n[PASS] test_deliveryJustBeforeOldExpiryRetainsFullApproval() (gas: 5314652)\n[PASS] test_deliveryJustBeforeRequestDeadlineRetainsFullApproval() (gas: 5314718)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 135.82ms (12.59ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64769)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 78629)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9516946)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8020785)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 80854255)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 138.10ms (82.70ms CPU time)\n\nRan 8 tests for test/GateFactoryEdges.t.sol:GateFactoryEdgesTest\n[PASS] testFuzz_flatWordsPreserveValidConfiguration(uint128,uint128,uint16,uint16,uint16,uint16,uint8) (runs: 256, μ: 7904870, ~: 7904851)\nLogs:\n  Bound result 1\n  Bound result 127\n  Bound result 3314\n  Bound result 4037\n  Bound result 93\n  Bound result 92\n  Bound result 8\n\n[PASS] test_constructorRejectsDirtyHighBitsInEveryNarrowWord() (gas: 11697736)\n[PASS] test_constructorRejectsTruncatedStaticArguments() (gas: 12929886)\n[PASS] test_factoryOwnerHandoverRequiresAcceptanceAndPreservesBinding() (gas: 8396637)\n[PASS] test_helpersAreCreatedByEachGateAndExistingDependenciesStayIntact() (gas: 15821522)\n[PASS] test_hookRejectsMissingCodeWrongHookWrongCabalAndDuplicateBinding() (gas: 8013952)\n[PASS] test_pinnedValidNumericEdges() (gas: 15759382)\n[PASS] test_protocolVectorPinsAllFifteenFieldsTypeStringAndDomain() (gas: 15405)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 157.11ms (165.35ms CPU time)\n\nRan 22 tests for test/Oracle.t.sol:OracleTest\n[PASS] testFuzz_attestationFieldsAreBound(uint8) (runs: 256, μ: 4471168, ~: 4466866)\nLogs:\n  Bound result 7\n\n[PASS] test_280UnicodeCharactersAccepted281Rejected() (gas: 7520888)\n[PASS] test_approvalNeverOutlivesAttestation() (gas: 4514522)\n[PASS] test_attestationCannotBeReusedForAnotherRequest() (gas: 7796718)\n[PASS] test_badSignerDomainAndTampering() (gas: 4795409)\n[PASS] test_bodyIsCanonicalJsonWithConsumerAndStoredEscapedQuestion() (gas: 14348105)\n[PASS] test_configuredPanelParametersFlowIntoBodyAndChecks() (gas: 4951241)\n[PASS] test_controlCharactersAndGuillemetsRejected() (gas: 3853513)\n[PASS] test_intakeFailureUnderpaymentDuplicateIdAndReentry() (gas: 7769060)\n[PASS] test_liveFormatDeliveryWithDistinctOracleIdApproves() (gas: 4536271)\n[PASS] test_malformedUTF8Rejected() (gas: 218846)\n[PASS] test_oldPendingUsesSnapshotIntakeSignerAndDomain() (gas: 5784231)\n[PASS] test_onlyIntakeOnlyPendingReplayAndUnknownIds() (gas: 4629131)\n[PASS] test_oracleClockMayRunSlightlyAheadAndValidityMayBeLong() (gas: 4514418)\n[PASS] test_ownerConfigSnapshotsInvalidatesOldExecutionAndCanClear() (gas: 6115673)\n[PASS] test_questionHashMustMatchStoredQuestionAndWindow() (gas: 6918252)\n[PASS] test_quotesInsideReasonCannotCloseTheDelimiter() (gas: 4365557)\n[PASS] test_sellQuestionIncludesHoldingsPriceBasisTimeNftAndReason() (gas: 11299808)\n[PASS] test_submitPaysExactlyQuotedPriceAndRevokesAllowance() (gas: 3463083)\n[PASS] test_timeoutClearsNoLateCallbackNoTradeFundsEscrowed() (gas: 6624575)\n[PASS] test_trueApprovesForFiveMinutesAndFalseRejects() (gas: 7761569)\n[PASS] test_wrongChainAndSizeAndConcurrentRequestRejected() (gas: 3542586)\nSuite result: ok. 22 passed; 0 failed; 0 skipped; finished in 934.99ms (738.85ms CPU time)\n\nRan 20 tests for test/Trading.t.sol:TradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9597350, ~: 9601116)\nLogs:\n  Bound result 564641972005440234615\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 9969589)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 232918)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23703655)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5169603)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10552150)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5198943)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4621615)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5512376)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13091068)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 57084043)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5319672)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5883916)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117029)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10159129)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5315069)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100513)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 327209)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11437751)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.37s (1.44s CPU time)\n\nRan 5 tests for test/Launch.t.sol:ReverseOrderLaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64769)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 79085)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9551491)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8021013)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 193196633)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 1.71s (131.22ms CPU time)\n\nRan 6 tests for test/GateLaunch.t.sol:GateLaunchTest\n[PASS] test_constructorRejectsZeroOwner() (gas: 730734)\n[PASS] test_constructorRequiresHookInitializedAndDependencyCode() (gas: 14947638)\n[PASS] test_existingHookOwnerBindsGateOnceAndRefusesSecondGate() (gas: 15817491)\n[PASS] test_explicitOwnerControlsConfigurationInsteadOfFactory() (gas: 8122802)\n[PASS] test_factoryDeploysOnlyGateWithAllThirteenManifestWords() (gas: 27487936)\n[PASS] test_flatConstructorRetainsEveryConfigurationValidation() (gas: 63231961)\nSuite result: ok. 6 passed; 0 failed; 0 skipped; finished in 1.73s (69.35ms CPU time)\n\nRan 7 tests for test/QuestionProperties.t.sol:QuestionPropertiesTest\n[PASS] testFuzz_jsonRoundTripsUntrustedPrintableAscii(bytes,bool,uint128) (runs: 1000, μ: 5027659, ~: 5510661)\n[PASS] test_emptyReasonIsQuotedAndLeftForPanelJudgment() (gas: 9346155)\n[PASS] test_everyAsciiControlCharacterRefusedQuoteBackslashAndDelSurvive() (gas: 15890019)\n[PASS] test_guillemetsRefusedAnywhereOtherLatin1Accepted() (gas: 9970465)\n[PASS] test_invalidUtf8NeverEntersOracleJson() (gas: 243913)\n[PASS] test_questionNeverExceedsTwoThousandCharactersAtMaximalValues() (gas: 2373470)\n[PASS] test_unicodeScalarLimitsIncludeAllUtf8Widths() (gas: 67874956)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.73s (2.02s CPU time)\n\nRan 20 tests for test/Trading.t.sol:ReverseOrderTradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9631903, ~: 9635689)\nLogs:\n  Bound result 999000000000000005960\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 10003938)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 233390)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23835344)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5203570)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10632542)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5233193)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4621550)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5551392)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13124762)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 15956781)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5327365)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5959729)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117294)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10253921)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5349475)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100508)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 327161)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11541711)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.78s (1.90s CPU time)\n\nRan 5 tests for test/HookBinding.t.sol:ReverseOrderHookBindingTest\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5642382)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 593641)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 24678373)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 15426281)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 26017928)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 1.84s (62.41ms CPU time)\n\nRan 16 tests for test/AdversarialOracle.t.sol:AdversarialOracleTest\n[PASS] testFuzz_malformedSignatureLengthCannotConsumeRequest(uint8) (runs: 1000, μ: 4493313, ~: 4493167)\nLogs:\n  Bound result 48\n\n[PASS] test_attestationIssuedBeforeSubmissionIsRefused() (gas: 4573494)\n[PASS] test_callbackHasNoDependencyOnTokenNftIntakeOrPoolReads() (gas: 4617456)\n[PASS] test_configurationRejectsEveryInvalidBoundaryWithoutAdvancingVersion() (gas: 1831229)\n[PASS] test_everySignedFieldRejectsPostSignatureMutation() (gas: 22113390)\n[PASS] test_explicitVerifierReplacesGateInDomainAndBody() (gas: 4976513)\n[PASS] test_failedOraclePaymentLeavesNoRequestAndCanRetry() (gas: 3855762)\n[PASS] test_identicalReasonFromAnotherUserDoesNotShareAttestation() (gas: 6624945)\n[PASS] test_mainnetDefaultsMatchAssignment() (gas: 24713)\n[PASS] test_rejectedAndClearedIdsCannotReplayOrAlterNewActiveRequest() (gas: 10939614)\n[PASS] test_rejectionReleasesSlotAndResubmissionNeedsFreshDecision() (gas: 7663092)\n[PASS] test_signatureRejectsHighSAndInvalidV() (gas: 4668262)\n[PASS] test_signatureRejectsWrongNameVersionAndDomainChain() (gas: 4845196)\n[PASS] test_timeoutAndApprovalBoundaryAtLastPermittedSecond() (gas: 5204695)\n[PASS] test_zeroOraclePriceAndZeroReturnedIdAreHandledAtomically() (gas: 3777096)\n[PASS] test_zeroVerifierMeansThisGateAndIsStoredResolved() (gas: 3732901)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 1.84s (1.79s CPU time)\n\nRan 7 tests for test/ReasonEscaping.t.sol:ReasonEscapingTest\n[PASS] testFuzz_arbitraryBytesAreJudgedLikeAnIndependentDecoder(bytes) (runs: 1000, μ: 15090, ~: 12778)\n[PASS] testFuzz_oneCorruptedByteIsJudgedLikeAnIndependentDecoder(bytes32,uint16,uint16,uint8) (runs: 1000, μ: 271386, ~: 166659)\nLogs:\n  Bound result 49\n  Bound result 14\n\n[PASS] testFuzz_wellFormedTextOfEveryWidthIsCountedEscapedAndQuotedExactly(bytes32,uint16) (runs: 1000, μ: 2020694, ~: 1808635)\nLogs:\n  Bound result 259\n\n[PASS] test_byteBoundBeforeContentAndScalarBoundAfterIt() (gas: 1479560)\n[PASS] test_escapedQuestionHashesLikeTheParsedBody() (gas: 2977892)\n[PASS] test_quotesAndBackslashesAreEscapedBetweenMultibyteText() (gas: 32360)\n[PASS] test_truncatedLeadByteAtTheEndIsRefusedWhateverFollowsInMemory() (gas: 28243)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.84s (3.73s CPU time)\n\nRan 5 tests for test/CabalCoin.t.sol:CabalCoinTest\n[PASS] testFuzz_transferConservesSupply(uint256) (runs: 256, μ: 82910, ~: 83387)\nLogs:\n  Bound result 1505650390599549081262966\n\n[PASS] test_allowanceAndInsufficientBalances() (gas: 197125)\n[PASS] test_launchSupplyMetadataAndPlainTransfer() (gas: 119450)\n[PASS] test_noAdministrativeMint() (gas: 36108)\n[PASS] test_runtimeNoEscapeHatches() (gas: 625143)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 1.84s (1.84s CPU time)\n\nRan 9 tests for test/EconomicProperties.t.sol:EconomicPropertiesTest\n[PASS] testFuzz_feeCannotExceedHalfPercentAndRoundingIsBounded(uint256) (runs: 1000, μ: 17505, ~: 17678)\n[PASS] testFuzz_priceMovementSymmetricMonotoneAndBounded(uint160,uint160,uint160) (runs: 1000, μ: 51376, ~: 51343)\nLogs:\n  Bound result 17653500772984067447577349288078137279806\n  Bound result 17653500772984067447577349288078137279806\n  Bound result 17653500772984067447577349288078137279807\n\n[PASS] testFuzz_repeatedBuySellCannotCreateImd(uint256,uint8) (runs: 1000, μ: 16413784, ~: 17403300)\nLogs:\n  Bound result 147058289\n  Bound result 3\n\n[PASS] test_feeAndPriceKnownBoundaries() (gas: 58513)\n[PASS] test_insufficientExecutionAllowancePreservesApprovalAndCanRetry() (gas: 5457591)\n[PASS] test_realTradesAtFeeRoundingEdges() (gas: 23272282)\n[PASS] test_sellApprovalSurvivesBalanceDropAndExecutesOnceRestored() (gas: 9860655)\n[PASS] test_sellLargerThanTrackedHoldingsClearsTheRecordWithoutUnderflow() (gas: 9647937)\n[PASS] test_sellSlippageFailureRollsBackFeePositionAndCostBasis() (gas: 10229670)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.84s (1.75s CPU time)\n\nRan 2 tests for test/invariant/GateOnlyRequests.t.sol:GateOnlyRequestsInvariantTest\n[PASS]\nGateOnlyRequestsInvariantTest invariants:\n[PASS] invariant_gatePreservesDonationsAndChargesOnlyTheRequester\n[PASS] invariant_requestStatesSnapshotsAndBindingRemainConsistent\n GateOnlyRequestsInvariantTest invariants (runs: 256, calls: 16384, reverts: 0)\n\n╭------------------------+--------------------+-------+---------+----------╮\n| Contract               | Selector           | Calls | Reverts | Discards |\n+==========================================================================+\n| GateOnlyRequestHandler | advance            | 1666  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | clear              | 1648  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | cycle              | 1640  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | donate             | 1652  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | reconfigure        | 1690  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refuseCallback     | 1605  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refusePayment      | 1566  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refuseUnauthorized | 1667  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | request            | 1652  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | resolve            | 1598  | 0       | 0        |\n╰------------------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 3111\n  Bound result 568\n  Bound result 20\n  Bound result 1\n  Bound result 999999999999999997\n  Bound result 3\n  Bound result 7\n  Bound result 583955733336061635\n  Bound result 17\n  Bound result 8\n  Bound result 2827\n  Bound result 17360\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 21\n  Bound result 237\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 244\n  Bound result 29\n  Bound result 3212\n  Bound result 404542680632324542\n  Bound result 2133832530159402\n  Bound result 127\n  Bound result 2000\n  Bound result 319403294684180178\n  Bound result 12345\n  Bound result 23\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 647115937957744944\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 1\n  Bound result 3571\n  Bound result 999999999999999993\n  Bound result 2324\n  Bound result 692669812530145809\n  Bound result 339934447798733237\n  Bound result 1\n  Bound result 123\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 1184\n\n[PASS] test_handlerExercisesPaymentsFailuresBothAnswersAndClearing() (gas: 18701146)\nLogs:\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 0\n  Bound result 1\n  Bound result 300\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 3600\n  Bound result 1000000000000000000\n  Bound result 1000000000000000000\n  Bound result 24\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 8.44s (8.44s CPU time)\n\nRan 2 tests for test/invariant/CabalInvariant.t.sol:CabalReverseInvariantTest\n[PASS] invariant_conservationSettlementLifecycleAndLockedPol() (runs: 256, calls: 16384, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| CabalHandler | advance            | 1463  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1449  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1497  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1487  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1513  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1528  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1484  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1560  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1436  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1472  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1495  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1000000000000000000000\n  Bound result 2818\n  Bound result 14\n  Bound result 6\n  Bound result 9785\n  Bound result 434\n  Bound result 999999999999999999665\n  Bound result 987402494003717132535\n  Bound result 0\n  Bound result 1000000\n  Bound result 8\n  Bound result 18\n  Bound result 1243\n  Bound result 799\n  Bound result 12\n  Bound result 391\n  Bound result 4\n  Bound result 658\n  Bound result 1\n  Bound result 999999999999999999607\n  Bound result 3165071360\n  Bound result 17866\n  Bound result 2\n  Bound result 26143262\n  Bound result 126975059963090111330\n  Bound result 174789857342557176067\n  Bound result 3025\n  Bound result 301500000000000000000\n  Bound result 2253\n  Bound result 446866953673533866925\n  Bound result 814712357628499459\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16342007)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 10000000000000000000\n  Bound result 10000000000000000000\n  Bound result 3601\n  Bound result 10000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 9.55s (9.56s CPU time)\n\nRan 2 tests for test/invariant/CabalInvariant.t.sol:CabalInvariantTest\n[PASS] invariant_conservationSettlementLifecycleAndLockedPol() (runs: 256, calls: 16384, reverts: 0)\n\n╭--------------+--------------------+-------+---------+----------╮\n| Contract     | Selector           | Calls | Reverts | Discards |\n+================================================================+\n| CabalHandler | advance            | 1463  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1449  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1497  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1487  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1513  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1528  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1484  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1560  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1436  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1472  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1495  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1000000000000000000000\n  Bound result 2818\n  Bound result 750000\n  Bound result 14\n  Bound result 0\n  Bound result 10352\n  Bound result 1078\n  Bound result 401\n  Bound result 999999999999999999625\n  Bound result 0\n  Bound result 1000000\n  Bound result 24\n  Bound result 18\n  Bound result 799\n  Bound result 19\n  Bound result 497\n  Bound result 4\n  Bound result 511\n  Bound result 1\n  Bound result 999999999999999999940\n  Bound result 19300\n  Bound result 2\n  Bound result 26143262\n  Bound result 127949927389340611530\n  Bound result 174789857342557176067\n  Bound result 3025\n  Bound result 736\n  Bound result 11759\n  Bound result 814712357628499459\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16299900)\nLogs:\n  Bound result 100000000000000000000\n  Bound result 10000000000000000000\n  Bound result 10000000000000000000\n  Bound result 3601\n  Bound result 10000000000000000000\n\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 9.59s (9.59s CPU time)\n\nRan 24 test suites in 9.59s (47.13s CPU time): 157 tests passed, 0 failed, 0 skipped (157 total tests)\n","passed":true},{"durationMs":101,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CabalCoin.approve(address,uint256)\",\"CabalCoin.transfer(address,uint256)\",\"CabalCoin.transferFrom(address,address,uint256)\",\"CabalGate.acceptOwnership()\",\"CabalGate.clearRequest(bytes32)\",\"CabalGate.configure((address,address,address,address,bytes32,uint128,uint128,uint16,uint16,uint16,uint16,uint8,uint8))\",\"CabalGate.executeBuyRequest(bytes32)\",\"CabalGate.executeBuyRequest(bytes32,uint256)\",\"CabalGate.executeSellRequest(bytes32)\",\"CabalGate.executeSellRequest(bytes32,uint256)\",\"CabalGate.onOracleResult(bytes32,(bytes32,uint256,bytes32,uint8,bytes,uint256,uint64,uint64,bytes32,bytes32,uint16,uint16,uint16,uint64,uint64),bytes)\",\"CabalGate.renounceOwnership()\",\"CabalGate.setSlippageLimit(bytes32,uint256)\",\"CabalGate.submitBuyRequest(uint256,string)\",\"CabalGate.submitSellRequest(uint256,string)\",\"CabalGate.transferOwnership(address)\",\"CabalGate.unlockCallback(bytes)\",\"CabalHook.acceptOwnership()\",\"CabalHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CabalHook.beforeInitialize(address,(address,address,uint24,int24,address),uint160)\",\"CabalHook.compound(int24,int24)\",\"CabalHook.finishSwap()\",\"CabalHook.renounceOwnership()\",\"CabalHook.setGate(address)\",\"CabalHook.setIMD(address)\",\"CabalHook.transferOwnership(address)\",\"CabalHook.unlockCallback(bytes)\"],\"files\":{\".gitignore\":4,\"ADAPTATION.md\":95,\"README.md\":59,\"docs/DEPLOYMENT.md\":70,\"docs/ORACLE.md\":97,\"docs/SECURITY.md\":29,\"docs/dependencies.json\":26,\"foundry.toml\":20,\"launch.json\":29,\"script/HookSaltMiner.sol\":23,\"src/CabalCoin.sol\":11,\"src/CabalGate.sol\":501,\"src/CabalHook.sol\":257,\"src/HookFlags.sol\":29,\"src/ImpactEstimator.sol\":91,\"src/QuestionBuilder.sol\":124,\"src/interfaces/IIntake.sol\":41,\"src/libraries/CanonicalRequest.sol\":34,\"src/libraries/DataStore.sol\":27,\"src/libraries/Json.sol\":145,\"src/libraries/MainnetDefaults.sol\":11,\"src/libraries/OracleSignature.sol\":42,\"src/libraries/PriceMath.sol\":14,\"test/AdversarialOracle.t.sol\":334,\"test/CabalCoin.t.sol\":62,\"test/CabalFixture.sol\":353,\"test/EconomicProperties.t.sol\":188,\"test/GateFactoryEdges.t.sol\":213,\"test/GateLaunch.t.sol\":236,\"test/GateLaunchChecks.md\":44,\"test/HookBinding.t.sol\":294,\"test/Launch.t.sol\":137,\"test/Oracle.t.sol\":439,\"test/OracleLatency.t.sol\":44,\"test/OracleLiveVector.t.sol\":81,\"test/OracleSigner.t.sol\":41,\"test/QuestionProperties.t.sol\":264,\"test/README.md\":23,\"test/ReasonEscaping.t.sol\":373,\"test/SubmissionGas.t.sol\":67,\"test/Trading.t.sol\":493,\"test/invariant/CabalHandler.sol\":355,\"test/invariant/CabalInvariant.t.sol\":75,\"test/invariant/GateOnlyRequests.t.sol\":400,\"test/mocks/MockERC20.sol\":13,\"test/mocks/MockIntake.sol\":93},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"f27a23e18cf194bb6ad3666a0f3dc36a56146cd37835e788e18de0b29b0d7ed9","verifiedTreeHash":"9b3fe2d15557950f50f5fc2223d987886f5f4c88","verifierVersion":"0.1.0+ad90ce4c"}]}