{"assessments":[],"deployments":[{"attestationHash":"57b31c558afc1b53a2049977b7936622183806c7522e5fb6d5a6facd276c021e","chainId":1,"contracts":[{"address":"0xc61dfe6f2aca035ee09eb2ce7a603ee6d744dd47","blockNumber":26152800,"name":"CabalGate","role":"other","txHash":"0x6ba4ca641a92f211f18b9adf787a8798b48a99f51a68a4ad0bccb5bdc56bc5ee"}],"id":"d91bae23-2fc7-4ef6-aa16-8dd320e49260","manifestHash":"b78925d36220b4064dd6aa49e51968d127e9e34a1b4444d834046e6aed4cf035","status":"live"}],"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":"56a73729-fd7c-445f-a74a-70a9e726513d","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"21ebae92e87c1933b74e6cb96bd0c6bc04d06292751a97177e1e7c1b1a70d49f","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":"d15b5e33b31ff0dc11e287263c2b562170b767d37eb7a89081c1a4feb6832b9e","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":"7ebec5b3f9c0d51bb6771d7f5925380489e630642e1d2769e5414da046123d6b","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":"8913887051c330dd2a2f9cd701148f0418bc55289dfc8ccc5f5553fd0b45fa34","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":"052e0f044f70a13db97daa45625af55db61ba5ea75b14320b909d46703a32bd7","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":"74b68d4a915c5f22ce36bed78289cc697a2d3b019a17c36edb8eaf36ccd01ae3","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":"8352fa2182dad8e6d247ff7fb3e1727c894900a1edece98b2c44b4c1961f3969","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":"cc40001ab6260e632d144bee4222ecccdbf27500f2125106a54bc69f38f6b7e6","dependsOn":["adapt_contract_project"],"execution":{"network":false,"profile":"foundry","requires":[],"tools":[]},"key":"manifest","kind":"code","role":"integrate","skillHash":null,"skillId":null,"state":"accepted"},{"acceptedSubmissionHash":"7cd472130b57295c8cd1fd2531383c00965ff0b6f39392b7397a606f3d2cde7d","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 on Ethereum mainnet (chain id 1), for the live CabalHook 0xf41b6ff942a082c0d320a0c151310ac2a922a0c0 from launch 953. Do not deploy or change CabalHook or CabalCoin.\n\nWHY THE LAST ATTEMPT (launch 990) PARKED: the launch checks deploy the gate in an empty EVM with no chain state. The constructor called the hook (initialized, poolManager, cabal, poolKey, imd) and required intake and imd to have code, so it reverted (\"application constructor failed\"). The constructor must therefore make NO external calls and NO code-length checks.\n\nCONSTRUCTOR, flat arguments in this order: hook, poolManager, cabal, currency0, currency1, fee, tickSpacing, initialOwner, intake, imd, signer, action, maxBuyAmount, maxSellAmount, maxImpactBps, maxDriftBps, panelSize, quorum, windowHours. Store hook, poolManager and cabal as immutables (keep the hook() and cabal() getters: hook.setGate requires gate.hook() == the hook and gate.cabal() == CABAL). Build the PoolKey from currency0, currency1, fee, tickSpacing and hooks = hook. Create QuestionBuilder and ImpactEstimator as now (their constructors only store values). Build the Config inside with oracleVerifier = address(this) and boolAnswerType = 0 and run the same validation, minus anything that reads another contract: check non-zero addresses, currency0 < currency1, cabal is one of the two currencies, imd is the other, and the numeric limits as before.\nkeccak256(abi.encode(hook.poolKey())) == keccak256(abi.encode(stored key)), and hook.gate() == address(this); revert InvalidConfig otherwise. Keep the existing block.chainid == 1 check there. The owner's later reconfiguration may keep its intake/imd code-length checks, since it runs on the live chain.\n\nChange nothing else in the gate: the oracle struct, type string, domain, request flow, fees and limits stay exactly as audited.\n\nManifest constructorArgs: \"0xf41b6ff942a082c0d320a0c151310ac2a922a0c0\", \"0x000000000004444c5dc75cb358380d2e3de08a90\", \"0x450e5910decee15c3ac056e3ed66cb5ea3dd33be\", \"0x450e5910decee15c3ac056e3ed66cb5ea3dd33be\", \"0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7\", \"12500\", \"60\", \"$owner\", \"0x1397434cd35e8a9c8ac312a61d3a285eb31dea56\", \"0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7\", \"0x5598aa9146215bc13eb26f2c692ad1461fd32982\", \"0x6f7261636c652e72657175657374406f7261636c652d31000000000000000000\", \"1000000000000000000000000\", \"10000000000000000000000000\", \"300\", \"500\", \"30\", \"20\", \"1\".\n(These are the live hook's values read on 2026-10-08: poolManager 0x0000…8a90, cabal 0x450e…33be, poolKey (0x450e…33be, 0xd34a…63b7, 12500, 60, hook), imd 0xd34a…63b7, gate unset.)\n\nTESTS: a test that deploys CabalGate with these constructor arguments where NO code exists at the hook, intake, imd or pool manager addresses, and asserts it deploys (this is what the launch checks do). Then, with a mock hook that reports initialized, poolKey, poolManager, imd, cabal and gate like the live one: a request succeeds once the hook's gate is set; a request reverts when any of those reads mismatch (wrong poolKey, wrong cabal, wrong imd, gate unset); setGate accepts the deployed gate and refuses a second one.\n\nAfter launch the hook's owner (0xfc3c…1774, the owner of launch 953's hook) calls hook.setGate(gate) once.\n\nDo not launch any token or Cabal hook again, only CabalGate.","parentJobId":null,"planHash":"8bbc6d0afbc6411cf37ab2cd3f536d697f9e802c451e23ba26ecba0af47048a1","previousHash":"7ac6a6afe24bcdd997dc603501f40fc0bfe3e026428f569a9a81170cfd0a0d44","projectId":"56a73729-fd7c-445f-a74a-70a9e726513d","publication":{"commit":"be82ea665ddb0baa91447cd94243c8ef85dc2fb9","deliveredAt":"2026-10-09T05:33:23.469Z","repoUrl":"https://github.com/identity-md-launches/launch-1128-launch-deploys-only-src-cabalgate-sol"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52129","feedbackHash":"bc35a7a96c44ec5d2dc67073ecb2bcf08249a2206216323edbd495d20cfaf097","nodeKey":"adapt_contract_project","submissionHash":"21ebae92e87c1933b74e6cb96bd0c6bc04d06292751a97177e1e7c1b1a70d49f","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52167","feedbackHash":"6cacc5e79b26582ffa24b029d0ff4fed5c1f226eb87e7fa85473498959343c20","nodeKey":"audit_economics","submissionHash":"b6d59b65bce1cac74a33f1de0b2745a6cd9711017d4eb9bbc6c9c64721d74069","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51214","feedbackHash":"b87c3ac7c4ecddcbd9a14504f46226fbb8d74945fe70a2de1d45d80a9fff474c","nodeKey":"audit_economics","submissionHash":"d15b5e33b31ff0dc11e287263c2b562170b767d37eb7a89081c1a4feb6832b9e","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51229","feedbackHash":"af3a5b13094c0ddd232a66307f13e7ce96d8dc70e216e376ff54505ae95be7fa","nodeKey":"audit_flow","submissionHash":"7ebec5b3f9c0d51bb6771d7f5925380489e630642e1d2769e5414da046123d6b","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52170","feedbackHash":"227bb0369a052ced0a60c54d26717aba118af8225ee03d7d7825633866403876","nodeKey":"audit_flow","submissionHash":"68c76f2877f340ef9bdd5fbf435777178acfffc1887f7f0846fa413ab7d60803","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52157","feedbackHash":"04446fcd8d759d4640dc47773df64be9542601f1c8e1b3cbaf778fee696f6fcd","nodeKey":"audit_judge","submissionHash":"052e0f044f70a13db97daa45625af55db61ba5ea75b14320b909d46703a32bd7","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51509","feedbackHash":"37b5f92f3cf7d9b717f99324d78e1ba86d96dd817df49bd2d3ae7a27c6ffee82","nodeKey":"audit_math","submissionHash":"74b68d4a915c5f22ce36bed78289cc697a2d3b019a17c36edb8eaf36ccd01ae3","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51375","feedbackHash":"c7ccb676c63ac5d6dbfe3a741eb5e613cdc7849e01b41a05f4fbb9935c77a8fb","nodeKey":"audit_math","submissionHash":"6148c06e5342e739536e8d4f3bd23e0754fcfcea43548af576d3c21605a5cae7","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51162","feedbackHash":"8dadf4780a85c3fbbb533c1b524b3050fb7d5cf2bce308531cac4c8d6ebc9f82","nodeKey":"audit_permissions","submissionHash":"d8aa5a46cb819230769407d639cfb503ac3df358048f0526ed01ba22d51353fa","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"52152","feedbackHash":"be722a3eb473731cb0ed4872836e5dbcf649b5f4ee4dd8952b1b1f66d266f2cc","nodeKey":"audit_permissions","submissionHash":"8352fa2182dad8e6d247ff7fb3e1727c894900a1edece98b2c44b4c1961f3969","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51883","feedbackHash":"9e6067340d6b8fddcaec354c61bad072e406703a7dff2d728ac43baff06c9c1a","nodeKey":"manifest","submissionHash":"cc40001ab6260e632d144bee4222ecccdbf27500f2125106a54bc69f38f6b7e6","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"51557","feedbackHash":"a0eb8ab443f29294a5a170d0919264612eb61762ef603d614764d6bb8445c779","nodeKey":"write_foundry_tests","submissionHash":"b12f04a3e5ebac41a14bb3b55fb69d365ba6d987a6d0028cb63d7e2ff4666d0a","tag1":"verification:checks","tag2":"acceptance-v2","value":1},{"agentId":"52214","feedbackHash":"6432c77bf60519cc2a51eeaf6c8b8c15d103f8c5ab19850319ced1fe3d8dddf9","nodeKey":"write_foundry_tests","submissionHash":"7cd472130b57295c8cd1fd2531383c00965ff0b6f39392b7397a606f3d2cde7d","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"8d6a8aa45d60d216b0c9115d83484a680a3a70bc3f7a285606355ba73382e6b0","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"37eed9f56188ea8b","findings":[{"citation":"resolved","description":"Merged from write_foundry_tests (high), audit_permissions (medium), audit_math (info), audit_economics (medium) and audit_flow (medium); one root cause. The brief declares nineteen flat constructor arguments (hook, poolManager, cabal, currency0, currency1, fee, tickSpacing, initialOwner, intake, imd, signer, action, maxBuyAmount, maxSellAmount, maxImpactBps, maxDriftBps, panelSize, quorum, windowHours) and a nineteen-entry manifest list. The compiled constructor (out/CabalGate.sol/CabalGate.json) has fifteen inputs: launchHook, manager, cabalToken, initialOwner, intake, imd, signer, action, maxBuyAmount (uint128), maxSellAmount (uint128), maxImpactBps, maxDriftBps, panelSize, quorum (uint16), windowHours (uint8); fee and tick spacing are the constants POOL_FEE = 12_500 and POOL_TICK_SPACING = 60 and the currencies are sorted at line 163. ADAPTATION.md attributes the cut to an operator instruction that the manifest allows at most sixteen words; that instruction is in no pinned input, so I cannot verify it. What changed since the specialists wrote: the tree now carries launch.json with exactly the fifteen words in ABI order (I compared it to the brief's list minus currency0, currency1, fee and tickSpacing: identical values, $owner in the initialOwner slot), and test/GateLaunch.t.sol deploys those words in an empty EVM through a copy of the protected probe (test_gateDeploysInAnEmptyEvmWithTheManifestWords, test_factoryDeploysOnlyGateWithAllFifteenManifestWords; both pass, runtime 24,522 bytes, no DELEGATECALL/CALLCODE/SELFDESTRUCT in the gate or either helper). So the launch as manifested deploys; recalibrated to low. It stays a finding because the delivered ABI contradicts the brief's explicit constructor and anyone regenerating the manifest from the brief reproduces the launch-990 failure. The requester must either confirm the sixteen-word rule (then the brief's list is the stale document and launch.json is right as it stands) or require the nineteen-word constructor (then the gate must change; note only 54 bytes of EIP-170 headroom remain).","line":139,"path":"src/CabalGate.sol","reproduction":"Both specialist proofs (.imd/reads/proofs/Proof_eb5435165ded.t.sol, Proof_5a5e2cc00462.t.sol) copied under test/scratch and run: both fail with 'application constructor failed' as claimed. Input: vm.chainId(1); creation = type(CabalGate).creationCode ++ abi.encode(0xf41b…a0c0, 0x0000…8a90, 0x450e…33be, 0x450e…33be, 0xd34a…63b7, 12500, 60, owner, 0x1397…ea56, 0xd34a…63b7, 0x5598…2982, 0x6f72…0000, 1e24, 1e25, 300, 500, 30, 20, 1) (19 words); CREATE2 through a probe with the protected floor's checks. Expected per the brief: a gate with owner()==owner and configuration().intake==0x1397…ea56. Actual: revert 'application constructor failed' (word 8, the Intake address, does not fit uint128 maxBuyAmount; the ABI decoder reverts). Control: the fifteen words of launch.json behind the same creation code deploy in an empty EVM (forge test --match-path test/GateLaunch.t.sol: 11 passed).","severity":"low","snippet":"    constructor(","title":"Constructor takes 15 words while the brief fixes 19; the tree's launch.json follows the 15-word ABI and deploys, so the brief and the delivered ABI must be reconciled by the requester"},{"citation":"resolved","description":"From audit_math (low); reproduced. estimate() prices the whole exact-input swap against poolManager.getLiquidity() at the current price (line 36) with the single-range formula at lines 48-57. A v4 swap that leaves that range continues against whatever is initialised beyond it, so when a deep narrow range sits at the current tick and the surrounding liquidity is shallow the estimate is a fraction of the real movement. The submission check at src/CabalGate.sol:255-256 compares the estimate with maxImpactBps, so the request is accepted, the submitter pays priceOf (0.5 IMD live) and the question sent to the panel states the wrong 'estimated price impact bps'; the panel approves; executeBuyRequest then reverts LimitExceeded at src/CabalGate.sol:453 because the measured movement exceeds the cap. The approval can only be cleared after approvedUntil, and resubmitting costs the oracle price again. The shape arises on the live pool by itself: CabalHook._addSingleSided places protocol liquidity in 600-tick bands beside the current tick, and anyone may add a one-spacing position since the hook has no liquidity permissions. The limitation is acknowledged in QuestionBuilder.DEFINITIONS, and the execution-time cap holds, so only the non-refundable oracle price is lost: low. A fix that keeps the design: walk initialised ticks in the swap direction (bounded) or refuse the submission when the estimated end price leaves the active range, so an under-estimate can never pass the cap. Any change to the gate must fit in the 54 bytes of EIP-170 headroom; the estimator is a separate contract and has room.","line":48,"path":"src/ImpactEstimator.sol","reproduction":"Scratch test on test/CabalFixture.sol (IMD currency0, price at tick 0, seed 1e25 liquidity in [-1200,1200]), owner configures live limits maxBuyAmount 1e24, maxImpactBps 300, maxDriftBps 500; anyone adds 1e26 liquidity in [-60,60]. gate.estimateImpact(true, 6.4e23) returns 114 (<= 300). ALICE submitBuyRequest(6.4e23, reason) succeeds and ALICE's IMD falls by intake.price(). Deliver a signed true attestation, setSlippageLimit(id, 1). ALICE executeBuyRequest(id) with the pool untouched since submission: reverts LimitExceeded. With the cap raised to 5000 the same buy moves the price 632 bps (measured with gate.priceMovement before/after). Expected: a request whose real impact exceeds maxImpactBps is refused before payment, or the panel sees the real figure. Actual: paid, approved on 114 bps, never executable.","severity":"low","snippet":"        uint256 net = FullMath.mulDiv(amount, 1_000_000 - _key.fee, 1_000_000);","title":"Impact estimate models only the active liquidity range, so a trade that crosses a liquidity step is accepted and paid for at submission, approved on a wrong figure, and then refused by the execution c"},{"citation":"resolved","description":"Merged from audit_permissions (info) and audit_flow (low); reproduced with the real CabalHook and PoolManager. By mandate the constructor reads nothing, so the stored key is shaped by the hook, cabal and imd words alone and is kept only as the private immutable _keyHash; the gate exposes no poolKey() or keyHash() view. The live hook's setGate (src/CabalHook.sol:113-118, out of scope for change) checks only gate.hook() and gate.cabal() and binds permanently. The imd word is therefore the one key-shaping input that no on-chain check covers: a gate whose imd differs from hook.imd() binds, every submitBuyRequest/submitSellRequest reverts InvalidConfig at the key-hash and hook.imd() checks, the owner cannot repair it (configure requires cfg.imd == hook.imd() but _key is immutable), and the hook refuses every later gate. The only guard is the procedure in docs/DEPLOYMENT.md asking the hook owner to recompute the key off-chain. Mitigating facts: launch.json's imd word 0xd34a…63b7 equals the brief's live hook.imd() and the oracle reference's mainnet IMD, and the hook owner's check is a documented step; so this is a reachable permanent-breakage state behind one transcription error, not a defect in the manifest as written. Low. A minimal fix that keeps the design: a view returning the derived PoolKey (or _keyHash) so the owner's pre-binding comparison can be made against the chain and scripted; it must fit in the remaining 54 bytes of runtime or be paid for elsewhere.","line":163,"path":"src/CabalGate.sol","reproduction":"Scratch test: real PoolManager and a second real CabalHook (owner H) with a CABAL/IMD pool initialised (fee 12500, spacing 60). Deploy gate W with the fifteen words but imd = 0x5F7Bb59365ce557C26dbcAa4EE9d39A4b95B7127 (the Robinhood-chain IMD, not hook.imd()); deploy gate R with the correct imd. H calls hook.setGate(W): succeeds, hook.gate()==W. ALICE calls W.submitBuyRequest(100e18, 'Pay October hosting'): reverts InvalidConfig. W's owner calls configure with imd = hook.imd(): accepted; ALICE's submit still reverts InvalidConfig. H calls hook.setGate(R): reverts InvalidGate. Expected: a mis-built gate is detectable or refused before the permanent binding. Actual: bound, unusable, unreplaceable.","severity":"low","snippet":"        (address currency0, address currency1) = cabalToken < imd ? (cabalToken, imd) : (imd, cabalToken);","title":"A gate built with a wrong imd word is accepted by the live hook's one-time setGate and can never submit; nothing on-chain lets the hook owner compare the gate's derived pool key before the irreversibl"},{"citation":"resolved","description":"From audit_math (info); reproduced. The only lower bound is amount > 0. For a 1 wei buy the estimator's net input truncates to 0 so estimateImpact returns 0 and the submission succeeds, charging the oracle price. At execution the v4 exact-input swap consumes the wei as fee and yields zero output; unlockCallback reverts PartialFill (outputDelta <= 0) and the approval is unusable. Self-inflicted and bounded by the oracle price; informational. A minimum amount per request (for example at least 400 wei so the hook fee is non-zero too) or a UI floor closes it.","line":250,"path":"src/CabalGate.sol","reproduction":"Fixture defaults: gate.estimateImpact(true, 1) == 0. ALICE submitBuyRequest(1, reason) succeeds and ALICE's IMD falls by intake.price(). Deliver an approving attestation, setSlippageLimit(id, 1). ALICE executeBuyRequest(id): reverts PartialFill. Expected: a request that cannot produce output is refused before the oracle is paid. Actual: paid, approved, never executable.","severity":"info","snippet":"        if (amount == 0 || amount > maxAmount) revert LimitExceeded();","title":"A buy too small to produce any output passes the amount and impact checks, is paid for, approved, and can never execute (PartialFill)"},{"citation":"resolved","description":"Merged from audit_permissions's two info findings; documented in docs/DEPLOYMENT.md, recorded as the permission model's trust points, not as bypasses. (a) _execute requires r.version == configVersion while onOracleResult verifies against the request's snapshot, so any configure() makes every pending or approved request unexecutable; the 0.5 IMD already paid is spent and the only exit is clearRequest. (b) configure() binds imd to hook.imd() but intake, signer, action and oracleVerifier are free: an owner-chosen Intake can quote any priceOf, which _submit pulls with no user-supplied cap (bounded by the submitter's allowance and balance), and an owner-chosen signer approves the owner's own trades without a panel, within the amount/impact/drift limits that remain enforced. (c) _configure does not constrain boolAnswerType; a non-zero value makes every attestation fail `a.answerType != cfg.boolAnswerType`, so each request under that config costs 0.5 IMD and is never answered. (d) renounceOwnership is inherited and would freeze configuration permanently. Gate custody is per-transaction, so no idle funds are at risk.","line":210,"path":"src/CabalGate.sol","reproduction":"(a) test/Oracle.t.sol test_ownerConfigSnapshotsInvalidatesOldExecutionAndCanClear (passes): ALICE submits and is approved; owner configure(windowHours=2); ALICE executeBuyRequest -> InvalidRequest; clearRequest succeeds; ALICE is down intake.price() with no trade. (b) Owner configure(cfg with intake = a contract whose priceOf returns 1000e18); BOB, who approved type(uint256).max as the fixtures do, calls submitBuyRequest(1e18, 'r'): _pullExact pulls 1000 IMD. Expected: submitter pays the published 0.5 IMD; actual: whatever the owner's Intake quotes. (c) Owner configure(cfg with boolAnswerType = 3); ALICE submits; a correctly signed bool attestation (answerType 0) is delivered: InvalidAttestation.","severity":"info","snippet":"        if (cfg.intake.code.length == 0 || cfg.imd != address(hook.imd()) || cfg.imd.code.length == 0) {","title":"Owner trust assumptions: configure() strands every in-flight request without refund, and the owner can replace intake, signer, action, oracleVerifier and boolAnswerType"},{"citation":"resolved","description":"From audit_economics (info); reproduced by the existing test. Price moves only through gate executions, each bounded to maxImpactBps of its own movement, so two approved buys from two addresses executed before a victim's execution can exceed maxDriftBps = 500 bps from the victim's submission price; the victim's execute reverts LimitExceeded for the rest of the five-minute window and must clear after approvedUntil and pay the oracle price again. Attacker cost: two oracle fees, 1.25% LP fee plus 0.5% hook fee on the volume, exposure to the moved price, and panel approval of their reasons. The owner can tighten maxDriftBps through configure if observed. No code change recommended.","line":400,"path":"src/CabalGate.sol","reproduction":"test/Trading.t.sol test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap (passes in the suite): BOB submits a 1000 IMD buy and is approved; CAROL executes two approved 140,000 IMD buys; priceMovement(request.sqrtPriceX96, current) > maxDriftBps; BOB's executeBuyRequest reverts LimitExceeded although unexpired; BOB must wait for approvedUntil, clearRequest and resubmit paying intake.price() again.","severity":"info","snippet":"        if (priceMovement(r.sqrtPriceX96, current) > cfg.maxDriftBps) revert LimitExceeded();","title":"Approved trades by other users can move the price past maxDriftBps and strand a victim's approval until it expires (documented trade-off, cost one oracle price)"},{"citation":"resolved","description":"From audit_math (info). feeFor floors volume/400 and doubles it, so the 0.5% fee is under-collected by at most 2 wei per trade and is zero below 400 wei. The gate uses hook.feeFor at src/CabalGate.sol:404 and 456 and checks finishSwap's return against it, so gate and hook agree and nothing desynchronises. Protocol dust that cannot be farmed, since every trade costs a 0.5 IMD oracle request. Recorded for completeness; CabalHook is out of scope for change.","line":176,"path":"src/CabalHook.sol","reproduction":"hook.feeFor(399) == 0 (0.5% of 399 is 1.995); hook.feeFor(799) == 2 (0.5% of 799 is 3.995). A 399 wei buy through the gate burns and allocates nothing (test/EconomicProperties.t.sol pins the rounding).","severity":"info","snippet":"        return (volume / 400) * 2;","title":"Live hook fee rounds down per leg: volumes under 400 wei pay no fee and each trade under-collects up to 2 wei (hook is live and unchangeable; the gate mirrors the same formula)"}],"hash":"052e0f044f70a13db97daa45625af55db61ba5ea75b14320b909d46703a32bd7","nodeId":"591351c9-b883-42d9-9f44-b4fbf8e9908f","outcome":"completed","summary":"The review is complete. The findings are in `.imd-findings.json` at the repository root, no source file was changed, and the scratch tests were removed.\n\n**Outcome.** No critical, high or medium defect survived reproduction. The gate deploys in an empty EVM with the manifest's words, the whole suite passes, and the oracle wiring matches the live service.\n\n| Check | Result |\n| --- | --- |\n| forge test | 179 passed, 0 failed |\n| CabalGate runtime | 24,522 bytes, no forbidden opcodes |\n| launch.json | 15 words, equal to the brief's values minus the four derived ones |\n\n**Findings kept, after merging and recalibration:**\n\n1. **Low, constructor ABI.** Five specialists reported the same root cause: the brief fixes 19 constructor words and the code takes 15. Both specialist proofs fail as claimed when the brief's 19 words are encoded. It is low rather than medium because the tree now carries a launch.json in the 15-word ABI order, and that manifest deploys through a copy of the protected probe. The requester must still settle which document is right, since the sixteen-word operator rule is in no pinned input.\n2. **Low, impact estimate.** The single-range estimator under-reports a trade that crosses a liquidity step. Reproduced on the fixture: estimate 114 bps, real movement 632 bps, so the request is paid for and approved, then execution reverts on the cap.\n3. **Low, wrong IMD word.** A gate built with a wrong imd word passes the live hook's setGate and can never submit, and the binding is permanent. Reproduced against the real hook. The manifest's imd word is correct, so the risk is procedural.\n4. **Info, four items.** A dust buy that is paid for and never executable, the owner's documented powers including the unconstrained boolAnswerType, the drift-cap stranding trade-off, and the live hook's fee rounding.\n\n**Coverage.** All 28 entry points have a row, plus three invariant rows for the empty-EVM constructor, the oracle format against the live vector, and the manifest schema. One item could not be verified offline and is noted in the coverage row: the shape of the body's `consumer` key, which rests on the tree's own live-evidence documentation.\n\nNo proofs are attached because nothing reached high severity. Any fix to findings 2 or 3 that touches the gate must fit in its 54 bytes of remaining EIP-170 headroom.","treeHash":null,"usage":{"cachedInputTokens":1858562,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":41958,"runtime":"claude","turns":32,"wallClockMs":992036}},{"artifacts":[],"attempt":1,"bundleHash":"4e7aced39b2a0ec1ae9f7043656136f62615ced33924fdf717e92a983fba1356","device":"63c29c49a249ab7e","findings":[],"hash":"21ebae92e87c1933b74e6cb96bd0c6bc04d06292751a97177e1e7c1b1a70d49f","nodeId":"14e85cbb-2386-4e83-b3e4-1251524e603c","outcome":"completed","summary":"The work is complete and verified. Nothing more is needed from the tree.\n\n**Outcome.** The CabalGate constructor now takes the 15 flat words the operator asked for, in the order hook, poolManager, cabal, initialOwner, intake, imd, signer, action, maxBuyAmount, maxSellAmount, maxImpactBps, maxDriftBps, panelSize, quorum, windowHours. The compiled ABI confirms 15 nonpayable static inputs. The build and the full test suite pass with the project's own configuration.\n\n| Check | Result |\n| --- | --- |\n| forge build | passed, cold build about 4.5 minutes, 4.3 GB peak |\n| forge test | 167 passed, 0 failed, 0 skipped, 25 suites |\n| gate runtime | 24,522 bytes, 54 under EIP-170 |\n| gate init code plus 15 words | 37,699 bytes, under 49,152 |\n\n**What changed in the contract** (`src/CabalGate.sol`):\n- The pool fee and tick spacing are now the constants `POOL_FEE` (12500) and `POOL_TICK_SPACING` (60), matching the only pool CabalHook accepts.\n- The constructor sorts cabal and imd by address into currency0 and currency1 and builds the PoolKey from them with hooks set to the hook.\n- Validation that needed the removed words is gone. The constructor now rejects a zero hook, pool manager, cabal or imd, and cabal equal to imd. The numeric limits are unchanged.\n- The constructor still makes no external calls and no code-length checks. The request path is byte-for-byte as accepted: chain id 1, the poolKey hash, hook.gate, hook.cabal and hook.imd, all before any payment.\n\n**Tests updated** to the 15 words in `test/GateLaunch.t.sol`, `test/GateFactoryEdges.t.sol` and `test/CabalFixture.sol`, including the empty-EVM deployment with no code at the hook, intake, IMD or pool manager. One new test deploys a gate for a CABAL whose address sorts above IMD and shows the derived key matches the hook's, a request passes once bound, and a hook reporting the unsorted order is refused. The fixture's two token orderings already run the real hook and PoolManager through both sort directions.\n\n**Documentation** in ADAPTATION.md, README.md, docs/DEPLOYMENT.md and the test READMEs now describes the fifteen-word constructor and the manifest's sixteen-argument limit. No launch.json or blocked file exists in the tree.\n\n**One note for the reviewer.** The operator's instruction describes the request path as checking hook.initialized and poolManager. The accepted code never read those two in the submission path, and I did not add reads there, since the instruction also says to keep the rest exactly as accepted and the runtime has only 54 bytes of headroom. ADAPTATION.md explains why those facts are implied by the existing hook.gate and poolKey checks.","treeHash":"e58c2007cd99c6516a636835b7e57e48f45d0101","usage":{"cachedInputTokens":1630358,"inputTokens":546,"model":"claude-fable-5-1","outputTokens":33712,"runtime":"claude","turns":49,"wallClockMs":994898}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"93c37f17670e4d98","findings":[{"citation":"resolved","description":"Boundary x invariant seam (Numerical Gap guide). `estimate` reads the liquidity active at the current price (line 36) and applies the single-range formula at line 52 as if that liquidity extended without limit in the swap direction. It never checks where the active range ends. `_submit` (src/CabalGate.sol:256-257) trusts the number: a request is accepted, the 0.5 IMD oracle price is pulled and spent, and the panel is told `estimated price impact bps=N`. At execution the real v4 swap leaves the range at its first step when the current tick is the range's lower bound (a sell, zeroForOne) and finds nothing below, so the swap consumes zero input, the gate reverts `PartialFill` (src/CabalGate.sol:451), and the approval can only be cleared after `approvedUntil`. The non-refundable oracle price and gas are lost for every such request, and the panel approves on a wrong impact figure. This is exactly the state a CABAL-only launch starts in and stays in until the first buy moves the price inside the range (on mainnet CABAL 0x450e... is currency0, so a token-only seed sits at the lower edge of its range): early sellers (holders from the launch allocation) are charged for requests that cannot execute. It persists after the first buy: with the price still in tick -1200 after a 100 IMD buy, a 1000 CABAL sell is estimated at 2 bps, approved, and reverts `PartialFill` because the seed remainder plus the 0.25 IMD protocol position below absorb far less than the trade. The comment in the file calls this 'the path a v4 swap takes'; at the range edge it is not. Minimal fix: in `estimate`, find the next initialised tick in the swap direction (the existing `_nextInitializedTick` helper, using `tick` for input0 and lte=true excluding the current tick when its sqrt price equals the current price, or simply the range boundary) and, when the computed `end` passes that tick's sqrt price, either continue the walk through the next range's liquidity (liquidityNet) or return 10000 so `_submit` refuses the request before charging the oracle. Returning 10000 at the boundary is conservative and preserves the agreed design (the panel is never asked about a trade the pool cannot fill).","line":52,"path":"src/ImpactEstimator.sol","reproduction":"State: PoolManager, CabalCoin (currency0) and an 18-decimal IMD (currency1), CabalHook bound to the pool with fee 12500 / spacing 60, pool initialised at sqrtPrice(tick -1200) and seeded with a CABAL-only position [-1200, 1200] of liquidity 1e25 (the TokenOnlySeed fixture with CABAL as currency0). Gate deployed with the manifest numbers (maxImpactBps 300, maxDriftBps 500), hook.setGate(gate). Alice holds 1000 CABAL and 1e6 IMD, both approved to the gate.\n1. gate.estimateImpact(false, 100e18) returns 1 (bps).\n2. Alice: gate.submitSellRequest(100e18, reason) succeeds; her IMD balance drops by the intake price (0.5 IMD live). Request status Pending.\n3. Intake delivers a signed `true` attestation; status Approved, approvedUntil = now+300.\n4. Alice: setSlippageLimit(id, 1); executeSellRequest(id) reverts PartialFill() (selector 0xd964f528): the swap crosses tick -1200 immediately, liquidity becomes 0, the price runs to the limit with zero input consumed, so inputDelta != -amount.\nExpected: a trade the pool cannot fill is refused at submission (LimitExceeded) before the oracle is paid, or the approved trade executes. Actual: the oracle price is spent and the approval is dead.\nSecond state (test/scratch probe on the same fixture): after Alice buys with 100 IMD (tick stays -1200), estimateImpact(false, 1000e18) = 2; submit/approve succeed; executeSellRequest reverts PartialFill(). The attached proof fails on the current code with PartialFill and passes once estimate() refuses (returns > maxImpactBps) a trade whose path leaves the active range into empty liquidity.","severity":"medium","snippet":"            end = FullMath.mulDiv(liquidity, start, uint256(liquidity) + FullMath.mulDiv(net, start, Q96));","title":"Impact estimate treats the active liquidity range as unbounded: sells at the lower edge of the CABAL-only seed are accepted, paid for and approved but can never execute"},{"citation":"resolved","description":"Same root cause as finding 1 seen from the other side (boundary x precision). When `liquidity` at line 36 is non-zero the estimator never looks past the active range, so a position of liquidity 1 that spans the current tick makes `end` overflow the sqrt-price bounds (lines 53/57) and the function returns the 10000 sentinel for any amount above a few wei, even though the real swap would leave that dust range within one tick and continue into the protocol-owned positions the gap branch (lines 38-47) would otherwise have found. `_submit` then reverts LimitExceeded for every buy and sell. Anyone can open such a position permissionlessly (the hook has no liquidity hooks); it costs dust and stays in place. Precondition: no other liquidity is active at the current tick, i.e. the price sits in a gap between ranges (for example after the seed position has been withdrawn, or before a protocol position adjacent to the tick exists). While the seed is active the dust is harmless because it adds to a large L. Fix: the same multi-range walk as finding 1 (continue through the next initialised tick when the active range is exhausted), or treat active liquidity below a minimum as absent and fall into the gap branch.","line":36,"path":"src/ImpactEstimator.sol","reproduction":"Fixture: CabalFixture default pool (IMD currency0, seed [-1200,1200] 1e25). 1. Alice buys with 100 IMD (creates the protocol IMD position beside the tick). 2. The seed LP removes its position: getLiquidity(poolId) == 0. 3. gate.estimateImpact(false, received/2000) == 115 (the gap branch follows the swap into the protocol position; submission would be accepted, as test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen shows). 4. Any account adds liquidity 1 over [minUsableTick(60), maxUsableTick(60)]: getLiquidity == 1. 5. gate.estimateImpact(false, received/2000) == 10000 and estimateImpact(true, 1 ether) == 10000, so submitSellRequest / submitBuyRequest revert LimitExceeded for every amount. Expected: the estimate follows the swap through the 1-wei range into the protocol position (about 115 bps) as it did without the dust. Actual: every submission is refused until a larger position becomes active at the tick. Reproduced in test/scratch/MathProbe.t.sol test_probe_dustPositionBlocksEstimates (logs: 'estimate without dust: 115', 'estimate with 1-wei dust: 10000').","severity":"low","snippet":"        uint128 liquidity = poolManager.getLiquidity(poolId);","title":"A 1-wei full-range position blocks every submission while no other liquidity is active at the current tick (estimate returns 10000)"}],"hash":"6148c06e5342e739536e8d4f3bd23e0754fcfcea43548af576d3c21605a5cae7","nodeId":"00c41a30-650c-49ce-8400-4d3ce99dce74","outcome":"completed","summary":"The review is complete. The findings file is written and validated, and no repository files were changed (scratch tests live only under the ignored test/scratch/ directory).\n\n**Outcome**\n\nTwo defects, both in the price-impact estimator, both reproduced with Foundry tests:\n\n- **Medium, src/ImpactEstimator.sol:52.** The estimate applies the single-range formula to the liquidity active at the current price as if that range were unbounded in the swap direction. When the price sits at the lower edge of a CABAL-only seed (the state a token-only launch starts in, with CABAL as currency0 as on mainnet), a sell of 100 CABAL is estimated at 1 bps, accepted, charged the oracle price, and approved. Execution then reverts with PartialFill because the v4 swap leaves the range at its first step and finds no liquidity below. The same happens after a first 100 IMD buy for a 1000 CABAL sell estimated at 2 bps. Users lose the non-refundable oracle price and the panel approves on a wrong impact figure. The attached self-contained proof test fails on the current code with PartialFill and passes once the estimator refuses a trade whose path exits the active range into empty liquidity.\n- **Low, src/ImpactEstimator.sol:36.** The mirror case. While no other liquidity is active at the current tick, a permissionless 1-wei full-range position makes the estimate return 10000 for every amount, so every buy and sell submission reverts with LimitExceeded. Without the dust the gap branch would have followed the swap into the protocol position and returned about 115 bps.\n\n**What held**\n\nI traced the remaining arithmetic against the Math Precision, Boundary and Numerical Gap checklists and found it sound: the symmetric movement formula and its one-bps round-up, the fee legs and their zero-fee path, the exact match between the gate's fee and the hook's fee base, the holdings and cost-basis reductions, the uint128 and int24 narrowing casts, the tick-bitmap walk for negative ticks, the attestation time-window boundaries, the question-length bound, and the spot-price chained divisions (relative error below 1e-20). Coverage rows answer all 28 listed entry points plus six invariant rows.\n\n**Not reached**\n\nThe estimate-at-exact-cap versus execution rounding check could not be exercised in the fixture because the configured buy cap keeps the estimate at 20 bps. Slither and Mythril were not run; the static-analysis leads about division-before-multiplication and strict equalities were checked by hand and are not defects.","treeHash":null,"usage":{"cachedInputTokens":7257232,"inputTokens":1130,"model":"claude-fable-5-1","outputTokens":79992,"runtime":"claude","turns":76,"wallClockMs":3047324}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"fa99051b60a858d6","findings":[{"citation":"resolved","description":"The flat constructor cannot read the live hook, so the pool words are the only description of the pool it will ever get. It validates tickSpacing (1..2^23-1), currency order and the token roles, but accepts any uint24 `fee`, including values above the v4 maximum of 1_000_000 and the dynamic-fee flag 0x800000, which the live hook's pool (fee 12500) can never match. The live CabalHook.setGate (src/CabalHook.sol:113-121, unchangeable) compares only gate.hook() and gate.cabal(), never the key, and the binding is permanent. So one wrong word in the manifest produces a gate that (a) passes the empty-EVM launch checks, (b) is accepted by the hook owner's setGate, (c) refuses every submission forever with InvalidConfig because keccak256(hook.poolKey()) != _keyHash, and (d) blocks any later, correct gate from ever being bound. For fee > 1_000_000 the public view estimateImpact also reverts with an arithmetic underflow in ImpactEstimator (`1_000_000 - _key.fee`). The brief's manifest value (12500) is correct, and docs/DEPLOYMENT.md asks the hook owner to recompute the key hash before binding; this finding is the cheap on-chain backstop that the constructor can add without any external call: revert InvalidConfig when fee > 1_000_000 (LPFeeLibrary.MAX_LP_FEE) or the dynamic-fee bit is set, and, since the live pool is fixed, optionally pin fee == 12500 and tickSpacing == 60 the same way CabalHook.beforeInitialize does. Minimal fix: add `|| fee > 1_000_000` (or `|| fee != 12_500 || tickSpacing != 60`) to the revert condition at src/CabalGate.sol:155-161.","line":160,"path":"src/CabalGate.sol","reproduction":"Chain id 1, no code at the hook. Deploy CabalGate with the manifest's nineteen words except fee = 1000001 (or 8388608, the dynamic-fee flag). Expected: constructor reverts InvalidConfig like it does for tickSpacing = 0. Actual: deployment succeeds, gate.hook() and gate.cabal() return the hook and CABAL. Then, with a hook at the live address that reports initialized, cabal = 0x450e…33be, imd = 0xd34a…63b7, poolKey = (CABAL, IMD, 12500, 60, hook), gate = 0 (what the live hook reports): hook owner calls hook.setGate(wrongGate) -> succeeds, hook.gate() == wrongGate; hook.setGate(correctGate) -> reverts InvalidGate (gate already set); wrongGate.submitBuyRequest(1e18, \"x\") -> reverts InvalidConfig; correctGate.submitBuyRequest -> reverts InvalidConfig (hook.gate() != correctGate); wrongGate.estimateImpact(true, 1e18) -> reverts with panic 0x11. Verified with test/scratch/FeeWord.t.sol (FeeWordTest.test_wrongFeeWordDeploysBindsPermanentlyAndNeverSubmits passes on the current tree, i.e. the sequence above executes exactly so).","severity":"low","snippet":"                || tickSpacing > uint24(type(int24).max)","title":"Constructor bounds tickSpacing but not fee: a gate built with an impossible fee word deploys, is bindable by the live hook's one-time setGate, and can never submit"},{"citation":"resolved","description":"The brief states: 'Change nothing else in the gate: the oracle struct, type string, domain, request flow, fees and limits stay exactly as audited.' Two things changed beyond the constructor and the submission-time hook checks: `_configure` now requires 2 <= quorum <= panelSize <= 300 (previously 1 <= quorum <= panelSize <= 1000, per ADAPTATION.md), and the external `mainnetConfig(...)` view was removed to recover runtime bytes (runtime is now 24,443 bytes, 133 under EIP-170). Both are documented in ADAPTATION.md as dispositions of imported audit findings 7640e8a5 and 72c9545e, and both are improvements (the oracle refuses panels outside 2..300 and would burn the 0.5 IMD), so no code fix is proposed; this is recorded so the judge and requester can accept the deviation explicitly rather than discover it. The launch values (panelSize 30, quorum 20) are inside both bounds.","line":224,"path":"src/CabalGate.sol","reproduction":"Owner calls gate.configure(cfg) with cfg equal to the current configuration except quorum = 1 (or panelSize = 301, quorum = 300). Audited gate: accepted, configVersion increments. Current gate: reverts InvalidConfig, configVersion unchanged (test/GateLaunch.t.sol test_ownerConfigureKeepsLiveDependencyChecksAndOracleBounds pins this). Calling the previously-existing selector mainnetConfig(...) on the current gate: reverts (no such function).","severity":"info","snippet":"                || cfg.maxDriftBps < cfg.maxImpactBps || cfg.maxDriftBps > 5000 || cfg.quorum < 2","title":"Scope deviation from the brief: panel/quorum limits were tightened (1..1000 to 2..300) and the mainnetConfig() view was removed although the brief says limits stay exactly as audited"}],"hash":"68c76f2877f340ef9bdd5fbf435777178acfffc1887f7f0846fa413ab7d60803","nodeId":"0ef205d9-e326-4d18-9139-cec24ca07e19","outcome":"completed","summary":"The review is complete. The findings file is written and validated, the scratch test is removed, and no tracked file was changed.\n\n**Outcome.** The control flow for the gate-only launch holds. I traced the constructor, both submission paths, the oracle callback, clearing, execution and the unlock callback against the Execution Trace, Periphery and First Principles guides, and found no loss-of-funds or permanent-breakage defect reachable from the manifest's values. The full suite passes on this tree, including the three invariant campaigns at full size.\n\n**Findings written to `.imd-findings.json`:**\n\n- **Low, constructor fee word unbounded.** The constructor bounds tickSpacing but accepts any `fee`, including values above the v4 maximum. A gate built with such a word passes the empty-EVM launch checks, the live hook's one-time `setGate` binds it anyway (it compares only `hook()` and `cabal()`), and the gate then refuses every submission forever while the correct gate can never be bound. Reproduced with a scratch test on the current tree. The manifest value 12500 is correct, so this is a deploy-time backstop, not a live defect. Suggested fix: revert when fee exceeds the v4 maximum, or pin fee and tickSpacing to the live pool's values.\n- **Info, scope deviation.** The brief says limits stay exactly as audited, but the panel and quorum bounds were tightened to the oracle's 2 to 300 range and the old `mainnetConfig` view was removed to recover bytes. Both are documented in ADAPTATION.md and are improvements. Recorded so the requester accepts the deviation explicitly.\n\n**Coverage.** All 28 listed entry points have rows, plus rows for the constructor and four invariants I checked: no payment before the hook reports this gate and key, the request body stays inside the oracle's input limits (definition values measured at 140 to 403 characters against a 512 cap), the launch size bounds (runtime 133 bytes under EIP-170), and the passing test suite. The only rows marked `finding` are the constructor and `CabalHook.setGate`, both pointing at the fee-word backstop.\n\n**Not reached.** I did not re-derive the oracle's canonical question hash or the live signature vector beyond confirming the existing live-vector tests pass, since the brief declares the oracle struct, type string and domain unchanged from the prior audit.","treeHash":null,"usage":{"cachedInputTokens":1467419,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":44933,"runtime":"claude","turns":33,"wallClockMs":786933}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"74a99f640688d37b","findings":[{"citation":"resolved","description":"Seam boundary x precision (Numerical Gap). ImpactEstimator.estimate (src/ImpactEstimator.sol:48-59) prices an exact-input swap against the liquidity active at the current price only: `end = L*sqrtP/(L + net*sqrtP/Q96)` with L = poolManager.getLiquidity(). A Uniswap v4 swap that leaves that range continues against whatever liquidity is initialised beyond it. When the active range is deep and narrow and the surrounding liquidity is shallow, the estimate is a small fraction of the real movement. The submission gate at src/CabalGate.sol:255-256 compares the estimate with maxImpactBps, so the request is accepted, the submitter pays IIntake.priceOf (0.5 IMD live), the question sent to the panel states the wrong `estimated price impact bps`, the panel approves, and the execution cap at src/CabalGate.sol:453 (`priceMovement(beforePrice, afterPrice) > cfg.maxImpactBps`) reverts with LimitExceeded. The approval is unusable; the user can only clear it after approvedUntil and resubmit, paying again. On the live pool this liquidity shape arises naturally: CabalHook._addSingleSided places protocol-owned liquidity in 600-tick single-sided bands beside the current tick after every fee, so the depth profile is stepped, and anyone may also add a one-spacing-wide position (the hook has no add-liquidity permission) to make a victim's estimate pass before their execution fails. The limitation is acknowledged in QuestionBuilder.DEFINITIONS (\"Single range: further tick crossings are not modelled\"), so this is reported as low: the execution-time check holds and only the non-refundable oracle price is lost. A minimal fix that keeps the design: have the estimator walk initialised ticks in the swap direction (as the pool does) for up to a bounded number of steps, or revert the submission when the estimated end price leaves the active range (sqrtPrice of the nearest initialised tick in the direction), so an under-estimate can never pass the cap.","line":255,"path":"src/CabalGate.sol","reproduction":"Fixture (test/CabalFixture.sol): IMD is currency0, pool price Q96 (tick 0), seed liquidity 1e25 in [-1200, 1200]. Configure live limits: maxBuyAmount = 1e24, maxImpactBps = 300, maxDriftBps = 500. Anyone adds 1e26 liquidity in the one-spacing range [-60, 60] (modifyLiquidity, allowed by the hook). Then: gate.estimateImpact(true, 6.4e23) returns 114 bps (<= 300). ALICE calls submitBuyRequest(6.4e23, reason): succeeds, ALICE's IMD drops by intake.price(); the body's question says `estimated price impact bps=114`. The oracle approves (status Approved) and ALICE sets a minimum output. ALICE calls executeBuyRequest(id) with the pool unchanged since submission (drift = 0): reverts LimitExceeded from the impact check in unlockCallback. Measured with the cap raised to 5000 the same swap moves the price 632 bps: within the narrow range the 1.1e26 liquidity absorbs ~3.3e23 of the 6.32e23 net input (60 ticks), the remaining ~3e23 then moves against only 1e25, i.e. a ~3% sqrt-price move on top. Expected: a request whose true impact exceeds maxImpactBps is refused at submission, before payment, or the panel sees the real figure. Actual: the request is paid for, approved on a wrong figure and can never execute. Control: the same trade with only the wide seed gives estimate 568 bps == actual 568 bps (the formula is right; the gap is the range edge). Verified with a scratch Foundry test (not kept).","severity":"low","snippet":"        uint256 estimated = estimateImpact(buy, amount);\n        if (estimated > cfg.maxImpactBps) revert LimitExceeded();","title":"Single-range impact estimate under-reports trades that cross a liquidity step: submission and panel accept an impact figure the execution cap then refuses, and the submitter's oracle price is lost"},{"citation":"resolved","description":"Seam boundary x precision. The only lower bound on a request is amount > 0. For a buy of 1 wei IMD the estimator's net input `amount * (1e6 - 12500) / 1e6` truncates to 0, so estimateImpact returns 0 and submission succeeds, charging the oracle price (0.5 IMD) for a trade of 1 wei. At execution the v4 exact-input swap of 1 wei yields amountIn 0 / fee 1 and zero output, and unlockCallback (src/CabalGate.sol:450) reverts PartialFill because outputDelta <= 0; the approval can never be used. This is self-inflicted and bounded by the oracle price, so informational: a user interface or a minimum amount per request (for example amount >= 400 so the hook fee is also non-zero) would close it. No funds beyond the oracle price are at risk.","line":250,"path":"src/CabalGate.sol","reproduction":"Fixture defaults. gate.estimateImpact(true, 1) == 0. ALICE calls submitBuyRequest(1, reason): succeeds and ALICE's IMD balance falls by intake.price(). Deliver an approving attestation and setSlippageLimit(id, 1). ALICE calls executeBuyRequest(id): reverts PartialFill. Expected: a request that cannot produce any output is refused before the oracle is paid. Actual: paid, approved, never executable. Verified with a scratch Foundry test (not kept).","severity":"info","snippet":"        if (amount == 0 || amount > maxAmount) revert LimitExceeded();","title":"Dust buy amounts pass the `amount == 0` check and the impact estimate but can never execute: the request is paid for and ends in PartialFill"},{"citation":"resolved","description":"Math Precision: fees should round up; feeFor floors volume/400 and doubles it, so a 0.5% fee of `volume/200` is under-collected by up to 2 wei per trade and is zero for any volume under 400 wei. The gate mirrors the same formula (src/CabalGate.sol:404 and 456) so gate and hook agree and nothing desynchronises; the loss is protocol dust that cannot be farmed because each trade costs a 0.5 IMD oracle request. CabalHook is live and out of scope for changes; recorded for completeness and already pinned by test/EconomicProperties.t.sol.","line":176,"path":"src/CabalHook.sol","reproduction":"hook.feeFor(399) returns 0 (0.5% of 399 is 1.995 -> expected at least 1 if rounding up); hook.feeFor(799) returns 2 (0.5% of 799 is 3.995 -> 3 rounding down, 4 rounding up). A buy of 399 wei IMD through the gate burns and allocates nothing. Verified with a scratch Foundry test (not kept).","severity":"info","snippet":"        return (volume / 400) * 2;","title":"Hook fee rounds down twice: volumes below 400 wei pay no fee and every leg loses up to one unit (dust, live hook cannot change)"},{"citation":"resolved","description":"Boundary (constructor input). The assignment lists nineteen constructorArgs (hook, poolManager, cabal, currency0, currency1, fee, tickSpacing, initialOwner, intake, imd, signer, action, maxBuyAmount, maxSellAmount, maxImpactBps, maxDriftBps, panelSize, quorum, windowHours). The delivered constructor takes fifteen (hook, poolManager, cabal, initialOwner, intake, imd, signer, action, maxBuyAmount, maxSellAmount, maxImpactBps, maxDriftBps, panelSize, quorum, windowHours), per ADAPTATION.md (the manifest allows at most sixteen words; fee and tick spacing became constants and the currencies are sorted inside). If the manifest step transcribes the brief's list, word 9 (the intake address) lands in the uint128 maxBuyAmount slot with non-zero high bits and the ABI decoder reverts, so the launch rehearsal fails with \"application constructor failed\" exactly as launch 990 did. Not a code defect: the implemented order is documented in docs/DEPLOYMENT.md and rehearsed by test/GateLaunch.t.sol. Recorded so the manifest step and the judge use the fifteen-word order and not the brief's nineteen.","line":139,"path":"src/CabalGate.sol","reproduction":"Append abi.encode of the nineteen brief values (hook, manager, cabal, cabal, imd, uint24 12500, int24 60, owner, intake, imd, signer, action, 1e24, 1e25, 300, 500, 30, 20, 1) to the CabalGate creation code and CREATE it: the deployment returns address(0) (constructor reverts in argument decoding). The same creation code with the fifteen words of docs/DEPLOYMENT.md deploys (test/GateLaunch.t.sol test_gateDeploysInAnEmptyEvmWithTheManifestWords). Verified with a scratch Foundry test (not kept).","severity":"info","snippet":"    constructor(\n        CabalHook launchHook,\n        IPoolManager manager,\n        address cabalToken,\n        address initialOwner,","title":"The brief's nineteen-word constructor argument list does not decode against the delivered fifteen-word constructor; the manifest must carry the fifteen words in the implemented order"}],"hash":"74b68d4a915c5f22ce36bed78289cc697a2d3b019a17c36edb8eaf36ccd01ae3","nodeId":"00c41a30-650c-49ce-8400-4d3ce99dce74","outcome":"completed","summary":"The review is complete. The findings file holds four findings and a full coverage record, and the working tree is otherwise untouched (the findings file is gitignored, so `git status` is clean).\n\n**What I audited.** The Math Precision, Boundary and Numerical Gap guides against the gate's arithmetic: `PriceMath.movement`, the impact estimator and its tick-bitmap walk, the spot and average price formulas, fee and holding accounting, every downcast, every time-window comparison in the oracle callback, the question length bound, the callback's gas against the 200k stipend, and the constructor's numeric validation against the live manifest words. Every one of the 28 listed entry points has a coverage row, plus four invariant rows. None is unreached.\n\n**Findings, by severity.**\n\n- **Low. Impact estimate under-reports across a liquidity step.** The estimator prices the swap against only the liquidity active at the current price. With a deep one-spacing range beside the shallow seed, a 640,000 IMD buy estimates 114 bps, under the 300 bps cap, so the submitter pays the oracle, the panel approves a question stating 114 bps, and execution then reverts because the real movement is 632 bps. The approval is unusable and the oracle price is lost. The live hook's own 600-tick protocol-liquidity bands create this stepped profile naturally, and anyone can add such a range. A control run on a single range gives estimate 568 bps equal to the actual 568 bps, so the formula itself is right. The author documents the limitation, which is why this is low rather than medium.\n- **Info. Dust requests.** A 1 wei buy passes the amount and impact checks, pays the oracle price, and can never execute because the swap produces zero output.\n- **Info. Hook fee rounds down.** Volumes under 400 wei pay no fee and each trade under-collects by up to 2 wei. The gate mirrors the formula exactly, so nothing desynchronises, and the hook is live and out of scope.\n- **Info. Constructor arity.** The brief lists nineteen constructor words but the delivered constructor takes fifteen, by operator instruction recorded in the adaptation notes. I verified that appending the nineteen brief values to the creation code fails deployment. The manifest step must use the fifteen-word order in `docs/DEPLOYMENT.md`.\n\n**What held.** Callback gas measured at 78,063 against the 200,000 stipend with the longest possible question. The time-window checks short-circuit before any subtraction can underflow. All narrowing casts are bounded by the int128 amount cap. The tick-bitmap walk matches Uniswap v4 semantics for negative ticks and crossing direction. The full existing suite of 161 unit tests passes.\n\n**Not reached.** Nothing in my area. I did not run the invariant campaigns or any fork, and the oracle service's own character counting for the 2,000-character question limit cannot be verified from this tree.","treeHash":null,"usage":{"cachedInputTokens":2524760,"inputTokens":514,"model":"claude-fable-5-1","outputTokens":58961,"runtime":"claude","turns":42,"wallClockMs":981901}},{"artifacts":[],"attempt":1,"bundleHash":"a19a2032dfda946c30a190ce8ec825d959b9f9460bd1e8e44832b57635972fa1","device":"6b47d1bf92391c22","findings":[{"description":"The brief fixes the constructor as nineteen flat arguments (hook, poolManager, cabal, currency0, currency1, fee, tickSpacing, initialOwner, intake, imd, signer, action, maxBuyAmount, maxSellAmount, maxImpactBps, maxDriftBps, panelSize, quorum, windowHours) and gives the matching nineteen manifest constructorArgs. The implementation takes fifteen (hook, poolManager, cabal, initialOwner, intake, imd, signer, action, maxBuy, maxSell, impact, drift, panel, quorum, window), with fee/tickSpacing as constants and the currencies sorted internally. ADAPTATION.md says an operator instruction reduced it to fifteen because the manifest allows at most sixteen words. That instruction is not in this task's brief, so I can't verify it. With the brief's words, ABI decoding shifts: initialOwner=CABAL, intake=IMD, imd=address(12500), signer=address(60), action=$owner, and maxBuyAmount=the Intake address, which exceeds uint128, so the constructor reverts. Either the brief's manifest words must be replaced by the fifteen words in docs/DEPLOYMENT.md, or the constructor must take the nineteen arguments the brief specifies. The requester has to decide which; the tests in test/ follow the fifteen-word implementation.","line":134,"path":"src/CabalGate.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {CabalGate} from \"src/CabalGate.sol\";\n\ncontract BriefWordsFactory {\n    function deploy(bytes memory code, bytes32 salt) external returns (address deployed) {\n        assembly (\"memory-safe\") {\n            deployed := create2(0, add(code, 32), mload(code), salt)\n        }\n        require(deployed != address(0) && deployed.code.length > 0, \"application constructor failed\");\n    }\n}\n\n/// @notice Deploys CabalGate with the nineteen constructorArgs the brief lists, in an empty EVM, as the launch checks do.\ncontract BriefNineteenWordsTest is Test {\n    function test_gateDeploysWithTheBriefsNineteenManifestWords() public {\n        vm.chainId(1);\n        address owner = makeAddr(\"owner\");\n        bytes memory words = abi.encode(\n            0xf41B6Ff942a082C0d320a0C151310ac2A922a0c0,\n            0x000000000004444c5dc75cB358380D2e3dE08A90,\n            0x450e5910DEcEe15c3AC056E3ed66Cb5ea3Dd33BE,\n            0x450e5910DEcEe15c3AC056E3ed66Cb5ea3Dd33BE,\n            0xD34a99Bc0f67aE1bbd63C660e6d0b0dd03E263B7,\n            uint256(12500),\n            uint256(60),\n            owner,\n            0x1397434cd35e8a9C8aC312A61D3A285EB31dea56,\n            0xD34a99Bc0f67aE1bbd63C660e6d0b0dd03E263B7,\n            0x5598Aa9146215Bc13eb26f2c692Ad1461Fd32982,\n            bytes32(0x6f7261636c652e72657175657374406f7261636c652d31000000000000000000),\n            uint256(1000000000000000000000000),\n            uint256(10000000000000000000000000),\n            uint256(300),\n            uint256(500),\n            uint256(30),\n            uint256(20),\n            uint256(1)\n        );\n        assertEq(words.length, 19 * 32);\n        BriefWordsFactory factory = new BriefWordsFactory();\n        CabalGate gate = CabalGate(factory.deploy(bytes.concat(type(CabalGate).creationCode, words), bytes32(0)));\n        assertEq(gate.owner(), owner, \"initialOwner must be the $owner word (word 7)\");\n        assertEq(gate.configuration().intake, 0x1397434cd35e8a9C8aC312A61D3A285EB31dea56);\n        assertEq(gate.configuration().imd, 0xD34a99Bc0f67aE1bbd63C660e6d0b0dd03E263B7);\n    }\n}","reproduction":"CREATE2-deploy CabalGate creationCode ++ abi.encode(the brief's 19 constructorArgs, $owner = any EOA) on chain 1 with no code at any dependency. Expected: deploys, owner()==$owner, configuration().intake==0x1397…ea56. Actual: constructor reverts (factory: 'application constructor failed'). The same deploy with the fifteen words in test/GateLaunch.t.sol::_words succeeds (GateEmptyEvmLaunchTest).","severity":"high","title":"CabalGate constructor takes 15 words; the brief's 19-word manifest constructorArgs cannot deploy it"}],"hash":"7cd472130b57295c8cd1fd2531383c00965ff0b6f39392b7397a606f3d2cde7d","nodeId":"b2c57e4b-76b8-476d-96f1-b8d268c0bdef","outcome":"completed","summary":"`forge build` passes, and `forge test` now passes all 179 tests in 28 suites, with none failing or skipped. Before my change one test failed. I also found a high-severity mismatch with the brief that tests can't resolve, so I've reported it in `.imd-findings.json` instead.\n\n**The failing test (fixed).** In `test/GateLiveHook.t.sol` (around line 106), `test_realHookRefusesGateBuiltWithSwappedTokenRoles` was still using a byte offset from an older 19-argument layout. It meant to overwrite the `imd` argument but hit `maxSellAmount` instead, so the gate never deployed. I corrected the offset; that one line is the only change to a delivered file.\n\n**The reported defect: the brief's deploy arguments don't fit the contract.** The brief lists 19 constructor arguments, starting hook, poolManager, cabal, currency0, currency1, fee, tickSpacing, initialOwner…. `src/CabalGate.sol` takes only 15:\n- Fee and tick spacing are fixed inside the contract at 12500 and 60.\n- currency0 and currency1 are worked out by sorting CABAL and IMD.\n\n`ADAPTATION.md` says an operator ordered this because a launch can take at most 16 constructor arguments. That instruction isn't in this task's brief, so I can't confirm it.\n\nDeploying with the brief's 19 values fails the same way the launch checks would (\"application constructor failed\"). Everything shifts by four positions: the owner becomes the CABAL token and the Intake address lands in `maxBuyAmount`, which is too big for its type. The proof is a test that deploys with the brief's 19 values and fails on the current code; its source is in the finding.\n\n**Decision for you:** either the launch uses the 15 values recorded in `docs/DEPLOYMENT.md`, or the constructor goes back to the 19 arguments the brief specifies. The existing tests follow the 15-argument version.\n\n**Coverage of the brief's test list** (already in the tree from earlier rounds):\n- **Empty-EVM deploy:** `GateEmptyEvmLaunchTest` deploys the gate with no code at the hook, pool manager, Intake, IMD or CABAL addresses, as the launch checks do.\n- **Requests and `setGate`:** using a mock hook and the real hook code placed at the live address, requests are refused until the gate is bound and succeed after. They are also refused without payment when the reported pool key, CABAL or IMD is wrong, or the gate is unset or another one. `setGate` accepts this gate once and refuses a second.\n- **Invariants:** random-sequence invariant tests cover what the gate holds and the request lifecycle.","treeHash":"01710eb4d1149c66914a1a44582914e229a7a383","usage":{"cachedInputTokens":683242,"inputTokens":22,"model":"claude-opus-5-5","outputTokens":6318,"runtime":"claude","turns":12,"wallClockMs":332467}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"4199bf0c80a9d6cf","findings":[{"citation":"resolved","description":"The assignment specifies the constructor as nineteen flat arguments (hook, poolManager, cabal, currency0, currency1, fee, tickSpacing, initialOwner, intake, imd, signer, action, maxBuyAmount, maxSellAmount, maxImpactBps, maxDriftBps, panelSize, quorum, windowHours) and gives a nineteen-entry manifest constructorArgs list. The delivered constructor has fifteen parameters: currency0, currency1, fee and tickSpacing were removed, the fee (12500) and tick spacing (60) became constants and the currencies are derived by sorting cabal and imd. ADAPTATION.md and docs/DEPLOYMENT.md attribute this to an operator instruction that the manifest allows at most sixteen constructor words; nothing in the tree or the supplied references lets a reviewer verify that limit, and the brief handed to this review still carries the nineteen-word list. The manifest step writes launch.json from one of these two sources. If it transcribes the brief's nineteen entries, the compiled fifteen-parameter constructor decodes the first fifteen words positionally (word 3 = CABAL as initialOwner, word 5 = 12500 as imd, word 8 = the Intake address as maxBuyAmount), the ABI decoder rejects the address word that does not fit uint128, CREATE2 returns zero and the floor reverts with \"application constructor failed\": exactly the launch 990 symptom. If the sixteen-word limit is real, the brief's constructor is infeasible and the fifteen-word table in docs/DEPLOYMENT.md must be the manifest's source. Either way the two sources disagree and must be reconciled before the manifest step; the ABI of the compiled artifact (15 inputs: address x7, bytes32, uint128 x2, uint16 x4, uint8) is the authority the manifest must match, in that order.","line":139,"path":"src/CabalGate.sol","reproduction":"Under the protected floor's factory (ContractsDeploymentProbe.deploy), chain id 1, empty EVM: creation = CabalGate creation code ++ abi.encode(0xf41b…a0c0, 0x0000…8a90, 0x450e…33be, 0x450e…33be, 0xd34a…63b7, 12500, 60, $owner, 0x1397…ea56, 0xd34a…63b7, 0x5598…2982, 0x6f72…0000, 1e24, 1e25, 300, 500, 30, 20, 1) [19 words, the brief's list]. Expected per the brief: the gate deploys. Actual: deploy reverts \"application constructor failed\" (verified with a scratch Foundry test). The same creation code with the fifteen words in docs/DEPLOYMENT.md order deploys successfully (7,955,312 gas measured through the probe).","severity":"medium","snippet":"    constructor(\n        CabalHook launchHook,\n        IPoolManager manager,\n        address cabalToken,\n        address initialOwner,\n        address intake,\n        address imd,\n        address signer,\n        bytes32 action,\n        uint128 maxBuyAmount,\n        uint128 maxSellAmount,\n        uint16 maxImpactBps,\n        uint16 maxDriftBps,\n        uint16 panelSize,\n        uint16 quorum,\n        uint8 windowHours\n    ) Ownable(initialOwner) {","title":"Constructor takes 15 words but the brief's manifest constructorArgs list 19; a manifest written from the brief parks the launch again"},{"citation":"resolved","description":"The constructor (by mandate) reads nothing from the hook, so the pool key it stores is shaped only by the hook, cabal and imd words, and the key is never exposed (there is no poolKey() view on the gate; only _keyHash is kept). The live hook's setGate checks only gate.hook() and gate.cabal(), never the key or the imd, and the binding is one-time and permanent. Consequently a gate whose imd word is any address other than hook.imd() (a transcription slip, the Robinhood-chain IMD, a wrong checksum) is accepted by setGate, after which every submitBuyRequest/submitSellRequest reverts InvalidConfig at the keccak256(reported) != _keyHash check, the gate owner cannot repair it (configure requires cfg.imd == hook.imd() and _key is set only in the constructor), and the hook refuses every later gate (gate != address(0)). The only protection is the pre-binding procedure in docs/DEPLOYMENT.md asking the hook owner to recompute the key off-chain from the words. The assumption chain is: setGate assumes the gate's key is right because its cabal() matches; the gate assumes the hook owner compared the key. Neither checks. A public view returning the derived PoolKey (or its hash) on the gate would let the hook owner compare hook.poolKey() against the gate on-chain before the irreversible call; note the runtime is 24,522 bytes, 54 under EIP-170, so the getter must be paid for by trimming elsewhere.","line":163,"path":"src/CabalGate.sol","reproduction":"Real CabalHook and PoolManager, hook initialized and unbound. Deploy gate W with the fifteen words but imd = 0x5F7Bb59365ce557C26dbcAa4EE9d39A4b95B7127 (not hook.imd()), and gate R with the correct imd. hook.owner() calls hook.setGate(W): succeeds, hook.gate() == W. ALICE calls W.submitBuyRequest(100e18, \"Pay October hosting\"): reverts InvalidConfig. Owner calls W.configure with imd = hook.imd(): accepted, submit still reverts InvalidConfig. hook.owner() calls hook.setGate(R): reverts InvalidGate. Expected: the mis-built gate should be detectable before the irreversible binding; actual: it is accepted and the hook is permanently without a working gate (verified with a scratch Foundry test).","severity":"low","snippet":"        (address currency0, address currency1) = cabalToken < imd ? (cabalToken, imd) : (imd, cabalToken);","title":"A gate built with a wrong imd word passes hook.setGate, can never submit, and consumes the live hook's only binding forever"}],"hash":"7ebec5b3f9c0d51bb6771d7f5925380489e630642e1d2769e5414da046123d6b","nodeId":"0ef205d9-e326-4d18-9139-cec24ca07e19","outcome":"completed","summary":"Review complete. The tree is clean apart from `.imd-findings.json`, which holds two findings and a 31-row coverage record. No source files were changed, and the scratch tests were removed.\n\n**Outcome**\n\nThe gate's control flow holds. The constructor makes no external calls and deploys through the floor's probe in an empty EVM, the submission path checks the hook's key, gate, CABAL and IMD before any payment, and the oracle struct, type string and domain reproduce the live vectors. Build and all 167 existing tests pass with this toolchain. Runtime is 24,522 bytes, 54 under the EIP-170 cap. Deployment through the probe costs about 7.96M gas, which the policy's gas ceiling must cover. The callback uses 78k gas with the longest question.\n\n**Findings**\n\n- **Medium, constructor arity versus the brief.** The brief specifies nineteen constructor words and a nineteen-entry manifest list. The compiled constructor takes fifteen. A scratch test deploying the brief's nineteen words through the floor's factory reverts with \"application constructor failed\", the launch 990 symptom. The tree attributes the reduction to an operator instruction about a sixteen-word manifest limit that nothing available to me verifies. The manifest step must follow the compiled ABI and the table in docs/DEPLOYMENT.md, not the brief's list, and the two sources need reconciling.\n- **Low, a wrong IMD word bricks the live hook's binding.** A gate built with any imd word other than the hook's derives a key the hook never bound. The live hook's setGate accepts it anyway, the binding is permanent, every submission then reverts, the owner cannot repair it, and the correct gate can never be bound. Verified against the real hook and PoolManager. The only guard is the off-chain procedure in docs/DEPLOYMENT.md. A key getter on the gate would let the hook owner compare on-chain first, at the cost of trimming bytes elsewhere.\n\n**Coverage**\n\nAll 28 listed entry points have rows. Every CabalGate and CabalCoin entry point holds. CabalHook rows hold as live, unchanged code, except setGate, which carries finding 2. Three invariant rows record the empty-EVM deployment, the size and gas measurements, and the oracle format check. No area was left unreached. Slither and aderyn leads on reentrancy, strict equality and unused returns were traced and none produced a reachable defect.","treeHash":null,"usage":{"cachedInputTokens":1888941,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":43236,"runtime":"claude","turns":49,"wallClockMs":931030}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"7c748c02cd2ee98f","findings":[{"citation":"resolved","description":"The assignment fixes the constructor as nineteen flat arguments in the order hook, poolManager, cabal, currency0, currency1, fee, tickSpacing, initialOwner, intake, imd, signer, action, maxBuyAmount, maxSellAmount, maxImpactBps, maxDriftBps, panelSize, quorum, windowHours, and gives a manifest constructorArgs with exactly those nineteen entries. The tree's constructor declares fifteen parameters (hook, poolManager, cabal, initialOwner, intake, imd, signer, action, maxBuyAmount, maxSellAmount, maxImpactBps, maxDriftBps, panelSize, quorum, windowHours); currency0/currency1 are derived by sorting and fee/tickSpacing are constants. ADAPTATION.md attributes this to an operator instruction that the manifest allows at most sixteen words, which is not visible in any pinned input. The two documents therefore disagree on the ABI, and whichever one the manifest step follows determines whether the launch parks again: with the brief's nineteen entries, the ABI decoder reads word 8 (the Intake address 0x1397...ea56) as uint128 maxBuyAmount and reverts, which is the same failure class ('application constructor failed') that parked launch 990. Access-control consequence if the decoder did not revert on a shifted layout: word 3 (currency0 = CABAL) would become initialOwner, so the gate's owner would be the CABAL token address and configure() would be unreachable forever. Either the constructor must be restored to the brief's nineteen words, or the brief/manifest must be corrected to the fifteen-word order documented in docs/DEPLOYMENT.md before the manifest step runs; the tree itself cannot satisfy the brief as written.","line":139,"path":"src/CabalGate.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {CabalGate} from \"src/CabalGate.sol\";\n\n/// @dev The launch factory's deploy, as the protected floor rehearses it: CREATE2 of creation code ++ the\n///      manifest's ABI-encoded constructorArgs, in an EVM where nothing the gate names has code.\ncontract BriefLaunchFactory {\n    function deploy(bytes memory code, bytes32 salt) external returns (address deployed) {\n        require(code.length > 0 && code.length <= 49_152, \"invalid init code\");\n        assembly (\"memory-safe\") {\n            deployed := create2(0, add(code, 32), mload(code), salt)\n        }\n        require(deployed != address(0) && deployed.code.length > 0, \"application constructor failed\");\n    }\n}\n\n/// @notice The brief's manifest constructorArgs are nineteen words in the order hook, poolManager, cabal,\n///         currency0, currency1, fee, tickSpacing, initialOwner, intake, imd, signer, action, maxBuyAmount,\n///         maxSellAmount, maxImpactBps, maxDriftBps, panelSize, quorum, windowHours. Encoding exactly those\n///         words behind the current creation code must deploy a gate configured with them.\ncontract BriefManifestWordsTest is Test {\n    address internal constant HOOK = 0xf41B6Ff942a082C0d320a0C151310ac2A922a0c0;\n    address internal constant POOL_MANAGER = 0x000000000004444c5dc75cB358380D2e3dE08A90;\n    address internal constant CABAL = 0x450e5910DEcEe15c3AC056E3ed66Cb5ea3Dd33BE;\n    address internal constant INTAKE = 0x1397434cd35e8a9C8aC312A61D3A285EB31dea56;\n    address internal constant IMD = 0xD34a99Bc0f67aE1bbd63C660e6d0b0dd03E263B7;\n    address internal constant SIGNER = 0x5598Aa9146215Bc13eb26f2c692Ad1461Fd32982;\n    bytes32 internal constant ACTION = 0x6f7261636c652e72657175657374406f7261636c652d31000000000000000000;\n\n    function test_briefNineteenManifestWordsDeployTheGateInAnEmptyEvm() public {\n        vm.chainId(1);\n        address owner = makeAddr(\"launch owner resolves $owner\");\n        assertEq(HOOK.code.length, 0);\n        assertEq(POOL_MANAGER.code.length, 0);\n        assertEq(INTAKE.code.length, 0);\n        assertEq(IMD.code.length, 0);\n\n        // Static words exactly as the brief's manifest lists them, in its declared order.\n        bytes memory arguments = abi.encode(\n            HOOK,\n            POOL_MANAGER,\n            CABAL,\n            CABAL, // currency0\n            IMD, // currency1\n            uint256(12500), // fee\n            uint256(60), // tickSpacing\n            owner,\n            INTAKE,\n            IMD,\n            SIGNER,\n            ACTION,\n            uint256(1000000000000000000000000),\n            uint256(10000000000000000000000000),\n            uint256(300),\n            uint256(500),\n            uint256(30),\n            uint256(20),\n            uint256(1)\n        );\n        assertEq(arguments.length, 19 * 32);\n        bytes memory creation = bytes.concat(vm.getCode(\"CabalGate.sol:CabalGate\"), arguments);\n        BriefLaunchFactory factory = new BriefLaunchFactory();\n\n        // Fails on the current tree: the constructor declares fifteen parameters in another order, so word 8\n        // (the Intake address) is decoded as uint128 maxBuyAmount and the ABI decoder reverts.\n        CabalGate gate = CabalGate(factory.deploy(creation, keccak256(\"brief words\")));\n        assertEq(gate.owner(), owner, \"word 7 is initialOwner in the brief's order\");\n        assertEq(address(gate.hook()), HOOK);\n        assertEq(address(gate.cabal()), CABAL);\n        CabalGate.Config memory cfg = gate.configuration();\n        assertEq(cfg.intake, INTAKE, \"word 8 is intake in the brief's order\");\n        assertEq(cfg.imd, IMD, \"word 9 is imd in the brief's order\");\n        assertEq(cfg.signer, SIGNER);\n        assertEq(cfg.action, ACTION);\n        assertEq(cfg.maxBuyAmount, 1000000000000000000000000);\n        assertEq(cfg.maxSellAmount, 10000000000000000000000000);\n        assertEq(cfg.maxImpactBps, 300);\n        assertEq(cfg.maxDriftBps, 500);\n        assertEq(cfg.panelSize, 30);\n        assertEq(cfg.quorum, 20);\n        assertEq(cfg.windowHours, 1);\n        assertEq(cfg.oracleVerifier, address(gate));\n        assertEq(cfg.boolAnswerType, 0);\n    }\n}","reproduction":"vm.chainId(1); creation = vm.getCode('CabalGate.sol:CabalGate') ++ abi.encode(HOOK 0xf41b...a0c0, POOL_MANAGER 0x0000...8a90, CABAL 0x450e...33be, CABAL, IMD 0xd34a...63b7, 12500, 60, owner, INTAKE 0x1397...ea56, IMD, SIGNER 0x5598...2982, ACTION 0x6f72...0000, 1e24, 1e25, 300, 500, 30, 20, 1) (19 words, the brief's manifest order); factory.deploy(creation, salt) with the protected floor's CREATE2 factory in an EVM with no code at any dependency. Expected: a CabalGate whose owner() is `owner`, configuration().intake == INTAKE and maxBuyAmount == 1e24. Actual: revert 'application constructor failed' (constructor ABI decode fails on word 8). The tree's own tests only encode the fifteen-word order (test/GateLaunch.t.sol _words), so no existing test exercises the brief's manifest.","severity":"medium","snippet":"    constructor(\n        CabalHook launchHook,\n        IPoolManager manager,\n        address cabalToken,\n        address initialOwner,","title":"Constructor takes 15 words in a different order than the brief's 19-entry manifest; deploying with the brief's constructorArgs fails with 'application constructor failed'"},{"citation":"resolved","description":"The gate checks the hook's poolKey, gate, cabal and imd at every submission (required by the brief, since the constructor may read nothing). The live hook's setGate (src/CabalHook.sol:113-121, out of scope for change) accepts any contract whose hook() and cabal() match, and the binding is one-time. The two checks are asymmetric: a gate whose imd word differs from hook.imd() (so its derived key differs from hook.poolKey()) passes setGate and then refuses every submitBuyRequest/submitSellRequest with InvalidConfig forever; because only the bound gate may swap (CabalHook._checkSwap), the CABAL/IMD pool becomes permanently untradeable and no second gate can be bound. The launch checks (empty EVM) cannot detect a wrong word. This is the hook owner's single irreversible action; docs/DEPLOYMENT.md already instructs recomputing keccak256(abi.encode(hook.poolKey())) and hook.imd() before binding. Recorded so the judge sees the state is reachable from a single wrong manifest word with no on-chain guard, not as a code defect in the gate.","line":245,"path":"src/CabalGate.sol","reproduction":"Deploy CabalGate with the manifest words but imd = any address other than 0xd34a...63b7 (e.g. the CABAL/IMD roles swapped, as test_hookRefusesGateWithSwappedTokenRoles does, or a typo). With a hook that reports cabal == the gate's cabal word (which is all the live setGate checks besides hook()), hookOwner calls hook.setGate(gate): succeeds and hook.gate() == gate. Then any user: gate.submitBuyRequest(100e18, 'reason') -> InvalidConfig (hook.imd() != cfg.imd, key hash mismatch). hookOwner calls hook.setGate(correctGate) -> InvalidGate (gate != 0). Expected: a mis-built gate cannot be bound. Actual: it can, and the binding is permanent. The tree's test for this scenario relies on cabal() mismatching; a gate with correct cabal and wrong imd is not tested.","severity":"info","snippet":"            !ok || keccak256(reported) != _keyHash || hook.gate() != address(this) || hook.cabal() != address(cabal)","title":"Trust assumption: hook.setGate verifies only hook() and cabal(); a gate built with a wrong imd word (or any key the hook does not report) can be bound permanently and can never submit, leaving the poo"},{"citation":"resolved","description":"onOracleResult authorizes and verifies against the snapshot _configs[r.version], but _execute requires r.version == configVersion. Any owner configure() therefore strands every in-flight request: the 0.5 IMD already pulled at submission is spent, an attestation delivered afterwards is consumed (attestationUsedBy) and marks the request Approved, yet executeBuy/SellRequest reverts InvalidRequest and the only exit is clearRequest. The owner gains nothing and the behaviour is documented (docs/DEPLOYMENT.md: 'Configuration updates invalidate existing executions and do not refund oracle charges'), so this is a privileged-power trust assumption rather than a bypass. Noted because an owner transaction that lands between a user's submission and execution costs that user the oracle fee with no on-chain notice window.","line":391,"path":"src/CabalGate.sol","reproduction":"ALICE: submitBuyRequest(100e18, 'reason') pays price 0.5 IMD; intake delivers a signed yes -> status Approved. Owner: configure(current config with windowHours = 2) -> configVersion 2. ALICE: executeBuyRequest(id, 1) -> revert InvalidRequest (r.version 1 != 2). ALICE: clearRequest(id) succeeds; ALICE is down 0.5 IMD with no trade (test/Oracle.t.sol test_ownerConfigSnapshotsInvalidatesOldExecutionAndCanClear shows the same sequence).","severity":"info","snippet":"        if (r.status != Status.Approved || r.buy != buy || r.version != configVersion) revert InvalidRequest();","title":"Trust assumption: owner configure() invalidates every pending and approved request; requesters' already-paid oracle fee is not refunded and approvals become unexecutable"},{"citation":"resolved","description":"configure() is onlyOwner and binds imd to hook.imd(), but intake, signer, action and oracleVerifier are free. A malicious or compromised gate owner can (a) point intake at a contract they control and signer at their own key, so their own requests are approved without a panel, trading within the amount/impact/drift limits that remain enforced; and (b) make priceOf return any value, so submitBuyRequest/submitSellRequest pulls that amount from a submitter who approved more than the quoted price (the gate pulls priceOf(action, imd) with no user-supplied cap). The hook fee and limits still apply and the gate custody is per-transaction, so no idle funds are at risk. Already documented in docs/DEPLOYMENT.md as an owner power with the mitigation that users approve only the quoted price; recorded here as the permission model's largest trust point, not as a bypass.","line":210,"path":"src/CabalGate.sol","reproduction":"(b) Owner: configure(cfg with intake = EvilIntake whose priceOf returns 1000e18 and request pulls it). BOB has approved type(uint256).max IMD to the gate (as the fixtures do): BOB.submitBuyRequest(1e18, 'r') -> _pullExact pulls 1000 IMD from BOB to the gate and forwards it to EvilIntake. Expected: submitter pays the published 0.5 IMD. Actual: pays whatever the owner-selected Intake quotes, bounded only by BOB's allowance and balance.","severity":"info","snippet":"        if (cfg.intake.code.length == 0 || cfg.imd != address(hook.imd()) || cfg.imd.code.length == 0) {","title":"Trust assumption: the gate owner can replace intake, signer, action and oracleVerifier, which lets the owner bypass the oracle decision for their own trades and lets an owner-chosen Intake quote any p"}],"hash":"8352fa2182dad8e6d247ff7fb3e1727c894900a1edece98b2c44b4c1961f3969","nodeId":"0a92b515-7177-44b4-bfee-e6301cb6a1e2","outcome":"completed","summary":"The review is complete and `.imd-findings.json` holds the result. No repository file was changed; only the findings file and a scratch test under `test/scratch/` were written.\n\n**Outcome.** The gate's permission model holds up under the Access Control, Trust Gap and Asymmetry checks. I found one substantiated defect, which is a mismatch between the brief and the tree rather than a bug in the request flow, plus three documented trust assumptions recorded as info.\n\n**Finding 1, medium, with proof.** The brief fixes a 19-word constructor and a 19-entry manifest, but the constructor in `src/CabalGate.sol:139` takes 15 words in a different order. ADAPTATION.md attributes the cut to an operator instruction about a 16-word manifest limit that appears in no pinned input. I encoded the brief's exact 19 constructorArgs behind the current creation code and deployed through a copy of the protected floor's factory. It reverts with \"application constructor failed\", the same failure class that parked launch 990. The scratch test fails on this tree and passes once the constructor matches the brief. Either the constructor is restored to 19 words or the manifest step must use the 15-word order from docs/DEPLOYMENT.md, and that decision has to be made before the manifest is written.\n\n**Info findings, all documented in the tree.**\n- The live hook's setGate checks only hook() and cabal(). A gate built with a wrong imd word binds successfully and then refuses every submission forever, leaving the pool unswappable. The hook is out of scope, so this is a handoff risk.\n- Owner reconfiguration strands every in-flight request. The requester's paid oracle fee is lost and the approval cannot execute.\n- The gate owner can replace intake, signer and verifier, which lets the owner bypass the panel for their own trades and lets an owner-chosen Intake quote any price to submitters.\n\n**Coverage.** All 29 rows answered: 25 holds, 4 finding, 0 unreached. I traced every CabalGate entry point for caller, guard, state writes and failure paths, plus the hook's setGate, swap callbacks and finishSwap. The full project suite passes with 167 tests.\n\n**Not covered.** No fork or live-chain read, so the manifest values were taken from the brief as given. Runtime is 54 bytes under the EIP-170 limit, which the fix for finding 1 would have to respect.","treeHash":null,"usage":{"cachedInputTokens":1175876,"inputTokens":290,"model":"claude-fable-5-1","outputTokens":31386,"runtime":"claude","turns":42,"wallClockMs":751420}},{"artifacts":[],"attempt":2,"bundleHash":"574a2e9c790801da1a933bae130b272c2dc7393a1af28494adb53d61c19770fc","device":"27168b1ff68f84d2","findings":[],"hash":"8841e823ef205134a95c97a1af16c42fffbd6fff11349581061c6c49599a8e31","nodeId":"14e85cbb-2386-4e83-b3e4-1251524e603c","outcome":"completed","summary":"Done. The gate now deploys in an empty EVM, builds and tests pass, and the stale manifest is gone.\n\n**What changed in `src/CabalGate.sol`**\n- The constructor takes the nineteen flat words in the brief's order and makes no external calls and no code-length checks. It stores hook, poolManager and cabal as immutables, builds the PoolKey from the currency, fee and tick-spacing words with the hook as `hooks`, and validates only chain-free facts: non-zero addresses, currency0 below currency1, cabal is one currency and imd the other, tick spacing fits int24, and the numeric limits as before. Tick spacing is a `uint24` word narrowed to `int24` because the launch ABI has no signed integers.\n- Every submission now requires the hook to report this gate, this CABAL, this IMD and exactly the stored pool key, reverting `InvalidConfig` before any oracle payment. The key is compared as raw return data against a hash computed once in the constructor, which kept the runtime small.\n- The owner's `configure` keeps the live checks the constructor cannot make: Intake and IMD have code and IMD equals the hook's IMD.\n- Panel size and quorum are bounded to the oracle's accepted 2 to 300 range. This fixes the reproduced low audit finding where a configuration with quorum 1 burned every request's fee.\n- The unused `mainnetConfig` view was removed. The submission checks pushed the runtime over EIP-170, and the audit named that view as the safe place to recover bytes.\n\n**Size, which matters for the floor's check**\n\n| Artifact | Bytes |\n| --- | --- |\n| Runtime (limit 24,576) | 24,443 |\n| Creation code plus 19 words (limit 49,152) | 38,011 |\n\n**Tests**: 166 pass in 25 suites, including the three invariant campaigns. The rewritten `test/GateLaunch.t.sol` deploys the gate with the manifest words where no code exists at the hook, PoolManager, Intake, IMD or CABAL addresses, then uses a mock hook at the live address to cover the one-time owner binding refusing a second gate, buy and sell requests that succeed only once the hook reports the gate, and requests refused when the hook reports another key, CABAL, IMD or gate. Edge-case, fixture and adversarial tests were updated to the new constructor and bounds.\n\n**Other files**: `launch.json` was deleted because it carried the thirteen-word constructor that parked launch 990 and the manifest step writes the new one. `ADAPTATION.md` lists every change, the audit disposition and the measured sizes. `docs/DEPLOYMENT.md` now transcribes the nineteen values and tells the hook owner to compare the hook's pool key hash with the manifest key before the permanent `setGate` call, since the hook checks only `hook()` and `cabal()`.\n\n**One thing to flag**: the previous attempt died during the checker's build, and a full build of this suite takes about four minutes and 3.5 GB here because the tests compile the real PoolManager through the IR pipeline. I kept my additions compact and did not add new heavy test contracts, but the suite's baseline cost is unchanged.","treeHash":"39ff23e6ba9586c7bd3bb135baac7fba5cbc1e0c","usage":{"cachedInputTokens":5580907,"inputTokens":1058,"model":"claude-fable-5-1","outputTokens":89939,"runtime":"claude","turns":81,"wallClockMs":1829422}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"584bd638e7e022f0","findings":[{"citation":"resolved","description":"The constructor calls launchHook.initialized(), poolManager(), cabal() and poolKey() (lines 142-146) and then _configure (line 217) requires cfg.intake.code.length != 0, cfg.imd == hook.imd() and cfg.imd.code.length != 0. The launch floor (.imd/reads/protected/evm_contracts/Contracts.protected.t.sol) deploys the gate by CREATE2 in a fresh EVM with no code at the hook, intake, IMD or PoolManager addresses; a call to a codeless address that must return data reverts in Solidity, so the constructor reverts and the probe fails with 'application constructor failed'. This is exactly why launch 990 parked. The constructor must take hook, poolManager, cabal, currency0, currency1, fee, tickSpacing, initialOwner, intake, imd, signer, action and the seven limits as flat words, store hook/poolManager/cabal as immutables, build the PoolKey locally, and validate only pure facts (non-zero addresses, currency0 < currency1, cabal is one currency and imd the other, numeric limits). The hook-dependent checks (hook.gate() == this, hook.poolKey() == stored key) belong in _submit, which already checks hook.gate(); the owner's configure may keep its code-length checks. Launch 990 confirmed on 2026-10-09 against mainnet (public RPC): hook.gate() is still 0x0, hook.owner() is 0xFc3C962FAD2C1cC77f1a0d46e7B8a2De79A21774, poolKey is (0x450e...33BE, 0xD34a...63B7, 12500, 60, hook), Intake.priceOf(action, IMD) is 0.5 IMD, so the manifest words in the brief are correct and only the constructor blocks the launch.","line":142,"path":"src/CabalGate.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {CabalGate} from \"src/CabalGate.sol\";\n\n/// @dev The protected floor's CREATE2 probe, as the launch checks run it: an empty EVM, no chain state.\ncontract EmptyChainFactory {\n    function deploy(bytes memory code, bytes32 salt) external returns (address deployed) {\n        require(code.length > 0 && code.length <= 49_152, \"invalid init code\");\n        assembly (\"memory-safe\") {\n            deployed := create2(0, add(code, 32), mload(code), salt)\n        }\n        require(deployed != address(0) && deployed.code.length > 0, \"application constructor failed\");\n    }\n}\n\n/// @notice Launch 990 parked because the CabalGate constructor reads the hook (initialized, poolManager, cabal,\n///         poolKey, imd) and requires code at intake and imd. The launch checks deploy in an EVM where none of those\n///         addresses has code, so the constructor reverts. This test deploys the gate with the brief's nineteen\n///         manifest words in exactly that state and asserts it deploys. It fails on the current source\n///         (\"application constructor failed\") and passes once the constructor makes no external calls and no\n///         code-length checks.\ncontract ProofConstructorNeedsChainStateTest is Test {\n    address internal constant HOOK = 0xf41B6Ff942a082C0d320a0C151310ac2A922a0c0;\n    address internal constant POOL_MANAGER = 0x000000000004444c5dc75cB358380D2e3dE08A90;\n    address internal constant CABAL = 0x450e5910DEcEe15c3AC056E3ed66Cb5ea3Dd33BE;\n    address internal constant IMD = 0xD34a99Bc0f67aE1bbd63C660e6d0b0dd03E263B7;\n    address internal constant INTAKE = 0x1397434cd35e8a9C8aC312A61D3A285EB31dea56;\n    address internal constant SIGNER = 0x5598Aa9146215Bc13eb26f2c692Ad1461Fd32982;\n    bytes32 internal constant ACTION = 0x6f7261636c652e72657175657374406f7261636c652d31000000000000000000;\n\n    function test_gateDeploysInAnEmptyEvmWithTheManifestWords() public {\n        vm.chainId(1);\n        address owner = makeAddr(\"launch owner resolves $owner\");\n        // The launch checks' precondition: nothing the constructor could call exists.\n        assertEq(HOOK.code.length, 0, \"hook must have no code in this rehearsal\");\n        assertEq(POOL_MANAGER.code.length, 0, \"pool manager must have no code in this rehearsal\");\n        assertEq(INTAKE.code.length, 0, \"intake must have no code in this rehearsal\");\n        assertEq(IMD.code.length, 0, \"imd must have no code in this rehearsal\");\n        assertEq(CABAL.code.length, 0, \"cabal must have no code in this rehearsal\");\n\n        // Manifest constructorArgs, flat, in the brief's order: hook, poolManager, cabal, currency0, currency1,\n        // fee, tickSpacing, initialOwner, intake, imd, signer, action, maxBuyAmount, maxSellAmount, maxImpactBps,\n        // maxDriftBps, panelSize, quorum, windowHours. Every value is one static ABI word, as the factory sends it.\n        bytes memory arguments = abi.encode(\n            HOOK,\n            POOL_MANAGER,\n            CABAL,\n            CABAL,\n            IMD,\n            uint256(12500),\n            uint256(60),\n            owner,\n            INTAKE,\n            IMD,\n            SIGNER,\n            ACTION,\n            uint256(1000000000000000000000000),\n            uint256(10000000000000000000000000),\n            uint256(300),\n            uint256(500),\n            uint256(30),\n            uint256(20),\n            uint256(1)\n        );\n        assertEq(arguments.length, 19 * 32);\n        bytes memory creation = bytes.concat(vm.getCode(\"CabalGate.sol:CabalGate\"), arguments);\n        assertLe(creation.length, 49_152, \"init code exceeds the factory bound\");\n\n        EmptyChainFactory factory = new EmptyChainFactory();\n        CabalGate gate = CabalGate(factory.deploy(creation, keccak256(\"launch 990 retry\")));\n\n        assertGt(address(gate).code.length, 0);\n        assertLe(address(gate).code.length, 24_576, \"runtime exceeds EIP-170\");\n        assertEq(address(gate.hook()), HOOK, \"hook() getter must return the supplied hook\");\n        assertEq(address(gate.cabal()), CABAL, \"cabal() getter must return the supplied CABAL\");\n        assertEq(address(gate.poolManager()), POOL_MANAGER);\n        assertEq(gate.owner(), owner);\n        assertEq(gate.configVersion(), 1);\n        CabalGate.Config memory cfg = gate.configuration();\n        assertEq(cfg.intake, INTAKE);\n        assertEq(cfg.imd, IMD);\n        assertEq(cfg.signer, SIGNER);\n        assertEq(cfg.oracleVerifier, address(gate));\n        assertEq(cfg.action, ACTION);\n        assertEq(cfg.maxBuyAmount, 1000000000000000000000000);\n        assertEq(cfg.maxSellAmount, 10000000000000000000000000);\n        assertEq(cfg.maxImpactBps, 300);\n        assertEq(cfg.maxDriftBps, 500);\n        assertEq(cfg.panelSize, 30);\n        assertEq(cfg.quorum, 20);\n        assertEq(cfg.windowHours, 1);\n        assertEq(cfg.boolAnswerType, 0);\n    }\n}","reproduction":"State: an EVM where 0xf41b...a0c0 (hook), 0x0000...8a90 (PoolManager), 0x1397...ea56 (Intake) and 0xd34a...63b7 (IMD) have no code (the protected floor's setUp). Input: create2 of CabalGate creation code ++ the 19 manifest words (or the current 13). Expected: the gate deploys and hook()/cabal()/poolManager()/configuration() return the supplied words. Actual: the first external call launchHook.initialized() reverts (no code at the callee), so create2 returns 0 and the probe reverts 'application constructor failed'. Run: forge test --match-path test/scratch/Proof_ConstructorNeedsChainState.t.sol -> [FAIL: application constructor failed].","severity":"high","snippet":"        if (!launchHook.initialized()) revert InvalidConfig();","title":"Constructor needs live chain state (hook calls and code-length checks), so the launch check's empty-EVM deployment reverts"},{"citation":"resolved","description":"The committed manifest lists 13 constructorArgs (hook, $owner, intake, imd, signer, action, limits) and its notes state 'The constructor requires an initialized hook and obtains poolManager, poolKey and CABAL from it; Intake and IMD must have code', which is the behaviour the brief forbids. The brief's manifest has 19 words in the order hook, poolManager, cabal, currency0, currency1, fee, tickSpacing, $owner, intake, imd, signer, action, maxBuyAmount, maxSellAmount, maxImpactBps, maxDriftBps, panelSize, quorum, windowHours. Once the constructor is rewritten, a manifest with 13 words makes the constructor's ABI decoding revert (too little data), and a manifest left as is reproduces the launch 990 failure. The notes also must stop asserting the hook is read in the constructor. Everything else in the file is schema-valid: kind evm_contracts, one contract named CabalGate, strings everywhere, notes under 4000 characters, no extra keys.","line":6,"path":"launch.json","reproduction":"Input: the current launch.json constructorArgs (13 strings) with the brief's 19-parameter constructor. Expected: 19 ABI words, one per parameter in declaration order. Actual: 13 words; the constructor's argument decoder reverts on short data (and with the current constructor the deployment reverts for the reason in the high finding). Verification: compare launch.json lines 7-19 (13 entries) with the brief's list (19 entries); the second entry is $owner where the brief's second entry is the PoolManager 0x000000000004444c5dc75cb358380d2e3de08a90.","severity":"medium","snippet":"      \"constructorArgs\": [","title":"launch.json still carries the 13-word constructor that parked launch 990, not the brief's 19 words"},{"citation":"resolved","description":"_configure only requires quorum != 0, quorum <= panelSize and panelSize <= 1000. The oracle's request body (oracle-consumer skill, 'The body') accepts panelSize and quorum only in 2..300 with quorum <= panelSize; a body outside that range is refused (status 1), no callback is made and the price is spent. The gate copies cfg.panelSize and cfg.quorum into the body verbatim (QuestionBuilder.build). So a configuration with quorum 1, or panelSize 301..1000, is accepted on chain and makes every subsequent submission pay the Intake price for a request that can never be answered; the requester discovers this only after the one-hour deadline and clears the request without refund. test/AdversarialOracle.t.sol line 237-240 even pins (panelSize 1000, quorum 1000) as an accepted edge. The owner is trusted, but the gate already validates these fields, and validates them against the wrong range. Minimal fix: require 2 <= cfg.quorum && cfg.panelSize <= 300 (the launch values 30/20 are inside).","line":222,"path":"src/CabalGate.sol","reproduction":"State: the gate as deployed (panelSize 30, quorum 20). Call: owner configure(cfg) with cfg.quorum = 1 (or cfg.panelSize = 1000, cfg.quorum = 1000). Expected: revert InvalidConfig. Actual: accepted, configVersion increments. Then ALICE submitBuyRequest(100e18, 'reason'): 0.5 IMD is pulled and forwarded to the Intake, the emitted body contains \"quorum\":1 (or \"panelSize\":1000), which the oracle refuses; no onOracleResult is ever delivered, ALICE's slot stays occupied until block.timestamp >= deadline (1 hour) and clearRequest returns nothing.","severity":"low","snippet":"                || cfg.quorum > cfg.panelSize || cfg.panelSize > 1000 || cfg.windowHours == 0 || cfg.windowHours > 24","title":"configure accepts panelSize/quorum values the oracle refuses, so every request under such a config burns its 0.5 IMD with no callback"},{"citation":"resolved","description":"GateLaunchFixture.setUp etches a MockLaunchHook at the hook address and MockIntake/MockERC20 at the Intake and IMD addresses before every deployment, and test_constructorRequiresHookInitializedAndDependencyCode (lines 196-211) asserts that deployment FAILS when any of those has no code, which is the opposite of what the launch floor requires. That is how a constructor that cannot run in the launch checks passed 162 local tests. The brief asks for a test that deploys the gate with the manifest words where no code exists at the hook, intake, IMD or PoolManager addresses and asserts success, followed by mock-hook tests of the submission-time binding checks (request succeeds once hook.gate() is set; reverts on wrong poolKey, wrong cabal, wrong imd, unset gate) and of setGate accepting the gate once and refusing a second. None of these exists today; the scratch proof attached to the high finding is the first of them.","line":71,"path":"test/GateLaunch.t.sol","reproduction":"Run forge test --match-path test/GateLaunch.t.sol: all pass. Remove the three vm.etch lines (71-73) or run the attached scratch proof: the constructor reverts. Expected: a passing test with no code at HOOK, INTAKE, IMD and the PoolManager, mirroring Contracts.protected.t.sol. Actual: test_constructorRequiresHookInitializedAndDependencyCode at line 196 expects 'application constructor failed' in that state.","severity":"low","snippet":"        vm.etch(HOOK, address(new MockLaunchHook(hookOwner)).code);","title":"Launch rehearsal tests etch mock code at the dependency addresses, so the suite never exercises the empty-EVM state the launch checks run in"},{"citation":"resolved","description":"forge inspect src/CabalGate.sol:CabalGate deployedBytecode is 23,967 bytes (limit 24,576; the protected floor asserts this). The adaptation adds a keccak256(abi.encode(hook.poolKey())) comparison in _submit, a PoolKey built from constructor words and extra validation, all of which grow the runtime. If the limit is crossed the floor fails with 'runtime exceeds EIP-170'. mainnetConfig() (lines 169-189) is a view that nothing on chain or in production calls and is a safe place to recover bytes if needed; the brief otherwise forbids other changes. Init code is 36,970 bytes plus 19*32 = 37,578, well under 49,152.","line":169,"path":"src/CabalGate.sol","reproduction":"Measurement on the current tree: forge inspect src/CabalGate.sol:CabalGate deployedBytecode | wc -c -> 23,967 bytes of runtime. Expected after adaptation: <= 24,576. Actual: unknown until built; re-measure and include the number in the adaptation notes.","severity":"info","snippet":"    function mainnetConfig(uint128 maxBuy, uint128 maxSell, uint16 impact, uint16 drift)","title":"Runtime is 609 bytes under EIP-170; the required submission-time poolKey check and the 19-word constructor must be measured against the limit"},{"citation":"resolved","description":"The evm-contracts launch supports constructor arguments of type address, uint8..uint256, bool and bytes32 only. The brief's tickSpacing word ('60') feeds PoolKey.tickSpacing, which is int24. If the new constructor declares the parameter as int24, the manifest/ABI validation refuses it. Declare it as uint24 (or uint8) and cast to int24 when building the key; 60 fits either way and the ABI word is identical. fee is uint24 and needs no change.","line":127,"path":"src/CabalGate.sol","reproduction":"Input: a constructor with parameter 'int24 tickSpacing'. Expected: manifest accepts '60'. Actual: the policy's supported-type list excludes signed integers, so the contract entry is rejected before deployment. With 'uint24 tickSpacing' and int24(uint24(tickSpacing)) inside, the same word deploys.","severity":"info","snippet":"    constructor(","title":"PoolKey.tickSpacing is int24; the constructor must declare it as an unsigned word because the launch ABI forbids signed integers"},{"citation":"resolved","description":"The live hook (bytecode read from mainnet on 2026-10-09, same 10,034-byte runtime as the repo's CabalHook, differing only in immutables) binds a gate once and refuses any replacement. Today the gate's key cannot be wrong because the constructor copies it from the hook; after the adaptation the key comes from manifest words. If a word is wrong (fee 3000, tickSpacing 10, currencies swapped relative to the brief's check) the gate still deploys, setGate still accepts it (it only compares hook() and cabal()), and then the brief's _submit check keccak256(abi.encode(hook.poolKey())) == keccak256(abi.encode(_key)) makes every request revert InvalidConfig with no recovery path, since the hook refuses a second gate. The manifest words in the brief match the live key, so this is a procedural guard: before the one-time setGate, the hook owner should recompute keccak256(abi.encode(hook.poolKey())) and compare it with the key the gate was built from (a test in the adaptation can assert it from the same constants), not just gate.hook() and gate.cabal().","line":116,"path":"src/CabalHook.sol","reproduction":"State (post-adaptation): gate deployed with currency0 = CABAL, currency1 = IMD, fee = 3000, tickSpacing = 60, hook = live hook. Call: hook owner setGate(gate). Expected: refused. Actual: accepted (hook() and cabal() match). Then any submitBuyRequest reverts InvalidConfig forever and hook.setGate(otherGate) reverts InvalidGate. Today's code is not affected because _key is read from the hook.","severity":"info","snippet":"                || address(IGateBinding(candidate).hook()) != address(this)","title":"hook.setGate checks only hook() and cabal(); once the key is constructor-supplied, a gate with a wrong fee/tickSpacing/currency order can be bound forever"}],"hash":"8913887051c330dd2a2f9cd701148f0418bc55289dfc8ccc5f5553fd0b45fa34","nodeId":"cf09d78d-66be-4a82-b1c3-44ac4f111b2d","outcome":"completed","summary":"Review complete. Findings are in `.imd-findings.json` (7 findings, one with a proof). No tracked file was changed; the only writes are the findings file and the scratch proof, both git-ignored.\n\n**What was read.** Every source file in `src/` (CabalGate, CabalHook, CabalCoin, QuestionBuilder, ImpactEstimator, HookFlags, the five libraries, IIntake), the full test suite, launch.json, ADAPTATION.md, docs, and the pinned skills and protected floor test. The suite builds and all 162 tests pass. I also read the live mainnet hook and Intake over a public RPC: gate is unset, the owner is 0xFc3C…1774, the pool key and PoolManager match the brief, the price is 0.5 IMD, and the live hook runtime is byte-for-byte the repo's CabalHook apart from immutables. Nothing was unreachable.\n\n**Findings, most severe first.**\n\n- **High, src/CabalGate.sol:142.** The constructor calls the hook (initialized, poolManager, cabal, poolKey, imd) and requires code at intake and IMD. In the launch floor's empty EVM the first call reverts and the probe reports \"application constructor failed\", which is why launch 990 parked. The proof in `test/scratch/Proof_ConstructorNeedsChainState.t.sol` deploys the gate with the brief's 19 manifest words and no code at any dependency address. It fails today for that reason and passes once the constructor makes no external calls or code checks.\n- **Medium, launch.json:6.** The committed manifest still lists the 13 old words and its notes describe the hook-reading constructor. Against the 19-parameter constructor the words decode short, and left as is it reproduces the parked outcome.\n- **Low, src/CabalGate.sol:222.** The owner can configure quorum 1 or panelSize up to 1000. The oracle only accepts 2 to 300, so every request under such a config pays 0.5 IMD and is never answered.\n- **Low, test/GateLaunch.t.sol:71.** The launch rehearsal etches mock code at the hook, Intake and IMD addresses, and one test asserts deployment must fail without that code. The suite therefore never ran in the state the launch checks use, and none of the brief's required tests exist yet.\n- **Info.** Runtime is 23,967 bytes, 609 under EIP-170, before the adapter adds the submission-time pool-key check. The tickSpacing word must be declared unsigned since the launch ABI forbids signed integers. The live hook's one-time setGate only compares hook() and cabal(), so a gate built from a wrong key word would be bound irreversibly; the hook owner should compare the key hash before binding.\n\n**Trust assumptions, not defects.** The owner can swap the Intake, signer and verifier, and a user pays whatever the configured Intake quotes. Signatures are ECDSA-only, so an ERC-1271 registry signer would never verify. Refused or undecided oracle requests are never refunded. All three are already recorded in ADAPTATION.md.\n\nThe runtime paths of the gate (request, callback, execution, settlement, fee accounting, replay protection) held up against the checklist. I found no loss-of-funds or accounting defect there.","treeHash":null,"usage":{"cachedInputTokens":1973899,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":35306,"runtime":"claude","turns":45,"wallClockMs":727309}},{"artifacts":[],"attempt":1,"bundleHash":"844a248234557a231ddc0116d76796a25b029b24927d20c406e48dded2f0147e","device":"559cfaaab2c0d013","findings":[{"description":"The constructor deploys QuestionBuilder (5,888 bytes of runtime) and ImpactEstimator (3,737 bytes) beside the gate's own 24,443-byte runtime, so one factory call deposits 34,068 bytes of code. Measured through the rehearsal factory with the manifest's nineteen words this is 7,945,238 gas for the deploy call. The protected floor does not bound gas; the deployment service 'enforces its gas ceiling', whose value is not stated in the brief. This is not a defect in the gate and no test can decide it; it is recorded so the manifest and deployment steps can confirm the ceiling exceeds roughly 8 million gas before launch 990 is retried. The gate runtime is also 133 bytes below the EIP-170 limit, so any further source growth must be matched by removals.","line":169,"path":"src/CabalGate.sol","reproduction":"Deploy CabalGate by CREATE2 from a factory with the nineteen manifest words (hook 0xf41b…a0c0, poolManager 0x0000…8a90, cabal/currency0 0x450e…33be, currency1/imd 0xd34a…63b7, fee 12500, tickSpacing 60, owner, intake 0x1397…ea56, signer 0x5598…2982, action bytes32('oracle.request@oracle-1'), 1e24, 1e25, 300, 500, 30, 20, 1) on chain id 1 in an empty EVM, measuring gasleft() around the factory call. Expected: the deployment fits the deployment service's gas ceiling. Actual: 7,945,238 gas for the deploy call (Foundry 1.8.3, solc 0.8.26, via-IR, 200 runs, cancun); whether that fits is unknown from the brief.","severity":"info","title":"Launch deployment of CabalGate costs about 7.95 million gas because the constructor creates two helper contracts"}],"hash":"b12f04a3e5ebac41a14bb3b55fb69d365ba6d987a6d0028cb63d7e2ff4666d0a","nodeId":"b2c57e4b-76b8-476d-96f1-b8d268c0bdef","outcome":"completed","summary":"The findings file exists, parses, and is excluded by the harness's own exclude list, as expected. Everything is verified, so the work is complete.\n\n## Outcome\n\n`forge build` and `forge test` pass: 179 tests across 29 suites, 0 failed, 0 skipped. The 166 existing tests were left untouched. I added one new test file and a README entry.\n\n**The brief's required tests already existed** in `test/GateLaunch.t.sol` (empty-EVM deployment, mock hook, request only after binding, refusals on wrong key/cabal/imd/gate, one-time `setGate`). So the new work is adversarial coverage beyond them, in `test/GateLiveHook.t.sol`:\n\n- **Real hook code at the live address.** The live address `0xf41b…a0c0` carries exactly CabalHook's three permission bits, so the real CabalHook runtime is placed there in the test EVM and the launch-953 `beforeInitialize` call is replayed from the PoolManager's address. This pins the real `setGate` checks and the real five-word `poolKey()` encoding that the gate hashes, which the mock only models. Nothing is deployed to any chain.\n- **Real binding paths.** Non-owner refused, codeless and getter-less candidates refused, swapped-role gate refused, deployed gate accepted once with the `GateBound` event, second gate and rebinding refused.\n- **Full request flow on the live addresses.** Buy and sell refused before binding without touching the intake, then accepted, followed by an approval, a rejection, replay of a consumed attestation against the same and a different request, and a clear.\n- **Failure paths.** Hook with no code, `poolKey()` reverting, same key in a different ABI encoding, chain id 4663, and owner reconfiguration onto the wrong IMD or an invalid drift bound. Each refusal is checked to cost the user nothing.\n- **Fuzzing.** 512 runs each over every pool-key field and over the CABAL, IMD and gate reads: acceptance only on exact equality, refusal otherwise, and recovery once the reads match again.\n- **Inert gate in the empty EVM.** Submissions and reconfiguration revert while two-step ownership still works.\n\n**No defect found in the gate.** One informational note went to `.imd-findings.json`: the launch deployment costs about 7.95 million gas because the constructor creates two helper contracts, and the brief does not state the deployment service's gas ceiling. That is for the manifest and deployment steps to confirm, not something a test can decide.\n\nTwo of my first drafts failed for harness reasons, not contract reasons: `expectRevert` latched onto a preceding external call, and `clearMockedCalls` also dropped the PoolManager mocks. Both are fixed in the committed file.","treeHash":"e8fdd37b8d6cfb785a1af6f35ce3249fabf34437","usage":{"cachedInputTokens":2442131,"inputTokens":610,"model":"claude-fable-5-1","outputTokens":42398,"runtime":"claude","turns":47,"wallClockMs":1027037}},{"artifacts":[],"attempt":1,"bundleHash":"84fa29d4ea7d202b08427ee7885d0682642d61d53fd471154e1822dc0c8a6e8e","device":"1507f63d3f1b973a","findings":[],"hash":"b4e5abf2067edc74fe2b74e0163c4df0fe2aec7d1cde251ec22d85a0e0d65d4c","nodeId":"14e85cbb-2386-4e83-b3e4-1251524e603c","outcome":"completed","summary":"","treeHash":"c471222cac5aeff6b3a57f07d4fec47c5cfa33f4","usage":{"cachedInputTokens":7560670,"inputTokens":1860,"model":"claude-fable-5-1","outputTokens":58831,"runtime":"claude","turns":61,"wallClockMs":1548393}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"1ca477e8d9b58040","findings":[],"hash":"b6d59b65bce1cac74a33f1de0b2745a6cd9711017d4eb9bbc6c9c64721d74069","nodeId":"316cf0c0-bac5-420a-85c7-2e245369124b","outcome":"completed","summary":"The review is complete. The findings file is valid JSON, the scratch directory is removed, and the working tree is otherwise untouched.\n\n**Outcome: no substantiated defects in the Economic Security, Invariant or Flow Gap areas.** The file `.imd-findings.json` holds an empty findings list and 33 coverage rows: one for each of the 28 listed entry points, plus five invariants I checked.\n\n**What I verified**\n\n- **Value conservation.** The gate ends every transaction with zero token balances and zero allowances. Buys pull input plus fee, send input to the pool and fee to the hook. Sells pull CABAL, take the fee from the IMD output, and forward the rest. The oracle price is pulled and forwarded exactly, with a balance delta check that rejects fee-on-transfer or pretend-success tokens.\n- **Fee economics.** The gate's fee base matches the hook's (input for buys, IMD output for sells), so the return-value equality cannot fail on a full fill. Burn and protocol-owned liquidity legs are equal. Trades under 400 wei pay zero fee, but each request costs 0.5 IMD, so there is no profitable amplification.\n- **Price protection.** Only the gate can swap, so third parties cannot move the price. Liquidity changes and other approved trades can only make an execution revert, never worsen a fill past the requester's minimum. The impact and drift caps are re-measured at execution.\n- **Oracle flow.** Attestations are consumed once, bound to the stored question and window, signed for this gate's domain, and accepted only from the snapshot intake before the deadline. A \"no\" answer is stored, not reverted.\n- **Request state machine.** The active-request lock, clear paths, config-version invalidation and approval expiry are consistent across all writers.\n- **Launch.** The constructor makes no external calls, the nineteen manifest words match the live hook values in declaration order, and the empty-EVM rehearsal passes.\n\n**Probes I ran.** All 166 existing tests pass. Scratch tests confirmed repeated sells crossing the hook's own liquidity settle cleanly in both token orderings, a one-wei approved sell reverts with PartialFill (self-harm only), and a dust buy pays no fee.\n\n**Not reached.** No mainnet fork was available, so the live hook's actual pool key, IMD address and unbound gate state remain as the brief reports them. The hook owner should still compare the hook's reported pool key hash with the manifest words before the one-time binding, as the deployment notes already instruct.","treeHash":null,"usage":{"cachedInputTokens":1765917,"inputTokens":450,"model":"claude-fable-5-1","outputTokens":44011,"runtime":"claude","turns":37,"wallClockMs":764319}},{"artifacts":[],"attempt":1,"bundleHash":"1ac9f452fd96f5e448a1910c27238e5182ff7309440ba7d233fac1f2b62a823e","device":"707624586655cf74","findings":[],"hash":"cc40001ab6260e632d144bee4222ecccdbf27500f2125106a54bc69f38f6b7e6","nodeId":"4010b189-0512-42e1-96bc-f23a082b9813","outcome":"completed","summary":"Done. I wrote launch.json as the only changed file, and it describes the accepted CabalGate exactly.\n\n**What the manifest contains**\n- Kind \"evm_contracts\", one contract entry named CabalGate, and a notes string under 4000 characters. No other keys.\n- The 15 constructor arguments the operator fixed, in that order: hook, poolManager, cabal, $owner, intake, imd, signer, action, maxBuyAmount, maxSellAmount, maxImpactBps, maxDriftBps, panelSize, quorum, windowHours.\n- Notes explain that only the gate deploys for the live hook from launch 953, that the gate derives the pool key from the sorted cabal and imd words with the constant fee and tick spacing, that the constructor makes no external calls, and that the hook owner must call setGate once after launch.\n\n**How it was checked**\n- The accepted source constructor in src/CabalGate.sol declares exactly these 15 parameters, and docs/DEPLOYMENT.md lists the same values, so the earlier parked attempt's 19-word mismatch is gone.\n- A Python check confirmed the schema shape: only the three allowed keys, a unique identifier under 32 characters, 15 string arguments all static words or $owner, and notes within the limit.\n- A scratch test in test/scratch parsed the manifest's own strings, ABI-encoded them as static words, and deployed CabalGate through a create2 probe modeled on the protected harness in an EVM where the hook, pool manager, intake and imd addresses have no code. It deployed, the owner and immutables matched, and runtime size stayed under the EIP-170 limit.\n- The full accepted suite ran clean. Only the scratch test is untracked beyond launch.json, and it is discarded before submission.\n\n| Check | Result |\n| --- | --- |\n| forge build | success |\n| forge test, accepted suite | 167 passed, 0 failed |\n| scratch manifest rehearsal | 1 passed |\n\nNext step after acceptance is the service-side deployment, followed by the hook owner at 0xFc3C…1774 calling setGate with the deployed gate once.","treeHash":"27a3d5c03e964df7ede626eebc021ab5b436171a","usage":{"cachedInputTokens":322443,"inputTokens":226,"model":"claude-fable-5-1","outputTokens":6288,"runtime":"claude","turns":8,"wallClockMs":441431}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"dd2ee4882a1be950","findings":[{"citation":"resolved","description":"The assignment fixes the launch manifest to nineteen constructorArgs in this order: hook, poolManager, cabal, currency0, currency1, fee, tickSpacing, initialOwner, intake, imd, signer, action, maxBuyAmount, maxSellAmount, maxImpactBps, maxDriftBps, panelSize, quorum, windowHours. The compiled constructor (ABI in out/CabalGate.sol/CabalGate.json) has fifteen inputs: launchHook, manager, cabalToken, initialOwner, intake, imd, signer, action, maxBuyAmount, maxSellAmount, maxImpactBps, maxDriftBps, panelSize, quorum, windowHours. currency0/currency1 are derived by sorting cabal and imd, and fee/tickSpacing are the constants POOL_FEE and POOL_TICK_SPACING. ADAPTATION.md states that an operator instruction reduced the list to fifteen because the manifest allows at most sixteen words, but the brief that drives the manifest step still lists nineteen and no launch.json exists in the tree to reconcile them. If the manifest step transcribes the brief, the factory appends nineteen words: the constructor decodes word 3 (currency0 = CABAL) as initialOwner, word 5 (fee 12500) as imd, and word 8 (the intake address) as uint128 maxBuyAmount, whose ABI range check reverts, so the protected probe fails with 'application constructor failed' and the launch parks exactly as launch 990 did. Consequence: the gate is never deployed or bound and no request is possible; no funds are at risk. Either the manifest must be written with the fifteen words documented in docs/DEPLOYMENT.md (hook, poolManager, cabal, $owner, intake, imd, signer, action, 1000000000000000000000000, 10000000000000000000000000, 300, 500, 30, 20, 1) or the constructor must accept the nineteen the brief names. Note the runtime is 24,522 bytes, 54 bytes under EIP-170, so restoring four parameters is not free.","line":139,"path":"src/CabalGate.sol","reproduction":"test/scratch/BriefWords.t.sol (forge test --match-path test/scratch/BriefWords.t.sol): a CREATE2 factory with the protected probe's checks deploys type(CabalGate).creationCode ++ abi.encode(0xf41b6ff942a082c0d320a0c151310ac2a922a0c0, 0x000000000004444c5dc75cb358380d2e3de08a90, 0x450e5910decee15c3ac056e3ed66cb5ea3dd33be, 0x450e5910decee15c3ac056e3ed66cb5ea3dd33be, 0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7, 12500, 60, owner, 0x1397434cd35e8a9c8ac312a61d3a285eb31dea56, 0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7, 0x5598aa9146215bc13eb26f2c692ad1461fd32982, 0x6f7261636c652e72657175657374406f7261636c652d31000000000000000000, 1e24, 1e25, 300, 500, 30, 20, 1) (19 words, 608 bytes). Actual: revert 'application constructor failed'. Expected per the brief: the gate deploys. The same creation code with the fifteen words (hook, poolManager, cabal, owner, intake, imd, signer, action, uint128 1e24, uint128 1e25, 300, 500, 30, 20, 1) deploys and hook() returns 0xf41b...a0c0. The scratch test passes as written because it asserts the revert; it demonstrates the mismatch rather than serving as a fix-gating proof.","severity":"medium","snippet":"    constructor(\n        CabalHook launchHook,\n        IPoolManager manager,","title":"Constructor takes 15 words but the brief's manifest constructorArgs supply 19: deploying with the brief's arguments reverts"},{"citation":"resolved","description":"Economic griefing vector, recorded so the judge sees it was costed rather than missed. Price moves only through gate executions (the hook refuses every other swap), each bounded to maxImpactBps = 300 bps of its own movement. Two approved buys from two attacker addresses (one active request per address) executed before a victim's execution move the price more than maxDriftBps = 500 bps from the victim's submission price. The victim's executeBuyRequest then reverts LimitExceeded for the rest of its five-minute window, and the victim can only clearRequest after approvedUntil and pay the oracle price (0.5 IMD) again. Attacker cost: two oracle fees, 1.25% LP fee plus 0.5% hook fee on enough volume to move the price about 5% (in the fixture, 2 x 140,000 IMD against 10,000,000e18 seed liquidity), exposure to the moved price, and the panel must approve the attacker's reasons. Victim loss: 0.5 IMD and time; no principal. The existing test test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap exercises exactly this and accepts it as the price of not stranding approvals on every ordinary trade. No code change is recommended; the owner can tighten maxDriftBps through configure if griefing is observed.","line":400,"path":"src/CabalGate.sol","reproduction":"Fixture of test/Trading.t.sol, second half of test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap with maxDriftBps = 300: BOB submits a 1000 IMD buy and is approved; CAROL executes two approved 140,000 IMD buys; priceMovement(request.sqrtPriceX96, current) > 300; BOB's executeBuyRequest reverts LimitExceeded although his approval is unexpired; BOB must wait for approvedUntil, call clearRequest, and resubmit paying intake.price() again. With the live 500 bps cap the same sequence needs about 5% of movement.","severity":"info","snippet":"        if (priceMovement(r.sqrtPriceX96, current) > cfg.maxDriftBps) revert LimitExceeded();","title":"Other users' approved trades can strand a victim's approval through the 500 bps drift cap (documented trade-off, cost quantified)"}],"hash":"d15b5e33b31ff0dc11e287263c2b562170b767d37eb7a89081c1a4feb6832b9e","nodeId":"316cf0c0-bac5-420a-85c7-2e245369124b","outcome":"completed","summary":"Review complete. No tracked file was changed. The findings file is at `.imd-findings.json` with two findings and a coverage row for all 28 listed entry points plus four invariants.\n\n**Outcome**\n\n- **Medium: constructor argument count does not match the brief.** The compiled constructor takes fifteen words. The brief's manifest `constructorArgs` lists nineteen (it still carries currency0, currency1, fee and tickSpacing). Deploying the creation code with those nineteen words reverts with \"application constructor failed\", so a manifest transcribed from the brief parks the launch exactly as launch 990 did. I reproduced it in a scratch test that deploys with both lists. ADAPTATION.md and docs/DEPLOYMENT.md attribute the fifteen-word list to an operator instruction, but nothing in the tree reconciles that with the brief, and no launch.json exists yet. Either the manifest must use the fifteen documented words or the constructor must match the brief. The runtime is 54 bytes under the EIP-170 limit, so restoring four parameters is not free.\n- **Info: drift-cap griefing, costed.** Two attacker addresses executing approved buys of up to 300 bps each push a victim's submission price past the 500 bps drift cap, stranding that approval until it expires and costing the victim another oracle fee. The attacker pays two oracle fees, 1.75% in fees on roughly 5% of price movement, and needs panel approval. The existing Trading test already exercises this and accepts it. No code change recommended.\n\n**Area coverage (Economic Security, Invariant, Flow Gap).** I traced the full request lifecycle and found it sound: hook identity checks run before any payment, the oracle price is pulled and forwarded exactly with allowance reset, each attestation is consumed once, buy and sell fees match the hook's `finishSwap` computation, the trade's own impact and the drift since submission are both re-measured on live pool state, the gate holds no tokens or allowances after any transaction, and `activeRequest` is set exactly when a request is Pending or Approved. Config versioning invalidates stale approvals without refunding oracle fees, which is documented. All 167 existing tests pass under Foundry 1.8.3 and solc 0.8.26. The live hook was traced only as the gate's counterparty since it is out of scope for change.\n\n**Not reached.** Live mainnet pool state (liquidity depth, current tick) was not inspected, so the submission-time impact estimate against the real pool is unverified. No fork or static analysis beyond the supplied tool output was run.","treeHash":null,"usage":{"cachedInputTokens":2032730,"inputTokens":418,"model":"claude-fable-5-1","outputTokens":47923,"runtime":"claude","turns":33,"wallClockMs":932700}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"771f83f312eace21","findings":[{"citation":"resolved","description":"Asymmetry between the two writers of Config (Pashov Access Control: 'for every storage variable written by 2+ functions, find the one with the weakest guard'; Asymmetry step 5: admin variant missing input validation). The constructor (lines 171-187) hard-wires boolAnswerType = 0 and oracleVerifier = address(this), because QuestionBuilder.build always emits \"answerType\":\"bool\" (QuestionBuilder.sol:100) and CanonicalRequest.hash always hashes \"answerType\":\"bool\" (CanonicalRequest.sol:22), so the live service can only ever answer with answerType 0. The owner path configure() -> _configure() validates every other numeric field but never checks cfg.boolAnswerType; any value 1..255 is stored. After such a configuration every submitBuyRequest/submitSellRequest still runs, still pays the Intake the full 0.5 IMD, and the oracle's genuine attestation (answerType 0) is refused at line 318 (a.answerType != cfg.boolAnswerType) with InvalidAttestation. The Intake does not retry failed callbacks, so the user waits REQUEST_TIMEOUT (1 hour) and clears; the price is never refunded. The same path also lets the owner set oracleVerifier to an arbitrary address while the constructor forces address(this); AdversarialOracle.t.sol:263 shows this is intended, so only boolAnswerType is a pure foot-gun with no legitimate non-zero value. Owner-only, so no unprivileged amplifier: reported as a hardening gap, not a bypass. Minimal fix that preserves the audited design: in _configure add `|| cfg.boolAnswerType != 0` to the InvalidConfig condition (the body and the hash are compiled to bool, so no other value can ever be used).","line":219,"path":"src/CabalGate.sol","reproduction":"Foundry, CabalFixture (gate bound to local hook, owner = test contract). 1) cfg = gate.configuration(); cfg.boolAnswerType = 3; gate.configure(cfg) -> succeeds, configVersion 2, configuration().boolAnswerType == 3. 2) ALICE submitBuyRequest(10 ether, reason) -> succeeds, ALICE pays intake.price() (0.5 IMD live), intake.bodyOf(id) contains '\"answerType\":\"bool\"'. 3) Intake delivers the genuine attestation for that body (answerType 0, true, signed by the configured signer over the gate's domain) -> reverts InvalidAttestation (expected: Approved). 4) ALICE clearRequest(id) before 1 hour -> InvalidRequest; after vm.warp(+1 hours) -> Cleared; ALICE's IMD balance is still minus the oracle price. Reproduced in test/scratch/ConfigureAsymmetry.t.sol::test_configureWithNonBoolAnswerTypeStrandsEveryLaterRequest (passes on the current code, i.e. the misconfiguration is accepted). Expected: configure(cfg with boolAnswerType 3) reverts InvalidConfig like the constructor path effectively does.","severity":"low","snippet":"        if (cfg.oracleVerifier == address(0)) cfg.oracleVerifier = address(this);\n        if (\n            cfg.intake == address(0) || cfg.imd == address(0) || cfg.signer == address(0) || cfg.action == bytes32(0)","title":"configure() accepts boolAnswerType != 0 (and a foreign oracleVerifier) that the constructor forbids; one mistaken owner call strands every later request's oracle payment"},{"citation":"resolved","description":"Documented in docs/DEPLOYMENT.md ('a malicious owner-selected Intake can charge up to the user's available balance and allowance'), so this is recorded as the trust assumption the launch rests on rather than as a bypass. Two distinct privileged parties sit behind the quoted price: the gate owner ($owner) chooses cfg.intake via configure(), and the Intake's own owner (read live: 0x047F606fD5b2BaA5f5C6c4aB8958E45CB6B054B7, neither the gate owner nor the hook owner 0xFc3C...1774) sets priceOf(action, imd), currently 500000000000000000. The gate pulls `price` from msg.sender with no `maxPrice` argument and no configured ceiling, and the project's own fixtures (CabalFixture._setup, GateLaunch._fund) approve the gate for type(uint256).max, which is also what most wallets propose. Every request that is refused by the service (status 1 or 2) or whose callback fails also spends this price with no refund. Trigger requires a privileged action (Intake owner raising the price, or gate owner pointing at another Intake), so under the validation gates this is a trust assumption, not a confirmed exploit; it is listed so the judge sees the exact actor and amount. A fix that keeps the agreed ABI is a config ceiling (e.g. revert LimitExceeded when price > maxBuyAmount or a dedicated cap), but any new Config field changes the struct the brief says must stay as audited, so this is a scope decision for the author.","line":281,"path":"src/CabalGate.sol","reproduction":"Live state (2026-10-09, block 26152283): Intake 0x1397434c...dea56 priceOf(0x6f7261636c65...0000, 0xd34a...63b7) = 500000000000000000; Intake.owner() = 0x047F606fD5b2BaA5f5C6c4aB8958E45CB6B054B7. Mainnet-fork rehearsal (test/scratch/ForkRehearsal.t.sol): gate deployed with the 19 manifest words, hook.setGate(gate) by hook.owner(), user approves IMD type(uint256).max, submitBuyRequest(10e18, ...) -> exactly 0.5 IMD leaves the user. Failing state: with MockIntake.setPrice(user's full IMD balance) (or the live Intake owner calling its price setter) the same submitBuyRequest(10e18, ...) pulls the user's entire IMD balance for a single request; the gate has no check between priceOf and _pullExact. Expected by a user: a bounded, displayed price; actual: unbounded pull up to allowance.","severity":"info","snippet":"        uint256 price = IIntake(cfg.intake).priceOf(cfg.action, cfg.imd);\n        uint256 beforePayment = payment.balanceOf(address(this));\n        _pullExact(payment, msg.sender, price);","title":"Trust gap (access x economics): submission pays whatever the owner-selected Intake quotes, with no user- or config-side price cap; the live Intake's price is set by a third party (0x047F...54B7), not "}],"hash":"d8aa5a46cb819230769407d639cfb503ac3df358048f0526ed01ba22d51353fa","nodeId":"0a92b515-7177-44b4-bfee-e6301cb6a1e2","outcome":"completed","summary":"The review is complete and `.imd-findings.json` is written with 2 findings and 29 coverage rows covering all 28 listed entry points plus two invariants. No source files were changed. The only files I created are the findings file and two investigation tests under the gitignored `test/scratch/`.\n\n**Outcome.** The gate's permission model holds. Every state-changing entry point has the guard its effect needs, both Config writers reach the same validation except for one field, and the launch handoff works against the live chain.\n\n**What I verified beyond reading the code**\n\n- The full suite passes. 166 tests, 0 failures.\n- Live mainnet state at block 26152283 matches the brief's words. The hook's owner is 0xFc3C…1774, its gate is unset, it is initialized, and its CABAL, IMD and pool key equal the manifest values. The Intake quotes 0.5 IMD. Every dependency address has code.\n- The live hook's runtime bytecode is byte-identical to the compiled `src/CabalHook.sol` apart from the two immutables, so the test mocks model the real `setGate`.\n- On a mainnet fork, the gate deployed from the 19 words, the real hook accepted it via `setGate` from its owner, and a 10 IMD buy went through the real Intake. Exactly 0.5 IMD left the user, the allowance returned to zero, and a second request was refused as active.\n- Sells currently estimate 10000 bps on the live pool because it is one-sided with no liquidity below the current tick. Buys above roughly 40 IMD exceed the 300 bps cap. This is chain state and launch design, not a gate defect, and the owner can retune the limits.\n\n**Findings**\n\n1. **Low.** `configure` accepts any `boolAnswerType`, while the constructor hard-wires zero and the body and canonical hash always say bool. A single mistaken owner call makes every later request pay 0.5 IMD and never be answerable. Reproduced in a scratch test. Suggested fix is one extra clause in the shared validation.\n2. **Info.** Submission pays whatever the configured Intake quotes with no cap. The live Intake's price is controlled by a third party distinct from both the gate and hook owners. This is already documented in the deployment notes, so it is recorded as the trust assumption with the exact actor and amounts.\n\n**Not covered.** No findings carry a proof file, since neither is critical or high. I did not simulate the oracle writer's callback against the real Intake. The existing live-vector test pins that format.","treeHash":null,"usage":{"cachedInputTokens":1834598,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":47695,"runtime":"claude","turns":39,"wallClockMs":1069083}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"56e50117311155be","findings":[],"hash":"ddf3874cbb2397b677b9039ce795daf639d37d7736255b8d346194ee9ad07f2e","nodeId":"4010b189-0512-42e1-96bc-f23a082b9813","outcome":"failed","summary":"needs input: The accepted src/CabalGate.sol constructor takes nineteen flat static words in the order the brief fixed (hook, poolManager, cabal, currency0, currency1, fee, tickSpacing, initialOwner, intake, imd, signer, action, maxBuyAmount, maxSellAmount, maxImpactBps, maxDriftBps, panelSize, quorum, windowHours). The launch manifest schema rejects any constructorArgs list longer than sixteen entries (launch_manifest check: 'contracts.0.constructorArgs: Too big: expected array to have <=16 items'). A manifest with sixteen or fewer words would not ABI-encode against the accepted constructor and the factory rehearsal would revert, so no valid launch.json can describe the accepted implementation. The constructor signature must be reduced to at most sixteen parameters, which is a source change outside this manifest-only assignment (only launch.json may be written). — Which reduction of the CabalGate constructor to at most sixteen words do you approve for a new build task before the manifest is written","treeHash":null,"usage":{"cachedInputTokens":685548,"inputTokens":452,"model":"claude-fable-5-1","outputTokens":9616,"runtime":"claude","turns":19,"wallClockMs":493483}}],"verification":[{"checks":[{"durationMs":137332,"exitCode":0,"name":"build","output":"Compiling 120 files with Solc 0.8.26\nSolc 0.8.26 finished in 137.09s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n   --> test/GateFactoryEdges.t.sol:229:5:\n    |\n229 |     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[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[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[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[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: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: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: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[missing-events-access-control]: `_executing` is changed without an event but is used for access control\n    ╭▸ src/CabalGate.sol:430:9\n    │\n430 │         _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:227:9\n    │\n227 │         emit Configured(configVersion, cfg);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\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[non-reentrant-not-first]: `nonReentrant` is not the first modifier\n    ╭▸ src/CabalGate.sol:209:64\n    │\n209 │     function configure(Config calldata cfg) external onlyOwner nonReentrant {\n    │                                                                ━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/non-reentrant-not-first\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/CabalGate.sol:221:90\n    │\n221 │                 || cfg.maxBuyAmount == 0 || 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:222:40\n    │\n222 │                 || 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:284:14\n    │\n284 │           id = IIntake(cfg.intake)\n    │ ┏━━━━━━━━━━━━━━┛\n285 │ ┃             .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:303:9\n    │\n303 │         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:287:13\n    │\n287 │         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:293:24\n    │\n293 │             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:294:23\n    │\n294 │             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:297:21\n    │\n297 │             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:314:35\n    │\n314 │         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:320:74\n    │\n320 │                 || 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:321:20\n    │\n321 │                 || 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:336:38\n    │\n336 │             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:341:9\n    │\n341 │         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:336:31\n    │\n336 │             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:358:33\n    │\n358 │             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:360:33\n    │\n360 │             if (!staleConfig && block.timestamp < r.approvedUntil) revert InvalidRequest();\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:392:13\n    │\n392 │         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:422:9\n    │\n422 │         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:414:44\n    │\n414 │             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[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[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[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:454:26\n    │\n454 │         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[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[incorrect-strict-equality]: dangerous strict equality check on an externally-influenced value\n    ╭▸ src/CabalGate.sol:486:13\n    │\n486 │         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:506:13\n    │\n506 │             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\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":8428,"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 1.07ms (727.19µs CPU time)\n\nRan 1 test for test/Trading.t.sol:ReverseTokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5205711)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 6.65ms (2.77ms CPU time)\n\nRan 1 test for test/GateLaunch.t.sol:GateEmptyEvmLaunchTest\n[PASS] test_gateDeploysInAnEmptyEvmWithTheManifestWords() (gas: 28103301)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 31.59ms (31.41ms CPU time)\n\nRan 2 tests for test/SubmissionGas.t.sol:SubmissionGasTest\n[PASS] test_longestReasonStaysUnderBudget() (gas: 1255354)\n[PASS] test_shortBuyAndSellStayUnderBudget() (gas: 1121472)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 69.16ms (1.47ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64802)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 78629)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9548036)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8196126)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 80854255)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 75.27ms (43.68ms CPU time)\n\nRan 1 test for test/OracleSigner.t.sol:OracleSignerTest\n[PASS] test_registrySignatureIsNotAnEOASignatureForTheConfiguredSigner() (gas: 4988860)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 76.20ms (2.15ms CPU time)\n\nRan 10 tests for test/GateLaunch.t.sol:GateLaunchTest\n[PASS] test_constructorIgnoresDependencyCodeAndHookState() (gas: 16032750)\n[PASS] test_constructorSortsCurrenciesWhenCabalSortsAboveImd() (gas: 12272898)\n[PASS] test_existingHookOwnerBindsGateOnceAndRefusesSecondGate() (gas: 16211054)\n[PASS] test_explicitOwnerControlsConfigurationInsteadOfFactory() (gas: 8303710)\n[PASS] test_factoryDeploysOnlyGateWithAllFifteenManifestWords() (gas: 28629703)\n[PASS] test_flatConstructorRetainsEveryValidation() (gas: 70090067)\n[PASS] test_hookRefusesGateWithSwappedTokenRoles() (gas: 8381586)\n[PASS] test_ownerConfigureKeepsLiveDependencyChecksAndOracleBounds() (gas: 9271118)\n[PASS] test_requestRevertsWhenTheHookReportsAnotherKeyCabalImdOrGate() (gas: 12789852)\n[PASS] test_requestSucceedsOnlyOnceTheHookReportsThisGate() (gas: 14721983)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 78.42ms (77.24ms CPU time)\n\nRan 1 test for test/Trading.t.sol:TokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5202749)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 84.06ms (3.01ms CPU time)\n\nRan 3 tests for test/OracleLatency.t.sol:OracleLatencyTest\n[PASS] test_deliveryAtOldExpiryRetainsFullApproval() (gas: 5330187)\n[PASS] test_deliveryJustBeforeOldExpiryRetainsFullApproval() (gas: 5330275)\n[PASS] test_deliveryJustBeforeRequestDeadlineRetainsFullApproval() (gas: 5330341)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 85.08ms (8.10ms CPU time)\n\nRan 1 test for test/Oracle.t.sol:OracleGasTest\n[PASS] test_callbackFitsBelow200kColdTransaction() (gas: 2041567)\nLogs:\n  callback gas including external call: 78063\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 112.92ms (5.98ms 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, μ: 8083352, ~: 8083328)\nLogs:\n  Bound result 582823731757406\n  Bound result 114\n  Bound result 1\n  Bound result 15\n  Bound result 2\n  Bound result 2\n  Bound result 12\n\n[PASS] test_constructorRejectsDirtyHighBitsInEveryNarrowWord() (gas: 14601379)\n[PASS] test_constructorRejectsTruncatedStaticArguments() (gas: 15941603)\n[PASS] test_factoryOwnerHandoverRequiresAcceptanceAndPreservesBinding() (gas: 8584754)\n[PASS] test_failedConfigurationRollsBackHelpersAndTheAddressStaysFree() (gas: 11144655)\n[PASS] test_helpersAreCreatedByEachGateAndExistingDependenciesStayIntact() (gas: 16181963)\n[PASS] test_hookRejectsMissingCodeWrongHookWrongCabalAndDuplicateBinding() (gas: 8206321)\n[PASS] test_pinnedValidNumericEdges() (gas: 16156965)\n[PASS] test_protocolVectorPinsAllFifteenFieldsTypeStringAndDomain() (gas: 15449)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 118.75ms (117.85ms CPU time)\n\nRan 7 tests for test/HookBinding.t.sol:HookBindingTest\n[PASS] test_buySubmissionRequiresHookHandoffBeforeCharging() (gas: 27895162)\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5623543)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 592316)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 13683664)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 4759768)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 15024101)\n[PASS] test_sellSubmissionRequiresHookHandoffBeforeCharging() (gas: 28432287)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 119.79ms (47.58ms CPU time)\n\nRan 20 tests for test/Trading.t.sol:TradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9628853, ~: 9632205)\nLogs:\n  Bound result 675347137212545513792\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 10000722)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 232962)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23797313)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5185138)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10583304)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5214501)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4637155)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5527912)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13137737)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 57084065)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5335234)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5899496)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117029)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10205744)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5330605)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100513)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 342723)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11484401)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 759.19ms (756.97ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:ReverseOrderLaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64802)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 79085)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9582585)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8196345)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 193196633)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 773.78ms (85.01ms CPU time)\n\nRan 16 tests for test/AdversarialOracle.t.sol:AdversarialOracleTest\n[PASS] testFuzz_malformedSignatureLengthCannotConsumeRequest(uint8) (runs: 1000, μ: 4508869, ~: 4508707)\nLogs:\n  Bound result 99\n\n[PASS] test_attestationIssuedBeforeSubmissionIsRefused() (gas: 4589034)\n[PASS] test_callbackHasNoDependencyOnTokenNftIntakeOrPoolReads() (gas: 4632996)\n[PASS] test_configurationRejectsEveryInvalidBoundaryWithoutAdvancingVersion() (gas: 2307694)\n[PASS] test_everySignedFieldRejectsPostSignatureMutation() (gas: 22129260)\n[PASS] test_explicitVerifierReplacesGateInDomainAndBody() (gas: 4992263)\n[PASS] test_failedOraclePaymentLeavesNoRequestAndCanRetry() (gas: 3886816)\n[PASS] test_identicalReasonFromAnotherUserDoesNotShareAttestation() (gas: 6656069)\n[PASS] test_mainnetDefaultsMatchAssignment() (gas: 65683)\n[PASS] test_rejectedAndClearedIdsCannotReplayOrAlterNewActiveRequest() (gas: 10986234)\n[PASS] test_rejectionReleasesSlotAndResubmissionNeedsFreshDecision() (gas: 7694194)\n[PASS] test_signatureRejectsHighSAndInvalidV() (gas: 4683802)\n[PASS] test_signatureRejectsWrongNameVersionAndDomainChain() (gas: 4860736)\n[PASS] test_timeoutAndApprovalBoundaryAtLastPermittedSecond() (gas: 5220275)\n[PASS] test_zeroOraclePriceAndZeroReturnedIdAreHandledAtomically() (gas: 3808153)\n[PASS] test_zeroVerifierMeansThisGateAndIsStoredResolved() (gas: 3748635)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 905.70ms (890.90ms CPU time)\n\nRan 22 tests for test/Oracle.t.sol:OracleTest\n[PASS] testFuzz_attestationFieldsAreBound(uint8) (runs: 256, μ: 4484627, ~: 4482254)\nLogs:\n  Bound result 3\n\n[PASS] test_280UnicodeCharactersAccepted281Rejected() (gas: 7551946)\n[PASS] test_approvalNeverOutlivesAttestation() (gas: 4530062)\n[PASS] test_attestationCannotBeReusedForAnotherRequest() (gas: 7827776)\n[PASS] test_badSignerDomainAndTampering() (gas: 4810927)\n[PASS] test_bodyIsCanonicalJsonWithConsumerAndStoredEscapedQuestion() (gas: 14363689)\n[PASS] test_configuredPanelParametersFlowIntoBodyAndChecks() (gas: 4966991)\n[PASS] test_controlCharactersAndGuillemetsRejected() (gas: 3946566)\n[PASS] test_intakeFailureUnderpaymentDuplicateIdAndReentry() (gas: 7831170)\n[PASS] test_liveFormatDeliveryWithDistinctOracleIdApproves() (gas: 4551833)\n[PASS] test_malformedUTF8Rejected() (gas: 249860)\n[PASS] test_oldPendingUsesSnapshotIntakeSignerAndDomain() (gas: 5799981)\n[PASS] test_onlyIntakeOnlyPendingReplayAndUnknownIds() (gas: 4644649)\n[PASS] test_oracleClockMayRunSlightlyAheadAndValidityMayBeLong() (gas: 4529958)\n[PASS] test_ownerConfigSnapshotsInvalidatesOldExecutionAndCanClear() (gas: 6130763)\n[PASS] test_questionHashMustMatchStoredQuestionAndWindow() (gas: 6933792)\n[PASS] test_quotesInsideReasonCannotCloseTheDelimiter() (gas: 4381075)\n[PASS] test_sellQuestionIncludesHoldingsPriceBasisTimeNftAndReason() (gas: 11330891)\n[PASS] test_submitPaysExactlyQuotedPriceAndRevokesAllowance() (gas: 3478623)\n[PASS] test_timeoutClearsNoLateCallbackNoTradeFundsEscrowed() (gas: 6655677)\n[PASS] test_trueApprovesForFiveMinutesAndFalseRejects() (gas: 7792671)\n[PASS] test_wrongChainAndSizeAndConcurrentRequestRejected() (gas: 3655634)\nSuite result: ok. 22 passed; 0 failed; 0 skipped; finished in 1.09s (651.11ms CPU time)\n\nRan 7 tests for test/QuestionProperties.t.sol:QuestionPropertiesTest\n[PASS] testFuzz_jsonRoundTripsUntrustedPrintableAscii(bytes,bool,uint128) (runs: 1000, μ: 5063404, ~: 5531791)\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.30s (1.52s CPU time)\n\nRan 20 tests for test/Trading.t.sol:ReverseOrderTradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9663416, ~: 9666790)\nLogs:\n  Bound result 999000000000000001201\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 10034987)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 233434)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23929007)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5219110)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10663702)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5248755)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4637090)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5566932)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13171434)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 15956803)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5342927)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5975313)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117294)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10300540)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5365015)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100508)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 342675)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11588362)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.40s (1.47s CPU time)\n\nRan 5 tests for test/CabalCoin.t.sol:CabalCoinTest\n[PASS] testFuzz_transferConservesSupply(uint256) (runs: 256, μ: 83232, ~: 83381)\nLogs:\n  Bound result 723308838798521366142407038\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.40s (8.56ms CPU time)\n\nRan 7 tests for test/HookBinding.t.sol:ReverseOrderHookBindingTest\n[PASS] test_buySubmissionRequiresHookHandoffBeforeCharging() (gas: 39718738)\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5657872)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 593624)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 24867505)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 15426303)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 26212051)\n[PASS] test_sellSubmissionRequiresHookHandoffBeforeCharging() (gas: 40270758)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.41s (92.80ms CPU time)\n\nRan 7 tests for test/ReasonEscaping.t.sol:ReasonEscapingTest\n[PASS] testFuzz_arbitraryBytesAreJudgedLikeAnIndependentDecoder(bytes) (runs: 1000, μ: 15347, ~: 12700)\n[PASS] testFuzz_oneCorruptedByteIsJudgedLikeAnIndependentDecoder(bytes32,uint16,uint16,uint8) (runs: 1000, μ: 272760, ~: 167905)\nLogs:\n  Bound result 59\n  Bound result 77\n\n[PASS] testFuzz_wellFormedTextOfEveryWidthIsCountedEscapedAndQuotedExactly(bytes32,uint16) (runs: 1000, μ: 2005974, ~: 1796672)\nLogs:\n  Bound result 2\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.41s (4.23s 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, μ: 51388, ~: 51343)\nLogs:\n  Bound result 881970936\n  Bound result 989342897552\n  Bound result 260810894125251729612616\n\n[PASS] testFuzz_repeatedBuySellCannotCreateImd(uint256,uint8) (runs: 1000, μ: 16509580, ~: 17472550)\nLogs:\n  Bound result 14431\n  Bound result 3\n\n[PASS] test_feeAndPriceKnownBoundaries() (gas: 58513)\n[PASS] test_insufficientExecutionAllowancePreservesApprovalAndCanRetry() (gas: 5473149)\n[PASS] test_realTradesAtFeeRoundingEdges() (gas: 23365493)\n[PASS] test_sellApprovalSurvivesBalanceDropAndExecutesOnceRestored() (gas: 9891833)\n[PASS] test_sellLargerThanTrackedHoldingsClearsTheRecordWithoutUnderflow() (gas: 9679049)\n[PASS] test_sellSlippageFailureRollsBackFeePositionAndCostBasis() (gas: 10260848)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.41s (1.37s 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            | 1592  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | clear              | 1546  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | cycle              | 1623  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | donate             | 1668  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | reconfigure        | 1710  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refuseCallback     | 1666  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refusePayment      | 1606  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refuseUnauthorized | 1606  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | request            | 1711  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | resolve            | 1656  | 0       | 0        |\n╰------------------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 256\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 10\n  Bound result 201\n  Bound result 1\n  Bound result 400000\n  Bound result 452\n  Bound result 23336\n  Bound result 17135\n  Bound result 1780\n  Bound result 828417\n  Bound result 518644370033325448\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 64\n  Bound result 8\n  Bound result 3220\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 2116\n  Bound result 3209\n  Bound result 614\n  Bound result 24\n  Bound result 1863\n  Bound result 1782\n  Bound result 7718\n  Bound result 804097473032293133\n  Bound result 4\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 300\n  Bound result 21\n  Bound result 1583\n  Bound result 16866\n  Bound result 1000000000000000000\n  Bound result 498590305761511170\n  Bound result 1\n  Bound result 23\n  Bound result 13\n\n[PASS] test_handlerExercisesPaymentsFailuresBothAnswersAndClearing() (gas: 18841340)\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 7.49s (7.49s 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            | 1485  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1531  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1457  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1556  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1418  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1541  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1503  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1512  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1482  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1504  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1395  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 0\n  Bound result 999999999999999999827\n  Bound result 16433\n  Bound result 1637\n  Bound result 408034632\n  Bound result 1863\n  Bound result 773\n  Bound result 5920\n  Bound result 18\n  Bound result 16059\n  Bound result 439\n  Bound result 226\n  Bound result 999999999999999999989\n  Bound result 1325\n  Bound result 756739820788970758305\n  Bound result 21\n  Bound result 3220\n  Bound result 1896\n  Bound result 3\n  Bound result 100500000000000000000\n  Bound result 269738711542352896362\n  Bound result 242\n  Bound result 11\n  Bound result 2135\n  Bound result 999999999999999999609\n  Bound result 1000000\n  Bound result 999999999999999999623\n  Bound result 5944\n  Bound result 1169\n  Bound result 409017646\n  Bound result 3024\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16396718)\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.20s (8.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            | 1485  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1531  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1457  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1556  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1418  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1541  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1503  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1512  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1482  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1504  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1395  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 0\n  Bound result 999999999999999999827\n  Bound result 16476\n  Bound result 1711869\n  Bound result 2837257442025708120202\n  Bound result 1863\n  Bound result 3585\n  Bound result 4907\n  Bound result 18\n  Bound result 999999999999999999626\n  Bound result 1291\n  Bound result 380102913749347591\n  Bound result 422281547052243231866\n  Bound result 999\n  Bound result 985253162021643154138\n  Bound result 15\n  Bound result 3220\n  Bound result 1896\n  Bound result 0\n  Bound result 100500000000000000000\n  Bound result 242\n  Bound result 18\n  Bound result 2135\n  Bound result 999999999999999999609\n  Bound result 1000000\n  Bound result 999999999999999999623\n  Bound result 0\n  Bound result 3432\n  Bound result 57238727975856913582\n  Bound result 409017646\n  Bound result 207\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16354611)\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.29s CPU time)\n\nRan 25 test suites in 8.30s (36.72s CPU time): 167 tests passed, 0 failed, 0 skipped (167 total tests)\n","passed":true},{"durationMs":74,"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\":101,\"README.md\":59,\"docs/DEPLOYMENT.md\":76,\"docs/ORACLE.md\":97,\"docs/SECURITY.md\":29,\"docs/dependencies.json\":26,\"foundry.toml\":20,\"script/HookSaltMiner.sol\":23,\"src/CabalCoin.sol\":11,\"src/CabalGate.sol\":510,\"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\":337,\"test/CabalCoin.t.sol\":62,\"test/CabalFixture.sol\":358,\"test/EconomicProperties.t.sol\":188,\"test/GateFactoryEdges.t.sol\":267,\"test/GateLaunch.t.sol\":551,\"test/GateLaunchChecks.md\":54,\"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},{"durationMs":8323,"exitCode":0,"name":"slither","output":"[high/medium] reentrancy-balance at src/CabalGate.sol:238: Reentrancy in CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#238-304):\n[high/medium] reentrancy-balance at src/CabalGate.sol:238: Reentrancy in CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#238-304):\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:494: CabalGate._reduceHolding(CabalGate.Holding,uint256) (src/CabalGate.sol#494-502) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalGate.sol:238: CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#238-304) 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:494: CabalGate._reduceHolding(CabalGate.Holding,uint256) (src/CabalGate.sol#494-502) 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:238: Reentrancy in CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#238-304):\n[medium/medium] reentrancy-no-eth at src/CabalGate.sol:387: Reentrancy in CabalGate._execute(bytes32,bool,uint256) (src/CabalGate.sol#387-423):\n[medium/medium] uninitialized-local at src/libraries/Json.sol:94: Json.length(bytes).n (src/libraries/Json.sol#94) is a local variable never initialized\n[medium/medium] unused-return at src/CabalGate.sol:387: CabalGate._execute(bytes32,bool,uint256) (src/CabalGate.sol#387-423) ignores return value by (current,None,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalGate.sol#399)\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/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:425: CabalGate.unlockCallback(bytes) (src/CabalGate.sol#425-463) ignores return value by (beforePrice,None,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalGate.sol#440)\n[medium/medium] unused-return at src/CabalGate.sol:425: CabalGate.unlockCallback(bytes) (src/CabalGate.sol#425-463) ignores return value by (afterPrice,None,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalGate.sol#451)\n[medium/medium] unused-return at src/CabalGate.sol:238: CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#238-304) ignores return value by (sqrtPrice,None,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalGate.sol#254)\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[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:387: Reentrancy in CabalGate._execute(bytes32,bool,uint256) (src/CabalGate.sol#387-423):\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:238: Reentrancy in CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#238-304):\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:310: CabalGate.onOracleResult(bytes32,Attestation,bytes) (src/CabalGate.sol#310-342) uses timestamp for comparisons\n[low/medium] timestamp at src/CabalGate.sol:353: CabalGate.clearRequest(bytes32) (src/CabalGate.sol#353-367) uses timestamp for comparisons\n[low/medium] timestamp at src/CabalGate.sol:387: CabalGate._execute(bytes32,bool,uint256) (src/CabalGate.sol#387-423) uses timestamp for comparisons\n[low/medium] timestamp at src/CabalGate.sol:238: CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#238-304) uses timestamp for comparisons","passed":true},{"durationMs":707,"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:324: Reentrancy: State change after external call (5 places)\n[low] centralization-risk at src/CabalGate.sol:29: 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:222: 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:209: `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:425: 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":"21ebae92e87c1933b74e6cb96bd0c6bc04d06292751a97177e1e7c1b1a70d49f","verifiedTreeHash":"e58c2007cd99c6516a636835b7e57e48f45d0101","verifierVersion":"0.1.0+14166f2e"},{"checks":[{"durationMs":139619,"exitCode":0,"name":"build","output":"Compiling 121 files with Solc 0.8.26\nSolc 0.8.26 finished in 139.38s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n   --> test/GateFactoryEdges.t.sol:229:5:\n    |\n229 |     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[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/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/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/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[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[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: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:430:9\n    │\n430 │         _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:227:9\n    │\n227 │         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:209:64\n    │\n209 │     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:221:90\n    │\n221 │                 || cfg.maxBuyAmount == 0 || 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:222:40\n    │\n222 │                 || 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:284:14\n    │\n284 │           id = IIntake(cfg.intake)\n    │ ┏━━━━━━━━━━━━━━┛\n285 │ ┃             .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[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:303:9\n    │\n303 │         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:287:13\n    │\n287 │         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:293:24\n    │\n293 │             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:294:23\n    │\n294 │             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:297:21\n    │\n297 │             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:314:35\n    │\n314 │         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:320:74\n    │\n320 │                 || 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:321:20\n    │\n321 │                 || 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:336:38\n    │\n336 │             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:341:9\n    │\n341 │         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:336:31\n    │\n336 │             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:358:33\n    │\n358 │             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:360:33\n    │\n360 │             if (!staleConfig && block.timestamp < r.approvedUntil) revert InvalidRequest();\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:392:13\n    │\n392 │         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:422:9\n    │\n422 │         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:414:44\n    │\n414 │             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[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:454:26\n    │\n454 │         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:486:13\n    │\n486 │         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:506:13\n    │\n506 │             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":7940,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 1 test for test/GateLiveHook.t.sol:GateEmptyEvmUsageTest\n[PASS] test_gateIsInertButIntactUntilItsDependenciesHaveCode() (gas: 8455918)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.02ms (897.43µs CPU time)\n\nRan 1 test for test/Trading.t.sol:ReverseTokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5205711)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 5.08ms (2.40ms 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 7.61ms (1.31ms CPU time)\n\nRan 5 tests for test/CabalCoin.t.sol:CabalCoinTest\n[PASS] testFuzz_transferConservesSupply(uint256) (runs: 256, μ: 83206, ~: 83405)\nLogs:\n  Bound result 505469447847154854946288937\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 15.58ms (18.39ms CPU time)\n\nRan 1 test for test/GateLaunch.t.sol:GateEmptyEvmLaunchTest\n[PASS] test_gateDeploysInAnEmptyEvmWithTheManifestWords() (gas: 28103301)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 40.71ms (40.56ms CPU time)\n\nRan 8 tests for test/GateLiveHook.t.sol:GateLiveHookTest\n[PASS] test_liveHookStateReadsExactlyAsTheManifestWordsDescribe() (gas: 85848)\n[PASS] test_ownerReconfigurationOnLiveHookKeepsTheBindingChecks() (gas: 8500497)\n[PASS] test_realHookRefusesGateBuiltWithSwappedTokenRoles() (gas: 8062505)\n[PASS] test_realSetGateBindsTheDeployedGateOnceAndRefusesEverythingElse() (gas: 16296478)\n[PASS] test_requestRefusedOffMainnetBeforeAnyHookReadOrPayment() (gas: 11761497)\n[PASS] test_requestRefusedWhenPoolKeyReturnEncodingDiffersEvenWithTheSameFields() (gas: 12010351)\n[PASS] test_requestRefusedWhenTheHookHasNoCodeOrItsPoolKeyReverts() (gas: 11923621)\n[PASS] test_requestsRefusedUntilTheRealHookBindsThenBuySellCallbackAndClearRunOnLiveAddresses() (gas: 17786255)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 46.97ms (9.57ms CPU time)\n\nRan 1 test for test/OracleSigner.t.sol:OracleSignerTest\n[PASS] test_registrySignatureIsNotAnEOASignatureForTheConfiguredSigner() (gas: 4988860)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 71.04ms (2.30ms CPU time)\n\nRan 1 test for test/Oracle.t.sol:OracleGasTest\n[PASS] test_callbackFitsBelow200kColdTransaction() (gas: 2041567)\nLogs:\n  callback gas including external call: 78063\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 72.38ms (3.17ms CPU time)\n\nRan 7 tests for test/HookBinding.t.sol:ReverseOrderHookBindingTest\n[PASS] test_buySubmissionRequiresHookHandoffBeforeCharging() (gas: 39718738)\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5657872)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 593624)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 24867505)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 15426303)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 26212051)\n[PASS] test_sellSubmissionRequiresHookHandoffBeforeCharging() (gas: 40270758)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 81.72ms (79.01ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64802)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 78629)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9548036)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8196126)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 80854255)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 82.11ms (41.96ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:ReverseOrderLaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64802)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 79085)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9582585)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8196345)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 193196633)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 91.16ms (85.11ms CPU time)\n\nRan 1 test for test/Trading.t.sol:TokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5202749)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 94.34ms (2.40ms CPU time)\n\nRan 3 tests for test/OracleLatency.t.sol:OracleLatencyTest\n[PASS] test_deliveryAtOldExpiryRetainsFullApproval() (gas: 5330187)\n[PASS] test_deliveryJustBeforeOldExpiryRetainsFullApproval() (gas: 5330275)\n[PASS] test_deliveryJustBeforeRequestDeadlineRetainsFullApproval() (gas: 5330341)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 98.94ms (6.89ms 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, μ: 8083307, ~: 8083309)\nLogs:\n  Bound result 255390343012325128352970925440078616\n  Bound result 98669403034923065196\n  Bound result 1704\n  Bound result 3270\n  Bound result 97\n  Bound result 3\n  Bound result 1\n\n[PASS] test_constructorRejectsDirtyHighBitsInEveryNarrowWord() (gas: 14601379)\n[PASS] test_constructorRejectsTruncatedStaticArguments() (gas: 15941603)\n[PASS] test_factoryOwnerHandoverRequiresAcceptanceAndPreservesBinding() (gas: 8584754)\n[PASS] test_failedConfigurationRollsBackHelpersAndTheAddressStaysFree() (gas: 11144655)\n[PASS] test_helpersAreCreatedByEachGateAndExistingDependenciesStayIntact() (gas: 16181963)\n[PASS] test_hookRejectsMissingCodeWrongHookWrongCabalAndDuplicateBinding() (gas: 8206321)\n[PASS] test_pinnedValidNumericEdges() (gas: 16156965)\n[PASS] test_protocolVectorPinsAllFifteenFieldsTypeStringAndDomain() (gas: 15449)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 106.28ms (125.18ms CPU time)\n\nRan 2 tests for test/SubmissionGas.t.sol:SubmissionGasTest\n[PASS] test_longestReasonStaysUnderBudget() (gas: 1255354)\n[PASS] test_shortBuyAndSellStayUnderBudget() (gas: 1121472)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 113.07ms (2.25ms CPU time)\n\nRan 7 tests for test/HookBinding.t.sol:HookBindingTest\n[PASS] test_buySubmissionRequiresHookHandoffBeforeCharging() (gas: 27895162)\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5623543)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 592316)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 13683664)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 4759768)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 15024101)\n[PASS] test_sellSubmissionRequiresHookHandoffBeforeCharging() (gas: 28432287)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 123.36ms (41.74ms CPU time)\n\nRan 22 tests for test/Oracle.t.sol:OracleTest\n[PASS] testFuzz_attestationFieldsAreBound(uint8) (runs: 256, μ: 4484417, ~: 4482254)\nLogs:\n  Bound result 5\n\n[PASS] test_280UnicodeCharactersAccepted281Rejected() (gas: 7551946)\n[PASS] test_approvalNeverOutlivesAttestation() (gas: 4530062)\n[PASS] test_attestationCannotBeReusedForAnotherRequest() (gas: 7827776)\n[PASS] test_badSignerDomainAndTampering() (gas: 4810927)\n[PASS] test_bodyIsCanonicalJsonWithConsumerAndStoredEscapedQuestion() (gas: 14363689)\n[PASS] test_configuredPanelParametersFlowIntoBodyAndChecks() (gas: 4966991)\n[PASS] test_controlCharactersAndGuillemetsRejected() (gas: 3946566)\n[PASS] test_intakeFailureUnderpaymentDuplicateIdAndReentry() (gas: 7831170)\n[PASS] test_liveFormatDeliveryWithDistinctOracleIdApproves() (gas: 4551833)\n[PASS] test_malformedUTF8Rejected() (gas: 249860)\n[PASS] test_oldPendingUsesSnapshotIntakeSignerAndDomain() (gas: 5799981)\n[PASS] test_onlyIntakeOnlyPendingReplayAndUnknownIds() (gas: 4644649)\n[PASS] test_oracleClockMayRunSlightlyAheadAndValidityMayBeLong() (gas: 4529958)\n[PASS] test_ownerConfigSnapshotsInvalidatesOldExecutionAndCanClear() (gas: 6130763)\n[PASS] test_questionHashMustMatchStoredQuestionAndWindow() (gas: 6933792)\n[PASS] test_quotesInsideReasonCannotCloseTheDelimiter() (gas: 4381075)\n[PASS] test_sellQuestionIncludesHoldingsPriceBasisTimeNftAndReason() (gas: 11330891)\n[PASS] test_submitPaysExactlyQuotedPriceAndRevokesAllowance() (gas: 3478623)\n[PASS] test_timeoutClearsNoLateCallbackNoTradeFundsEscrowed() (gas: 6655677)\n[PASS] test_trueApprovesForFiveMinutesAndFalseRejects() (gas: 7792671)\n[PASS] test_wrongChainAndSizeAndConcurrentRequestRejected() (gas: 3655634)\nSuite result: ok. 22 passed; 0 failed; 0 skipped; finished in 492.47ms (472.34ms CPU time)\n\nRan 10 tests for test/GateLaunch.t.sol:GateLaunchTest\n[PASS] test_constructorIgnoresDependencyCodeAndHookState() (gas: 16032750)\n[PASS] test_constructorSortsCurrenciesWhenCabalSortsAboveImd() (gas: 12272898)\n[PASS] test_existingHookOwnerBindsGateOnceAndRefusesSecondGate() (gas: 16211054)\n[PASS] test_explicitOwnerControlsConfigurationInsteadOfFactory() (gas: 8303710)\n[PASS] test_factoryDeploysOnlyGateWithAllFifteenManifestWords() (gas: 28629703)\n[PASS] test_flatConstructorRetainsEveryValidation() (gas: 70090067)\n[PASS] test_hookRefusesGateWithSwappedTokenRoles() (gas: 8381586)\n[PASS] test_ownerConfigureKeepsLiveDependencyChecksAndOracleBounds() (gas: 9271118)\n[PASS] test_requestRevertsWhenTheHookReportsAnotherKeyCabalImdOrGate() (gas: 12789852)\n[PASS] test_requestSucceedsOnlyOnceTheHookReportsThisGate() (gas: 14721983)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 847.35ms (57.09ms CPU time)\n\nRan 3 tests for test/GateLiveHook.t.sol:GateHookReadFuzzTest\n[PASS] testFuzz_onlyTheExactCabalImdAndGateAreAccepted(address,address,address,bool) (runs: 512, μ: 3848093, ~: 4059013)\n[PASS] testFuzz_onlyTheExactPoolKeyIsAccepted(uint8,uint256,bool) (runs: 512, μ: 3780507, ~: 4009803)\nLogs:\n  Bound result 2\n\n[PASS] test_pinnedNearMisses() (gas: 4234622)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 850.32ms (1.64s CPU time)\n\nRan 20 tests for test/Trading.t.sol:TradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9628543, ~: 9632205)\nLogs:\n  Bound result 761841147747607549849\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 10000722)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 232962)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23797313)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5185138)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10583304)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5214501)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4637155)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5527912)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13137737)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 57084065)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5335234)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5899496)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117029)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10205744)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5330605)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100513)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 342723)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11484401)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 974.81ms (923.26ms CPU time)\n\nRan 16 tests for test/AdversarialOracle.t.sol:AdversarialOracleTest\n[PASS] testFuzz_malformedSignatureLengthCannotConsumeRequest(uint8) (runs: 1000, μ: 4508860, ~: 4508707)\nLogs:\n  Bound result 125\n\n[PASS] test_attestationIssuedBeforeSubmissionIsRefused() (gas: 4589034)\n[PASS] test_callbackHasNoDependencyOnTokenNftIntakeOrPoolReads() (gas: 4632996)\n[PASS] test_configurationRejectsEveryInvalidBoundaryWithoutAdvancingVersion() (gas: 2307694)\n[PASS] test_everySignedFieldRejectsPostSignatureMutation() (gas: 22129260)\n[PASS] test_explicitVerifierReplacesGateInDomainAndBody() (gas: 4992263)\n[PASS] test_failedOraclePaymentLeavesNoRequestAndCanRetry() (gas: 3886816)\n[PASS] test_identicalReasonFromAnotherUserDoesNotShareAttestation() (gas: 6656069)\n[PASS] test_mainnetDefaultsMatchAssignment() (gas: 65683)\n[PASS] test_rejectedAndClearedIdsCannotReplayOrAlterNewActiveRequest() (gas: 10986234)\n[PASS] test_rejectionReleasesSlotAndResubmissionNeedsFreshDecision() (gas: 7694194)\n[PASS] test_signatureRejectsHighSAndInvalidV() (gas: 4683802)\n[PASS] test_signatureRejectsWrongNameVersionAndDomainChain() (gas: 4860736)\n[PASS] test_timeoutAndApprovalBoundaryAtLastPermittedSecond() (gas: 5220275)\n[PASS] test_zeroOraclePriceAndZeroReturnedIdAreHandledAtomically() (gas: 3808153)\n[PASS] test_zeroVerifierMeansThisGateAndIsStoredResolved() (gas: 3748635)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 1.24s (1.20s CPU time)\n\nRan 7 tests for test/ReasonEscaping.t.sol:ReasonEscapingTest\n[PASS] testFuzz_arbitraryBytesAreJudgedLikeAnIndependentDecoder(bytes) (runs: 1000, μ: 14868, ~: 12712)\n[PASS] testFuzz_oneCorruptedByteIsJudgedLikeAnIndependentDecoder(bytes32,uint16,uint16,uint8) (runs: 1000, μ: 282996, ~: 190746)\nLogs:\n  Bound result 162\n  Bound result 272\n\n[PASS] testFuzz_wellFormedTextOfEveryWidthIsCountedEscapedAndQuotedExactly(bytes32,uint16) (runs: 1000, μ: 2039340, ~: 1793143)\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.24s (2.27s CPU time)\n\nRan 20 tests for test/Trading.t.sol:ReverseOrderTradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9662899, ~: 9666780)\nLogs:\n  Bound result 761841147747607549849\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 10034987)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 233434)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23929007)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5219110)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10663702)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5248755)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4637090)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5566932)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13171434)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 15956803)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5342927)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5975313)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117294)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10300540)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5365015)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100508)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 342675)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11588362)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.26s (1.34s CPU time)\n\nRan 7 tests for test/QuestionProperties.t.sol:QuestionPropertiesTest\n[PASS] testFuzz_jsonRoundTripsUntrustedPrintableAscii(bytes,bool,uint128) (runs: 1000, μ: 5030835, ~: 4930353)\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.26s (1.46s CPU time)\n\nRan 9 tests for test/EconomicProperties.t.sol:EconomicPropertiesTest\n[PASS] testFuzz_feeCannotExceedHalfPercentAndRoundingIsBounded(uint256) (runs: 1000, μ: 17512, ~: 17678)\n[PASS] testFuzz_priceMovementSymmetricMonotoneAndBounded(uint160,uint160,uint160) (runs: 1000, μ: 51405, ~: 51343)\nLogs:\n  Bound result 221313827399\n  Bound result 1179208382840913810\n  Bound result 31960146822162028539477400\n\n[PASS] testFuzz_repeatedBuySellCannotCreateImd(uint256,uint8) (runs: 1000, μ: 16329452, ~: 17462220)\nLogs:\n  Bound result 339562912322673422088\n  Bound result 3\n\n[PASS] test_feeAndPriceKnownBoundaries() (gas: 58513)\n[PASS] test_insufficientExecutionAllowancePreservesApprovalAndCanRetry() (gas: 5473149)\n[PASS] test_realTradesAtFeeRoundingEdges() (gas: 23365493)\n[PASS] test_sellApprovalSurvivesBalanceDropAndExecutesOnceRestored() (gas: 9891833)\n[PASS] test_sellLargerThanTrackedHoldingsClearsTheRecordWithoutUnderflow() (gas: 9679049)\n[PASS] test_sellSlippageFailureRollsBackFeePositionAndCostBasis() (gas: 10260848)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.26s (1.23s 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            | 1622  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | clear              | 1676  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | cycle              | 1654  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | donate             | 1644  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | reconfigure        | 1693  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refuseCallback     | 1601  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refusePayment      | 1632  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refuseUnauthorized | 1652  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | request            | 1595  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | resolve            | 1615  | 0       | 0        |\n╰------------------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 139147431899998728\n  Bound result 244189832305305686\n  Bound result 446\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 19\n  Bound result 1193046\n  Bound result 130\n  Bound result 589\n  Bound result 64\n  Bound result 20\n  Bound result 12772\n  Bound result 383\n  Bound result 155828549693282354\n  Bound result 7500\n  Bound result 1120\n  Bound result 10\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 885031302966213839\n  Bound result 2000\n  Bound result 529035837012967424\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 16035\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 1648\n  Bound result 1073\n  Bound result 10\n  Bound result 11\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 20\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 3\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 200000\n  Bound result 187\n  Bound result 3\n  Bound result 23\n  Bound result 2964\n  Bound result 1\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 799\n\n[PASS] test_handlerExercisesPaymentsFailuresBothAnswersAndClearing() (gas: 18841340)\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 7.00s (7.00s 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            | 1565  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1439  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1448  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1532  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1444  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1539  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1500  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1446  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1535  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1454  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1482  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 400\n  Bound result 1400\n  Bound result 999999999999999998\n  Bound result 697\n  Bound result 3599\n  Bound result 10000000000000000000\n  Bound result 0\n  Bound result 3378\n  Bound result 646\n  Bound result 614\n  Bound result 999999999999999999788\n  Bound result 1680\n  Bound result 21\n  Bound result 10\n  Bound result 60\n  Bound result 999999999999999999999\n  Bound result 1315\n  Bound result 20759\n  Bound result 3408510222\n  Bound result 3408510222\n  Bound result 1972\n  Bound result 22\n  Bound result 2324\n  Bound result 2496\n  Bound result 827905\n  Bound result 711\n  Bound result 1969\n  Bound result 18462\n  Bound result 799\n  Bound result 0\n  Bound result 9283\n  Bound result 1800003600\n  Bound result 61\n  Bound result 1000\n  Bound result 371636862\n  Bound result 20582\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16396718)\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.57s (7.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            | 1565  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1439  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1448  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1532  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1444  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1539  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1500  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1446  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1535  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1454  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1482  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 400\n  Bound result 3786714986\n  Bound result 999999999999999998\n  Bound result 9498\n  Bound result 3599\n  Bound result 10000000000000000000\n  Bound result 0\n  Bound result 3369\n  Bound result 380543652421633061026\n  Bound result 3231\n  Bound result 999999999999999999788\n  Bound result 841576192921683451590\n  Bound result 500\n  Bound result 21\n  Bound result 10\n  Bound result 60\n  Bound result 999999999999999999999\n  Bound result 234\n  Bound result 13950\n  Bound result 2917\n  Bound result 2917\n  Bound result 2306\n  Bound result 22\n  Bound result 2426\n  Bound result 10654\n  Bound result 827905\n  Bound result 113549768\n  Bound result 3372\n  Bound result 892679477163368368\n  Bound result 799\n  Bound result 0\n  Bound result 8742\n  Bound result 1800003600\n  Bound result 61\n  Bound result 1000\n  Bound result 371636862\n  Bound result 13281\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16354611)\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.84s (7.82s CPU time)\n\nRan 28 test suites in 7.84s (32.89s CPU time): 179 tests passed, 0 failed, 0 skipped (179 total tests)\n","passed":true},{"durationMs":64,"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\":101,\"README.md\":59,\"docs/DEPLOYMENT.md\":76,\"docs/ORACLE.md\":97,\"docs/SECURITY.md\":29,\"docs/dependencies.json\":26,\"foundry.toml\":20,\"script/HookSaltMiner.sol\":23,\"src/CabalCoin.sol\":11,\"src/CabalGate.sol\":510,\"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\":337,\"test/CabalCoin.t.sol\":62,\"test/CabalFixture.sol\":358,\"test/EconomicProperties.t.sol\":188,\"test/GateFactoryEdges.t.sol\":267,\"test/GateLaunch.t.sol\":551,\"test/GateLaunchChecks.md\":54,\"test/GateLiveHook.t.sol\":414,\"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\":24,\"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":"7cd472130b57295c8cd1fd2531383c00965ff0b6f39392b7397a606f3d2cde7d","verifiedTreeHash":"01710eb4d1149c66914a1a44582914e229a7a383","verifierVersion":"0.1.0+14166f2e"},{"checks":[{"durationMs":134812,"exitCode":0,"name":"build","output":"Compiling 120 files with Solc 0.8.26\nSolc 0.8.26 finished in 134.55s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n   --> test/GateFactoryEdges.t.sol:233:5:\n    |\n233 |     function test_protocolVectorPinsAllFifteenFieldsTypeStringAndDomain() public {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\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[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:431:9\n    │\n431 │         _executing = false;\n    │         ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\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: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[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:228:9\n    │\n228 │         emit Configured(configVersion, cfg);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:160:34\n    │\n160 │                 || tickSpacing > uint24(type(int24).max)\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint24' 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:166:70\n    │\n166 │             Currency.wrap(currency0), Currency.wrap(currency1), fee, int24(tickSpacing), IHooks(address(launchHook))\n    │                                                                      ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int24' 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: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[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/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[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:222:90\n    │\n222 │                 || cfg.maxBuyAmount == 0 || 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:223:40\n    │\n223 │                 || 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:285:14\n    │\n285 │           id = IIntake(cfg.intake)\n    │ ┏━━━━━━━━━━━━━━┛\n286 │ ┃             .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:304:9\n    │\n304 │         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:288:13\n    │\n288 │         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:294:24\n    │\n294 │             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:295:23\n    │\n295 │             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:298:21\n    │\n298 │             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:315:35\n    │\n315 │         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:321:74\n    │\n321 │                 || 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:322:20\n    │\n322 │                 || 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:337:38\n    │\n337 │             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:342:9\n    │\n342 │         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:337:31\n    │\n337 │             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:359:33\n    │\n359 │             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:361:33\n    │\n361 │             if (!staleConfig && block.timestamp < r.approvedUntil) revert InvalidRequest();\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:393:13\n    │\n393 │         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:423:9\n    │\n423 │         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:415:44\n    │\n415 │             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[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:455:26\n    │\n455 │         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:487:13\n    │\n487 │         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:507:13\n    │\n507 │             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":8285,"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 1.18ms (1.27ms CPU time)\n\nRan 1 test for test/Trading.t.sol:ReverseTokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5205640)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 13.50ms (5.92ms CPU time)\n\nRan 5 tests for test/CabalCoin.t.sol:CabalCoinTest\n[PASS] testFuzz_transferConservesSupply(uint256) (runs: 256, μ: 83125, ~: 83399)\nLogs:\n  Bound result 92\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 29.22ms (10.83ms CPU time)\n\nRan 1 test for test/GateLaunch.t.sol:GateEmptyEvmLaunchTest\n[PASS] test_gateDeploysInAnEmptyEvmWithTheManifestWords() (gas: 28030480)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 29.28ms (29.12ms CPU time)\n\nRan 1 test for test/Trading.t.sol:TokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5202507)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 65.28ms (2.29ms CPU time)\n\nRan 1 test for test/Oracle.t.sol:OracleGasTest\n[PASS] test_callbackFitsBelow200kColdTransaction() (gas: 2041560)\nLogs:\n  callback gas including external call: 78063\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 66.31ms (2.86ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:ReverseOrderLaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64815)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 79097)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9582420)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8196768)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 193201216)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 77.15ms (68.66ms CPU time)\n\nRan 2 tests for test/SubmissionGas.t.sol:SubmissionGasTest\n[PASS] test_longestReasonStaysUnderBudget() (gas: 1255330)\n[PASS] test_shortBuyAndSellStayUnderBudget() (gas: 1121402)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 108.90ms (2.07ms CPU time)\n\nRan 7 tests for test/HookBinding.t.sol:HookBindingTest\n[PASS] test_buySubmissionRequiresHookHandoffBeforeCharging() (gas: 27904126)\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5623463)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 592361)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 13687939)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 4760220)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 15028426)\n[PASS] test_sellSubmissionRequiresHookHandoffBeforeCharging() (gas: 28441285)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 111.45ms (41.01ms CPU time)\n\nRan 1 test for test/OracleSigner.t.sol:OracleSignerTest\n[PASS] test_registrySignatureIsNotAnEOASignatureForTheConfiguredSigner() (gas: 4988822)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 119.99ms (3.53ms 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, μ: 8073154, ~: 8073122)\nLogs:\n  Bound result 1\n  Bound result 50280972822995746186458110123057628\n  Bound result 10\n  Bound result 10\n  Bound result 27\n  Bound result 4\n  Bound result 10\n\n[PASS] test_constructorRejectsDirtyHighBitsInEveryNarrowWord() (gas: 20707250)\n[PASS] test_constructorRejectsTruncatedStaticArguments() (gas: 22207025)\n[PASS] test_factoryOwnerHandoverRequiresAcceptanceAndPreservesBinding() (gas: 8574269)\n[PASS] test_failedConfigurationRollsBackHelpersAndTheAddressStaysFree() (gas: 11140602)\n[PASS] test_helpersAreCreatedByEachGateAndExistingDependenciesStayIntact() (gas: 16162087)\n[PASS] test_hookRejectsMissingCodeWrongHookWrongCabalAndDuplicateBinding() (gas: 8196078)\n[PASS] test_pinnedValidNumericEdges() (gas: 16137138)\n[PASS] test_protocolVectorPinsAllFifteenFieldsTypeStringAndDomain() (gas: 15449)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 141.28ms (156.88ms CPU time)\n\nRan 9 tests for test/GateLaunch.t.sol:GateLaunchTest\n[PASS] test_constructorIgnoresDependencyCodeAndHookState() (gas: 16011666)\n[PASS] test_existingHookOwnerBindsGateOnceAndRefusesSecondGate() (gas: 16191392)\n[PASS] test_explicitOwnerControlsConfigurationInsteadOfFactory() (gas: 8293607)\n[PASS] test_factoryDeploysOnlyGateWithAllNineteenManifestWords() (gas: 28532832)\n[PASS] test_flatConstructorRetainsEveryValidation() (gas: 81027076)\n[PASS] test_hookRefusesGateWithSwappedTokenRoles() (gas: 8371363)\n[PASS] test_ownerConfigureKeepsLiveDependencyChecksAndOracleBounds() (gas: 9261025)\n[PASS] test_requestRevertsWhenTheHookReportsAnotherKeyCabalImdOrGate() (gas: 12778085)\n[PASS] test_requestSucceedsOnlyOnceTheHookReportsThisGate() (gas: 14711313)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 200.83ms (45.54ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64815)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 78641)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9547880)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8196370)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 80857111)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 280.29ms (41.00ms CPU time)\n\nRan 16 tests for test/AdversarialOracle.t.sol:AdversarialOracleTest\n[PASS] testFuzz_malformedSignatureLengthCannotConsumeRequest(uint8) (runs: 1000, μ: 4508780, ~: 4508627)\nLogs:\n  Bound result 18\n\n[PASS] test_attestationIssuedBeforeSubmissionIsRefused() (gas: 4588977)\n[PASS] test_callbackHasNoDependencyOnTokenNftIntakeOrPoolReads() (gas: 4632939)\n[PASS] test_configurationRejectsEveryInvalidBoundaryWithoutAdvancingVersion() (gas: 2306671)\n[PASS] test_everySignedFieldRejectsPostSignatureMutation() (gas: 22128370)\n[PASS] test_explicitVerifierReplacesGateInDomainAndBody() (gas: 4992210)\n[PASS] test_failedOraclePaymentLeavesNoRequestAndCanRetry() (gas: 3886681)\n[PASS] test_identicalReasonFromAnotherUserDoesNotShareAttestation() (gas: 6655838)\n[PASS] test_mainnetDefaultsMatchAssignment() (gas: 65703)\n[PASS] test_rejectedAndClearedIdsCannotReplayOrAlterNewActiveRequest() (gas: 10985891)\n[PASS] test_rejectionReleasesSlotAndResubmissionNeedsFreshDecision() (gas: 7693973)\n[PASS] test_signatureRejectsHighSAndInvalidV() (gas: 4683745)\n[PASS] test_signatureRejectsWrongNameVersionAndDomainChain() (gas: 4860681)\n[PASS] test_timeoutAndApprovalBoundaryAtLastPermittedSecond() (gas: 5220117)\n[PASS] test_zeroOraclePriceAndZeroReturnedIdAreHandledAtomically() (gas: 3808019)\n[PASS] test_zeroVerifierMeansThisGateAndIsStoredResolved() (gas: 3748615)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 957.13ms (950.46ms CPU time)\n\nRan 20 tests for test/Trading.t.sol:ReverseOrderTradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9663610, ~: 9666630)\nLogs:\n  Bound result 999000000000000000093\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 10034843)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 233460)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23928363)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5218964)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10663530)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5248565)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4636966)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5566910)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13171107)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 15958313)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5342823)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5975057)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117361)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10300256)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5364936)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453777)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100600)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 342627)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11588088)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.07s (1.16s CPU time)\n\nRan 3 tests for test/OracleLatency.t.sol:OracleLatencyTest\n[PASS] test_deliveryAtOldExpiryRetainsFullApproval() (gas: 5329984)\n[PASS] test_deliveryJustBeforeOldExpiryRetainsFullApproval() (gas: 5330072)\n[PASS] test_deliveryJustBeforeRequestDeadlineRetainsFullApproval() (gas: 5330138)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 1.30s (7.99ms CPU time)\n\nRan 7 tests for test/HookBinding.t.sol:ReverseOrderHookBindingTest\n[PASS] test_buySubmissionRequiresHookHandoffBeforeCharging() (gas: 39738304)\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5657783)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 593669)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 24877374)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 15427341)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 26221970)\n[PASS] test_sellSubmissionRequiresHookHandoffBeforeCharging() (gas: 40290359)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.31s (123.63ms CPU time)\n\nRan 7 tests for test/QuestionProperties.t.sol:QuestionPropertiesTest\n[PASS] testFuzz_jsonRoundTripsUntrustedPrintableAscii(bytes,bool,uint128) (runs: 1000, μ: 5044481, ~: 5541955)\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.53s CPU time)\n\nRan 7 tests for test/ReasonEscaping.t.sol:ReasonEscapingTest\n[PASS] testFuzz_arbitraryBytesAreJudgedLikeAnIndependentDecoder(bytes) (runs: 1000, μ: 16193, ~: 12759)\n[PASS] testFuzz_oneCorruptedByteIsJudgedLikeAnIndependentDecoder(bytes32,uint16,uint16,uint8) (runs: 1000, μ: 286889, ~: 185509)\nLogs:\n  Bound result 276\n  Bound result 341\n\n[PASS] testFuzz_wellFormedTextOfEveryWidthIsCountedEscapedAndQuotedExactly(bytes32,uint16) (runs: 1000, μ: 2084075, ~: 1844350)\nLogs:\n  Bound result 190\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 (2.65s CPU time)\n\nRan 20 tests for test/Trading.t.sol:TradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9629044, ~: 9632063)\nLogs:\n  Bound result 999000000000000000093\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 10000499)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 232988)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23796677)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5185001)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10583138)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5214320)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4637031)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5527899)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13137418)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 57087463)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5335130)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5899249)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117096)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10205469)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5330535)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453777)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100605)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 342675)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11484128)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.32s (1.33s CPU time)\n\nRan 22 tests for test/Oracle.t.sol:OracleTest\n[PASS] testFuzz_attestationFieldsAreBound(uint8) (runs: 256, μ: 4484147, ~: 4482348)\nLogs:\n  Bound result 4\n\n[PASS] test_280UnicodeCharactersAccepted281Rejected() (gas: 7551853)\n[PASS] test_approvalNeverOutlivesAttestation() (gas: 4530004)\n[PASS] test_attestationCannotBeReusedForAnotherRequest() (gas: 7827686)\n[PASS] test_badSignerDomainAndTampering() (gas: 4810916)\n[PASS] test_bodyIsCanonicalJsonWithConsumerAndStoredEscapedQuestion() (gas: 14363554)\n[PASS] test_configuredPanelParametersFlowIntoBodyAndChecks() (gas: 4966937)\n[PASS] test_controlCharactersAndGuillemetsRejected() (gas: 3946320)\n[PASS] test_intakeFailureUnderpaymentDuplicateIdAndReentry() (gas: 7830902)\n[PASS] test_liveFormatDeliveryWithDistinctOracleIdApproves() (gas: 4551732)\n[PASS] test_malformedUTF8Rejected() (gas: 249790)\n[PASS] test_oldPendingUsesSnapshotIntakeSignerAndDomain() (gas: 5799924)\n[PASS] test_onlyIntakeOnlyPendingReplayAndUnknownIds() (gas: 4644635)\n[PASS] test_oracleClockMayRunSlightlyAheadAndValidityMayBeLong() (gas: 4529900)\n[PASS] test_ownerConfigSnapshotsInvalidatesOldExecutionAndCanClear() (gas: 6130621)\n[PASS] test_questionHashMustMatchStoredQuestionAndWindow() (gas: 6933761)\n[PASS] test_quotesInsideReasonCannotCloseTheDelimiter() (gas: 4381054)\n[PASS] test_sellQuestionIncludesHoldingsPriceBasisTimeNftAndReason() (gas: 11330781)\n[PASS] test_submitPaysExactlyQuotedPriceAndRevokesAllowance() (gas: 3478532)\n[PASS] test_timeoutClearsNoLateCallbackNoTradeFundsEscrowed() (gas: 6655465)\n[PASS] test_trueApprovesForFiveMinutesAndFalseRejects() (gas: 7792450)\n[PASS] test_wrongChainAndSizeAndConcurrentRequestRejected() (gas: 3655388)\nSuite result: ok. 22 passed; 0 failed; 0 skipped; finished in 1.32s (1.30s CPU time)\n\nRan 9 tests for test/EconomicProperties.t.sol:EconomicPropertiesTest\n[PASS] testFuzz_feeCannotExceedHalfPercentAndRoundingIsBounded(uint256) (runs: 1000, μ: 17470, ~: 17696)\n[PASS] testFuzz_priceMovementSymmetricMonotoneAndBounded(uint160,uint160,uint160) (runs: 1000, μ: 51278, ~: 51230)\nLogs:\n  Bound result 3552\n  Bound result 1461501637330902918203684832716283019655932542974\n  Bound result 1461501637330902918203684832716283019655932542974\n\n[PASS] testFuzz_repeatedBuySellCannotCreateImd(uint256,uint8) (runs: 1000, μ: 16346734, ~: 17458566)\nLogs:\n  Bound result 333643558896542\n  Bound result 2\n\n[PASS] test_feeAndPriceKnownBoundaries() (gas: 58487)\n[PASS] test_insufficientExecutionAllowancePreservesApprovalAndCanRetry() (gas: 5472990)\n[PASS] test_realTradesAtFeeRoundingEdges() (gas: 23364977)\n[PASS] test_sellApprovalSurvivesBalanceDropAndExecutesOnceRestored() (gas: 9891494)\n[PASS] test_sellLargerThanTrackedHoldingsClearsTheRecordWithoutUnderflow() (gas: 9678863)\n[PASS] test_sellSlippageFailureRollsBackFeePositionAndCostBasis() (gas: 10260509)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.32s (1.28s 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            | 1636  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | clear              | 1629  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | cycle              | 1622  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | donate             | 1610  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | reconfigure        | 1662  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refuseCallback     | 1654  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refusePayment      | 1629  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refuseUnauthorized | 1596  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | request            | 1692  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | resolve            | 1654  | 0       | 0        |\n╰------------------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 224\n  Bound result 16803\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 10973527\n  Bound result 828417\n  Bound result 1645\n  Bound result 0\n  Bound result 3898454\n  Bound result 1527\n  Bound result 543145807640700717\n  Bound result 1001\n  Bound result 1633\n  Bound result 22118\n  Bound result 23\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 15\n  Bound result 21259\n  Bound result 200\n  Bound result 1398\n  Bound result 971880845463515079\n  Bound result 3218\n  Bound result 12705\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 20\n  Bound result 22\n  Bound result 16\n  Bound result 394\n  Bound result 480766375000403080\n  Bound result 1408\n  Bound result 4\n  Bound result 11\n  Bound result 8218\n  Bound result 280743323735687043\n  Bound result 1000000000000000000\n  Bound result 136275314817270205\n\n[PASS] test_handlerExercisesPaymentsFailuresBothAnswersAndClearing() (gas: 18838876)\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 7.26s (7.26s 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            | 1526  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1461  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1526  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1451  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1500  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1446  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1487  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1458  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1560  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1479  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1490  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 0\n  Bound result 821096873977831687793\n  Bound result 0\n  Bound result 2\n  Bound result 999999999999999999664\n  Bound result 0\n  Bound result 0\n  Bound result 11659\n  Bound result 200\n  Bound result 999999999999999999614\n  Bound result 0\n  Bound result 298\n  Bound result 61\n  Bound result 0\n  Bound result 261\n  Bound result 206050003949151543170\n  Bound result 941245665355568664546\n  Bound result 0\n  Bound result 2646\n  Bound result 7\n  Bound result 5712082\n  Bound result 19\n  Bound result 26031907730635\n  Bound result 130\n  Bound result 1\n  Bound result 15\n  Bound result 124\n  Bound result 92\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16353806)\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.15s (8.14s 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            | 1526  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1461  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1526  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1451  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1500  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1446  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1487  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1458  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1560  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1479  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1490  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 0\n  Bound result 8081\n  Bound result 29\n  Bound result 2\n  Bound result 999999999999999999664\n  Bound result 0\n  Bound result 0\n  Bound result 11055\n  Bound result 200\n  Bound result 999999999999999999614\n  Bound result 0\n  Bound result 298\n  Bound result 61\n  Bound result 0\n  Bound result 3400\n  Bound result 206050003949151543170\n  Bound result 957273030537742351976\n  Bound result 600486548829932293\n  Bound result 2646\n  Bound result 7\n  Bound result 5712082\n  Bound result 15\n  Bound result 26031907730635\n  Bound result 130\n  Bound result 1\n  Bound result 366179171551254073360\n  Bound result 10\n  Bound result 164\n  Bound result 92\n  Bound result 999999999999999999667\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16395913)\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.18s (8.19s CPU time)\n\nRan 25 test suites in 8.18s (36.04s CPU time): 166 tests passed, 0 failed, 0 skipped (166 total tests)\n","passed":true},{"durationMs":79,"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\":80,\"README.md\":59,\"docs/DEPLOYMENT.md\":80,\"docs/ORACLE.md\":97,\"docs/SECURITY.md\":29,\"docs/dependencies.json\":26,\"foundry.toml\":20,\"script/HookSaltMiner.sol\":23,\"src/CabalCoin.sol\":11,\"src/CabalGate.sol\":511,\"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\":337,\"test/CabalCoin.t.sol\":62,\"test/CabalFixture.sol\":362,\"test/EconomicProperties.t.sol\":188,\"test/GateFactoryEdges.t.sol\":271,\"test/GateLaunch.t.sol\":542,\"test/GateLaunchChecks.md\":54,\"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},{"durationMs":8240,"exitCode":0,"name":"slither","output":"[high/medium] reentrancy-balance at src/CabalGate.sol:239: Reentrancy in CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#239-305):\n[high/medium] reentrancy-balance at src/CabalGate.sol:239: Reentrancy in CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#239-305):\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:495: CabalGate._reduceHolding(CabalGate.Holding,uint256) (src/CabalGate.sol#495-503) 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:239: CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#239-305) uses a dangerous strict equality:\n[medium/high] incorrect-equality at src/CabalGate.sol:495: CabalGate._reduceHolding(CabalGate.Holding,uint256) (src/CabalGate.sol#495-503) 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:239: Reentrancy in CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#239-305):\n[medium/medium] reentrancy-no-eth at src/CabalGate.sol:388: Reentrancy in CabalGate._execute(bytes32,bool,uint256) (src/CabalGate.sol#388-424):\n[medium/medium] uninitialized-local at src/libraries/Json.sol:94: Json.length(bytes).n (src/libraries/Json.sol#94) is a local variable never initialized\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/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:426: CabalGate.unlockCallback(bytes) (src/CabalGate.sol#426-464) ignores return value by (afterPrice,None,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalGate.sol#452)\n[medium/medium] unused-return at src/CabalGate.sol:239: CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#239-305) ignores return value by (sqrtPrice,None,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalGate.sol#255)\n[medium/medium] unused-return at src/CabalGate.sol:426: CabalGate.unlockCallback(bytes) (src/CabalGate.sol#426-464) ignores return value by (beforePrice,None,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalGate.sol#441)\n[medium/medium] unused-return at src/CabalGate.sol:388: CabalGate._execute(bytes32,bool,uint256) (src/CabalGate.sol#388-424) ignores return value by (current,None,None,None) = poolManager.getSlot0(_key.toId()) (src/CabalGate.sol#400)\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[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:239: Reentrancy in CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#239-305):\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:388: Reentrancy in CabalGate._execute(bytes32,bool,uint256) (src/CabalGate.sol#388-424):\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:388: CabalGate._execute(bytes32,bool,uint256) (src/CabalGate.sol#388-424) uses timestamp for comparisons\n[low/medium] timestamp at src/CabalGate.sol:311: CabalGate.onOracleResult(bytes32,Attestation,bytes) (src/CabalGate.sol#311-343) uses timestamp for comparisons\n[low/medium] timestamp at src/CabalGate.sol:354: CabalGate.clearRequest(bytes32) (src/CabalGate.sol#354-368) uses timestamp for comparisons\n[low/medium] timestamp at src/CabalGate.sol:239: CabalGate._submit(bool,uint256,string) (src/CabalGate.sol#239-305) uses timestamp for comparisons","passed":true},{"durationMs":671,"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:325: Reentrancy: State change after external call (5 places)\n[low] centralization-risk at src/CabalGate.sol:29: 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:223: 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:426: 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":"8841e823ef205134a95c97a1af16c42fffbd6fff11349581061c6c49599a8e31","verifiedTreeHash":"39ff23e6ba9586c7bd3bb135baac7fba5cbc1e0c","verifierVersion":"0.1.0+8af37dff"},{"checks":[{"durationMs":143489,"exitCode":0,"name":"build","output":"Compiling 121 files with Solc 0.8.26\nSolc 0.8.26 finished in 143.23s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n   --> test/GateFactoryEdges.t.sol:233:5:\n    |\n233 |     function test_protocolVectorPinsAllFifteenFieldsTypeStringAndDomain() public {\n    |     ^ (Relevant source part starts here and spans across multiple lines).\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[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[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[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[missing-events-access-control]: `_executing` is changed without an event but is used for access control\n    ╭▸ src/CabalGate.sol:431:9\n    │\n431 │         _executing = false;\n    │         ━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/missing-events-access-control\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[reentrancy-events]: event emitted after an external call; reentrancy can reorder or fabricate logs that off-chain consumers rely on\n    ╭▸ src/CabalGate.sol:228:9\n    │\n228 │         emit Configured(configVersion, cfg);\n    │         ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/reentrancy-events\n\nwarning[unsafe-typecast]: typecast can truncate values\n    ╭▸ src/CabalGate.sol:160:34\n    │\n160 │                 || tickSpacing > uint24(type(int24).max)\n    │                                  ━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'uint24' 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:166:70\n    │\n166 │             Currency.wrap(currency0), Currency.wrap(currency1), fee, int24(tickSpacing), IHooks(address(launchHook))\n    │                                                                      ━━━━━━━━━━━━━━━━━━\n    │\n    ├ note: consider disabling this lint if you're certain the cast is safe\n    │       \n    │       // casting to 'int24' 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[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:222:90\n    │\n222 │                 || cfg.maxBuyAmount == 0 || 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:223:40\n    │\n223 │                 || 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:285:14\n    │\n285 │           id = IIntake(cfg.intake)\n    │ ┏━━━━━━━━━━━━━━┛\n286 │ ┃             .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:304:9\n    │\n304 │         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:288:13\n    │\n288 │         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:294:24\n    │\n294 │             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:295:23\n    │\n295 │             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:298:21\n    │\n298 │             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:315:35\n    │\n315 │         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:321:74\n    │\n321 │                 || 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:322:20\n    │\n322 │                 || 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:337:38\n    │\n337 │             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:342:9\n    │\n342 │         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:337:31\n    │\n337 │             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:359:33\n    │\n359 │             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:361:33\n    │\n361 │             if (!staleConfig && block.timestamp < r.approvedUntil) revert InvalidRequest();\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:393:13\n    │\n393 │         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:423:9\n    │\n423 │         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:415:44\n    │\n415 │             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:455:26\n    │\n455 │         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:487:13\n    │\n487 │         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:507:13\n    │\n507 │             IDENTITY_NFT.staticcall{gas: 30000}(abi.encodeWithSignature(\"balanceOf(address)\", user));\n    │             ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n    │\n    ╰ help: https://getfoundry.sh/forge/linting/return-bomb\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[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":8287,"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 816.32µs (613.78µs CPU time)\n\nRan 1 test for test/GateLiveHook.t.sol:GateEmptyEvmUsageTest\n[PASS] test_gateIsInertButIntactUntilItsDependenciesHaveCode() (gas: 8445498)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 931.35µs (835.27µs CPU time)\n\nRan 5 tests for test/CabalCoin.t.sol:CabalCoinTest\n[PASS] testFuzz_transferConservesSupply(uint256) (runs: 256, μ: 83170, ~: 83405)\nLogs:\n  Bound result 74519449938477045160712883\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 8.03ms (8.69ms CPU time)\n\nRan 8 tests for test/GateLiveHook.t.sol:GateLiveHookTest\n[PASS] test_liveHookStateReadsExactlyAsTheManifestWordsDescribe() (gas: 85465)\n[PASS] test_ownerReconfigurationOnLiveHookKeepsTheBindingChecks() (gas: 8490360)\n[PASS] test_realHookRefusesGateBuiltWithSwappedTokenRoles() (gas: 8052439)\n[PASS] test_realSetGateBindsTheDeployedGateOnceAndRefusesEverythingElse() (gas: 16276794)\n[PASS] test_requestRefusedOffMainnetBeforeAnyHookReadOrPayment() (gas: 11751067)\n[PASS] test_requestRefusedWhenPoolKeyReturnEncodingDiffersEvenWithTheSameFields() (gas: 11999554)\n[PASS] test_requestRefusedWhenTheHookHasNoCodeOrItsPoolKeyReverts() (gas: 11912922)\n[PASS] test_requestsRefusedUntilTheRealHookBindsThenBuySellCallbackAndClearRunOnLiveAddresses() (gas: 17774847)\nSuite result: ok. 8 passed; 0 failed; 0 skipped; finished in 11.28ms (10.43ms CPU time)\n\nRan 1 test for test/Trading.t.sol:ReverseTokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5205640)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 12.19ms (7.50ms CPU time)\n\nRan 1 test for test/GateLaunch.t.sol:GateEmptyEvmLaunchTest\n[PASS] test_gateDeploysInAnEmptyEvmWithTheManifestWords() (gas: 28030480)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 32.95ms (32.80ms CPU time)\n\nRan 9 tests for test/GateLaunch.t.sol:GateLaunchTest\n[PASS] test_constructorIgnoresDependencyCodeAndHookState() (gas: 16011666)\n[PASS] test_existingHookOwnerBindsGateOnceAndRefusesSecondGate() (gas: 16191392)\n[PASS] test_explicitOwnerControlsConfigurationInsteadOfFactory() (gas: 8293607)\n[PASS] test_factoryDeploysOnlyGateWithAllNineteenManifestWords() (gas: 28532832)\n[PASS] test_flatConstructorRetainsEveryValidation() (gas: 81027076)\n[PASS] test_hookRefusesGateWithSwappedTokenRoles() (gas: 8371363)\n[PASS] test_ownerConfigureKeepsLiveDependencyChecksAndOracleBounds() (gas: 9261025)\n[PASS] test_requestRevertsWhenTheHookReportsAnotherKeyCabalImdOrGate() (gas: 12778085)\n[PASS] test_requestSucceedsOnlyOnceTheHookReportsThisGate() (gas: 14711313)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 45.84ms (64.01ms CPU time)\n\nRan 2 tests for test/SubmissionGas.t.sol:SubmissionGasTest\n[PASS] test_longestReasonStaysUnderBudget() (gas: 1255330)\n[PASS] test_shortBuyAndSellStayUnderBudget() (gas: 1121402)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 64.31ms (1.48ms CPU time)\n\nRan 1 test for test/OracleSigner.t.sol:OracleSignerTest\n[PASS] test_registrySignatureIsNotAnEOASignatureForTheConfiguredSigner() (gas: 4988822)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 65.57ms (2.29ms CPU time)\n\nRan 1 test for test/Trading.t.sol:TokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5202507)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 75.20ms (2.54ms CPU time)\n\nRan 3 tests for test/OracleLatency.t.sol:OracleLatencyTest\n[PASS] test_deliveryAtOldExpiryRetainsFullApproval() (gas: 5329984)\n[PASS] test_deliveryJustBeforeOldExpiryRetainsFullApproval() (gas: 5330072)\n[PASS] test_deliveryJustBeforeRequestDeadlineRetainsFullApproval() (gas: 5330138)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 105.92ms (9.44ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:ReverseOrderLaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64815)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 79097)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9582420)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8196768)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 193201216)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 108.86ms (92.78ms CPU time)\n\nRan 7 tests for test/HookBinding.t.sol:HookBindingTest\n[PASS] test_buySubmissionRequiresHookHandoffBeforeCharging() (gas: 27904126)\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5623463)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 592361)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 13687939)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 4760220)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 15028426)\n[PASS] test_sellSubmissionRequiresHookHandoffBeforeCharging() (gas: 28441285)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 111.99ms (43.92ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64815)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 78641)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9547880)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8196370)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 80857111)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 115.33ms (67.49ms CPU time)\n\nRan 1 test for test/Oracle.t.sol:OracleGasTest\n[PASS] test_callbackFitsBelow200kColdTransaction() (gas: 2041560)\nLogs:\n  callback gas including external call: 78063\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 124.62ms (5.71ms CPU time)\n\nRan 20 tests for test/Trading.t.sol:ReverseOrderTradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9663021, ~: 9666630)\nLogs:\n  Bound result 644938477035559046280\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 10034843)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 233460)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23928363)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5218964)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10663530)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5248565)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4636966)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5566910)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13171107)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 15958313)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5342823)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5975057)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117361)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10300256)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5364936)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453777)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100600)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 342627)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11588088)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 865.02ms (941.00ms CPU time)\n\nRan 16 tests for test/AdversarialOracle.t.sol:AdversarialOracleTest\n[PASS] testFuzz_malformedSignatureLengthCannotConsumeRequest(uint8) (runs: 1000, μ: 4508779, ~: 4508627)\nLogs:\n  Bound result 28\n\n[PASS] test_attestationIssuedBeforeSubmissionIsRefused() (gas: 4588977)\n[PASS] test_callbackHasNoDependencyOnTokenNftIntakeOrPoolReads() (gas: 4632939)\n[PASS] test_configurationRejectsEveryInvalidBoundaryWithoutAdvancingVersion() (gas: 2306671)\n[PASS] test_everySignedFieldRejectsPostSignatureMutation() (gas: 22128370)\n[PASS] test_explicitVerifierReplacesGateInDomainAndBody() (gas: 4992210)\n[PASS] test_failedOraclePaymentLeavesNoRequestAndCanRetry() (gas: 3886681)\n[PASS] test_identicalReasonFromAnotherUserDoesNotShareAttestation() (gas: 6655838)\n[PASS] test_mainnetDefaultsMatchAssignment() (gas: 65703)\n[PASS] test_rejectedAndClearedIdsCannotReplayOrAlterNewActiveRequest() (gas: 10985891)\n[PASS] test_rejectionReleasesSlotAndResubmissionNeedsFreshDecision() (gas: 7693973)\n[PASS] test_signatureRejectsHighSAndInvalidV() (gas: 4683745)\n[PASS] test_signatureRejectsWrongNameVersionAndDomainChain() (gas: 4860681)\n[PASS] test_timeoutAndApprovalBoundaryAtLastPermittedSecond() (gas: 5220117)\n[PASS] test_zeroOraclePriceAndZeroReturnedIdAreHandledAtomically() (gas: 3808019)\n[PASS] test_zeroVerifierMeansThisGateAndIsStoredResolved() (gas: 3748615)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 969.79ms (948.26ms CPU time)\n\nRan 20 tests for test/Trading.t.sol:TradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9628458, ~: 9632063)\nLogs:\n  Bound result 644938477035559046280\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 10000499)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 232988)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23796677)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5185001)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10583138)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5214320)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4637031)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5527899)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13137418)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 57087463)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5335130)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5899249)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117096)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10205469)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5330535)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453777)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100605)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 342675)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11484128)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.11s (1.11s 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, μ: 8073161, ~: 8073139)\nLogs:\n  Bound result 19\n  Bound result 3432\n  Bound result 244\n  Bound result 911\n  Bound result 157\n  Bound result 146\n  Bound result 16\n\n[PASS] test_constructorRejectsDirtyHighBitsInEveryNarrowWord() (gas: 20707250)\n[PASS] test_constructorRejectsTruncatedStaticArguments() (gas: 22207025)\n[PASS] test_factoryOwnerHandoverRequiresAcceptanceAndPreservesBinding() (gas: 8574269)\n[PASS] test_failedConfigurationRollsBackHelpersAndTheAddressStaysFree() (gas: 11140602)\n[PASS] test_helpersAreCreatedByEachGateAndExistingDependenciesStayIntact() (gas: 16162087)\n[PASS] test_hookRejectsMissingCodeWrongHookWrongCabalAndDuplicateBinding() (gas: 8196078)\n[PASS] test_pinnedValidNumericEdges() (gas: 16137138)\n[PASS] test_protocolVectorPinsAllFifteenFieldsTypeStringAndDomain() (gas: 15449)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.25s (1.27s CPU time)\n\nRan 22 tests for test/Oracle.t.sol:OracleTest\n[PASS] testFuzz_attestationFieldsAreBound(uint8) (runs: 256, μ: 4485793, ~: 4482348)\nLogs:\n  Bound result 2\n\n[PASS] test_280UnicodeCharactersAccepted281Rejected() (gas: 7551853)\n[PASS] test_approvalNeverOutlivesAttestation() (gas: 4530004)\n[PASS] test_attestationCannotBeReusedForAnotherRequest() (gas: 7827686)\n[PASS] test_badSignerDomainAndTampering() (gas: 4810916)\n[PASS] test_bodyIsCanonicalJsonWithConsumerAndStoredEscapedQuestion() (gas: 14363554)\n[PASS] test_configuredPanelParametersFlowIntoBodyAndChecks() (gas: 4966937)\n[PASS] test_controlCharactersAndGuillemetsRejected() (gas: 3946320)\n[PASS] test_intakeFailureUnderpaymentDuplicateIdAndReentry() (gas: 7830902)\n[PASS] test_liveFormatDeliveryWithDistinctOracleIdApproves() (gas: 4551732)\n[PASS] test_malformedUTF8Rejected() (gas: 249790)\n[PASS] test_oldPendingUsesSnapshotIntakeSignerAndDomain() (gas: 5799924)\n[PASS] test_onlyIntakeOnlyPendingReplayAndUnknownIds() (gas: 4644635)\n[PASS] test_oracleClockMayRunSlightlyAheadAndValidityMayBeLong() (gas: 4529900)\n[PASS] test_ownerConfigSnapshotsInvalidatesOldExecutionAndCanClear() (gas: 6130621)\n[PASS] test_questionHashMustMatchStoredQuestionAndWindow() (gas: 6933761)\n[PASS] test_quotesInsideReasonCannotCloseTheDelimiter() (gas: 4381054)\n[PASS] test_sellQuestionIncludesHoldingsPriceBasisTimeNftAndReason() (gas: 11330781)\n[PASS] test_submitPaysExactlyQuotedPriceAndRevokesAllowance() (gas: 3478532)\n[PASS] test_timeoutClearsNoLateCallbackNoTradeFundsEscrowed() (gas: 6655465)\n[PASS] test_trueApprovesForFiveMinutesAndFalseRejects() (gas: 7792450)\n[PASS] test_wrongChainAndSizeAndConcurrentRequestRejected() (gas: 3655388)\nSuite result: ok. 22 passed; 0 failed; 0 skipped; finished in 1.35s (1.33s CPU time)\n\nRan 7 tests for test/ReasonEscaping.t.sol:ReasonEscapingTest\n[PASS] testFuzz_arbitraryBytesAreJudgedLikeAnIndependentDecoder(bytes) (runs: 1000, μ: 15530, ~: 12712)\n[PASS] testFuzz_oneCorruptedByteIsJudgedLikeAnIndependentDecoder(bytes32,uint16,uint16,uint8) (runs: 1000, μ: 272891, ~: 181037)\nLogs:\n  Bound result 226\n  Bound result 12\n\n[PASS] testFuzz_wellFormedTextOfEveryWidthIsCountedEscapedAndQuotedExactly(bytes32,uint16) (runs: 1000, μ: 2071985, ~: 1822334)\nLogs:\n  Bound result 110\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.43s (2.81s CPU time)\n\nRan 7 tests for test/HookBinding.t.sol:ReverseOrderHookBindingTest\n[PASS] test_buySubmissionRequiresHookHandoffBeforeCharging() (gas: 39738304)\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5657783)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 593669)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 24877374)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 15427341)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 26221970)\n[PASS] test_sellSubmissionRequiresHookHandoffBeforeCharging() (gas: 40290359)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 1.43s (100.95ms CPU time)\n\nRan 3 tests for test/GateLiveHook.t.sol:GateHookReadFuzzTest\n[PASS] testFuzz_onlyTheExactCabalImdAndGateAreAccepted(address,address,address,bool) (runs: 512, μ: 3849719, ~: 4058793)\n[PASS] testFuzz_onlyTheExactPoolKeyIsAccepted(uint8,uint256,bool) (runs: 512, μ: 3779619, ~: 4008878)\nLogs:\n  Bound result 3\n\n[PASS] test_pinnedNearMisses() (gas: 4233386)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 1.43s (2.39s CPU time)\n\nRan 9 tests for test/EconomicProperties.t.sol:EconomicPropertiesTest\n[PASS] testFuzz_feeCannotExceedHalfPercentAndRoundingIsBounded(uint256) (runs: 1000, μ: 17463, ~: 17696)\n[PASS] testFuzz_priceMovementSymmetricMonotoneAndBounded(uint160,uint160,uint160) (runs: 1000, μ: 51286, ~: 51230)\nLogs:\n  Bound result 36074192516557804838109915348841724629\n  Bound result 1461501637294828725687127027878173104307090820732\n  Bound result 1461501637322683207846964273464666395828328649568\n\n[PASS] testFuzz_repeatedBuySellCannotCreateImd(uint256,uint8) (runs: 1000, μ: 16580356, ~: 17465145)\nLogs:\n  Bound result 358928676759192577222\n  Bound result 1\n\n[PASS] test_feeAndPriceKnownBoundaries() (gas: 58487)\n[PASS] test_insufficientExecutionAllowancePreservesApprovalAndCanRetry() (gas: 5472990)\n[PASS] test_realTradesAtFeeRoundingEdges() (gas: 23364977)\n[PASS] test_sellApprovalSurvivesBalanceDropAndExecutesOnceRestored() (gas: 9891494)\n[PASS] test_sellLargerThanTrackedHoldingsClearsTheRecordWithoutUnderflow() (gas: 9678863)\n[PASS] test_sellSlippageFailureRollsBackFeePositionAndCostBasis() (gas: 10260509)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.43s (1.41s CPU time)\n\nRan 7 tests for test/QuestionProperties.t.sol:QuestionPropertiesTest\n[PASS] testFuzz_jsonRoundTripsUntrustedPrintableAscii(bytes,bool,uint128) (runs: 1000, μ: 5112645, ~: 5638692)\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.43s (1.45s 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            | 1636  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | clear              | 1585  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | cycle              | 1631  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | donate             | 1618  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | reconfigure        | 1616  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refuseCallback     | 1690  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refusePayment      | 1599  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refuseUnauthorized | 1686  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | request            | 1640  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | resolve            | 1683  | 0       | 0        |\n╰------------------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 4\n  Bound result 48\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 300\n  Bound result 11188\n  Bound result 400\n  Bound result 500000000000000000\n  Bound result 581543581218402496\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 1975\n  Bound result 13243\n  Bound result 6\n  Bound result 2\n  Bound result 23\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 19\n  Bound result 2942\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 20\n  Bound result 385249019867072579\n  Bound result 123\n  Bound result 499999999999999699\n  Bound result 6\n  Bound result 714412162779451329\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 3555\n  Bound result 7\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n\n[PASS] test_handlerExercisesPaymentsFailuresBothAnswersAndClearing() (gas: 18838876)\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 7.01s (7.01s 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            | 1518  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1433  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1462  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1467  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1570  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1453  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1476  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1486  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1447  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1532  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1540  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 24\n  Bound result 9156\n  Bound result 1791409411\n  Bound result 7446\n  Bound result 3783\n  Bound result 999999999999999999664\n  Bound result 10232\n  Bound result 182204407139524322568\n  Bound result 22\n  Bound result 18\n  Bound result 2\n  Bound result 2807\n  Bound result 895484616941158587428\n  Bound result 587\n  Bound result 1000\n  Bound result 402\n  Bound result 1503\n  Bound result 8\n  Bound result 999999999999999999609\n  Bound result 21341\n  Bound result 3\n  Bound result 20124\n  Bound result 1413056653104\n  Bound result 1334\n  Bound result 224\n  Bound result 19\n  Bound result 10000000000000000000\n  Bound result 874181052615498961662\n  Bound result 22\n  Bound result 1\n  Bound result 12044993\n  Bound result 12\n  Bound result 8\n  Bound result 10\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16395913)\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.17s (8.17s 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            | 1518  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1433  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1462  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1467  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1570  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1453  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1476  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1486  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1447  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1532  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1540  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 7\n  Bound result 14939\n  Bound result 1791409411\n  Bound result 0\n  Bound result 0\n  Bound result 999999999999999999664\n  Bound result 9254\n  Bound result 182204407139524322568\n  Bound result 22\n  Bound result 18\n  Bound result 7\n  Bound result 2734\n  Bound result 895484616941158587428\n  Bound result 0\n  Bound result 1000\n  Bound result 2231\n  Bound result 0\n  Bound result 999999999999999999609\n  Bound result 18150\n  Bound result 11\n  Bound result 810663491572711043348\n  Bound result 1413056653104\n  Bound result 2828\n  Bound result 224\n  Bound result 19\n  Bound result 10000000000000000000\n  Bound result 874181052615498936244\n  Bound result 18\n  Bound result 1\n  Bound result 12044993\n  Bound result 12\n  Bound result 17\n  Bound result 11\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16353806)\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.18s (8.17s CPU time)\n\nRan 28 test suites in 8.18s (36.95s CPU time): 178 tests passed, 0 failed, 0 skipped (178 total tests)\n","passed":true},{"durationMs":71,"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\":80,\"README.md\":59,\"docs/DEPLOYMENT.md\":80,\"docs/ORACLE.md\":97,\"docs/SECURITY.md\":29,\"docs/dependencies.json\":26,\"foundry.toml\":20,\"script/HookSaltMiner.sol\":23,\"src/CabalCoin.sol\":11,\"src/CabalGate.sol\":511,\"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\":337,\"test/CabalCoin.t.sol\":62,\"test/CabalFixture.sol\":362,\"test/EconomicProperties.t.sol\":188,\"test/GateFactoryEdges.t.sol\":271,\"test/GateLaunch.t.sol\":542,\"test/GateLaunchChecks.md\":54,\"test/GateLiveHook.t.sol\":414,\"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\":24,\"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":"b12f04a3e5ebac41a14bb3b55fb69d365ba6d987a6d0028cb63d7e2ff4666d0a","verifiedTreeHash":"e8fdd37b8d6cfb785a1af6f35ce3249fabf34437","verifierVersion":"0.1.0+8af37dff"},{"checks":[{"durationMs":300025,"exitCode":137,"name":"build","output":"Compiling 120 files with Solc 0.8.26\n","passed":false}],"detail":"build failed with exit code 137","evaluation":"checks","profile":"foundry","status":"rejected","submissionHash":"b4e5abf2067edc74fe2b74e0163c4df0fe2aec7d1cde251ec22d85a0e0d65d4c","verifiedTreeHash":"c471222cac5aeff6b3a57f07d4fec47c5cfa33f4","verifierVersion":"0.1.0+5d71dfd4"},{"checks":[{"durationMs":140897,"exitCode":0,"name":"build","output":"Compiling 120 files with Solc 0.8.26\nSolc 0.8.26 finished in 140.66s\nCompiler run successful with warnings:\nWarning (2018): Function state mutability can be restricted to view\n   --> test/GateFactoryEdges.t.sol:229:5:\n    |\n229 |     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[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: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:430:9\n    │\n430 │         _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:227:9\n    │\n227 │         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:209:64\n    │\n209 │     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:221:90\n    │\n221 │                 || cfg.maxBuyAmount == 0 || 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:222:40\n    │\n222 │                 || 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:284:14\n    │\n284 │           id = IIntake(cfg.intake)\n    │ ┏━━━━━━━━━━━━━━┛\n285 │ ┃             .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:303:9\n    │\n303 │         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:287:13\n    │\n287 │         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:293:24\n    │\n293 │             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:294:23\n    │\n294 │             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:297:21\n    │\n297 │             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:314:35\n    │\n314 │         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:320:74\n    │\n320 │                 || 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:321:20\n    │\n321 │                 || 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:336:38\n    │\n336 │             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:341:9\n    │\n341 │         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:336:31\n    │\n336 │             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:358:33\n    │\n358 │             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:360:33\n    │\n360 │             if (!staleConfig && block.timestamp < r.approvedUntil) revert InvalidRequest();\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[block-timestamp]: usage of `block.timestamp` in a comparison may be manipulated by validators\n    ╭▸ src/CabalGate.sol:392:13\n    │\n392 │         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:422:9\n    │\n422 │         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:414:44\n    │\n414 │             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[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:454:26\n    │\n454 │         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:486:13\n    │\n486 │         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:506:13\n    │\n506 │             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/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\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":8184,"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 730.97µs (833.10µs CPU time)\n\nRan 1 test for test/Trading.t.sol:ReverseTokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5205711)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 8.36ms (3.59ms CPU time)\n\nRan 1 test for test/GateLaunch.t.sol:GateEmptyEvmLaunchTest\n[PASS] test_gateDeploysInAnEmptyEvmWithTheManifestWords() (gas: 28103301)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 28.43ms (28.27ms CPU time)\n\nRan 10 tests for test/GateLaunch.t.sol:GateLaunchTest\n[PASS] test_constructorIgnoresDependencyCodeAndHookState() (gas: 16032750)\n[PASS] test_constructorSortsCurrenciesWhenCabalSortsAboveImd() (gas: 12272898)\n[PASS] test_existingHookOwnerBindsGateOnceAndRefusesSecondGate() (gas: 16211054)\n[PASS] test_explicitOwnerControlsConfigurationInsteadOfFactory() (gas: 8303710)\n[PASS] test_factoryDeploysOnlyGateWithAllFifteenManifestWords() (gas: 28629703)\n[PASS] test_flatConstructorRetainsEveryValidation() (gas: 70090067)\n[PASS] test_hookRefusesGateWithSwappedTokenRoles() (gas: 8381586)\n[PASS] test_ownerConfigureKeepsLiveDependencyChecksAndOracleBounds() (gas: 9271118)\n[PASS] test_requestRevertsWhenTheHookReportsAnotherKeyCabalImdOrGate() (gas: 12789852)\n[PASS] test_requestSucceedsOnlyOnceTheHookReportsThisGate() (gas: 14721983)\nSuite result: ok. 10 passed; 0 failed; 0 skipped; finished in 64.25ms (77.41ms CPU time)\n\nRan 1 test for test/OracleSigner.t.sol:OracleSignerTest\n[PASS] test_registrySignatureIsNotAnEOASignatureForTheConfiguredSigner() (gas: 4988860)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 73.71ms (2.12ms CPU time)\n\nRan 3 tests for test/OracleLatency.t.sol:OracleLatencyTest\n[PASS] test_deliveryAtOldExpiryRetainsFullApproval() (gas: 5330187)\n[PASS] test_deliveryJustBeforeOldExpiryRetainsFullApproval() (gas: 5330275)\n[PASS] test_deliveryJustBeforeRequestDeadlineRetainsFullApproval() (gas: 5330341)\nSuite result: ok. 3 passed; 0 failed; 0 skipped; finished in 79.77ms (7.32ms CPU time)\n\nRan 5 tests for test/Launch.t.sol:LaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64802)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 78629)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9548036)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8196126)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 80854255)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 90.81ms (54.48ms CPU time)\n\nRan 2 tests for test/SubmissionGas.t.sol:SubmissionGasTest\n[PASS] test_longestReasonStaysUnderBudget() (gas: 1255354)\n[PASS] test_shortBuyAndSellStayUnderBudget() (gas: 1121472)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 90.84ms (1.59ms CPU time)\n\nRan 1 test for test/Trading.t.sol:TokenOnlySeedTest\n[PASS] test_firstBuyOnFreshManagerWithOnlyCabalSeeded() (gas: 5202749)\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 102.23ms (2.55ms CPU time)\n\nRan 1 test for test/Oracle.t.sol:OracleGasTest\n[PASS] test_callbackFitsBelow200kColdTransaction() (gas: 2041567)\nLogs:\n  callback gas including external call: 78063\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 113.50ms (4.89ms CPU time)\n\nRan 7 tests for test/HookBinding.t.sol:HookBindingTest\n[PASS] test_buySubmissionRequiresHookHandoffBeforeCharging() (gas: 27895162)\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5623543)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 592316)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 13683664)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 4759768)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 15024101)\n[PASS] test_sellSubmissionRequiresHookHandoffBeforeCharging() (gas: 28432287)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 134.58ms (49.67ms CPU time)\n\nRan 7 tests for test/HookBinding.t.sol:ReverseOrderHookBindingTest\n[PASS] test_buySubmissionRequiresHookHandoffBeforeCharging() (gas: 39718738)\n[PASS] test_compoundOnARangeTheHookDoesNotOwnRevertsAndChangesNothing() (gas: 5657872)\n[PASS] test_feeStateMachineBlocksSwapsAndCompoundingUntilTheGateSettles() (gas: 593624)\n[PASS] test_firstValidPoolBindsTheHookSoDeploymentAndInitializationMustBeAtomic() (gas: 24867505)\n[PASS] test_initializationRefusesNativeCurrencyMisorderedKeysAndKeysNamingAnotherHook() (gas: 15426303)\n[PASS] test_liquidityDonationsAndFeeClaimsPassBeforeAndAfterBindingWhileSwapsNeverDo() (gas: 26212051)\n[PASS] test_sellSubmissionRequiresHookHandoffBeforeCharging() (gas: 40270758)\nSuite result: ok. 7 passed; 0 failed; 0 skipped; finished in 684.96ms (80.76ms CPU time)\n\nRan 22 tests for test/Oracle.t.sol:OracleTest\n[PASS] testFuzz_attestationFieldsAreBound(uint8) (runs: 256, μ: 4485718, ~: 4482254)\nLogs:\n  Bound result 13\n\n[PASS] test_280UnicodeCharactersAccepted281Rejected() (gas: 7551946)\n[PASS] test_approvalNeverOutlivesAttestation() (gas: 4530062)\n[PASS] test_attestationCannotBeReusedForAnotherRequest() (gas: 7827776)\n[PASS] test_badSignerDomainAndTampering() (gas: 4810927)\n[PASS] test_bodyIsCanonicalJsonWithConsumerAndStoredEscapedQuestion() (gas: 14363689)\n[PASS] test_configuredPanelParametersFlowIntoBodyAndChecks() (gas: 4966991)\n[PASS] test_controlCharactersAndGuillemetsRejected() (gas: 3946566)\n[PASS] test_intakeFailureUnderpaymentDuplicateIdAndReentry() (gas: 7831170)\n[PASS] test_liveFormatDeliveryWithDistinctOracleIdApproves() (gas: 4551833)\n[PASS] test_malformedUTF8Rejected() (gas: 249860)\n[PASS] test_oldPendingUsesSnapshotIntakeSignerAndDomain() (gas: 5799981)\n[PASS] test_onlyIntakeOnlyPendingReplayAndUnknownIds() (gas: 4644649)\n[PASS] test_oracleClockMayRunSlightlyAheadAndValidityMayBeLong() (gas: 4529958)\n[PASS] test_ownerConfigSnapshotsInvalidatesOldExecutionAndCanClear() (gas: 6130763)\n[PASS] test_questionHashMustMatchStoredQuestionAndWindow() (gas: 6933792)\n[PASS] test_quotesInsideReasonCannotCloseTheDelimiter() (gas: 4381075)\n[PASS] test_sellQuestionIncludesHoldingsPriceBasisTimeNftAndReason() (gas: 11330891)\n[PASS] test_submitPaysExactlyQuotedPriceAndRevokesAllowance() (gas: 3478623)\n[PASS] test_timeoutClearsNoLateCallbackNoTradeFundsEscrowed() (gas: 6655677)\n[PASS] test_trueApprovesForFiveMinutesAndFalseRejects() (gas: 7792671)\n[PASS] test_wrongChainAndSizeAndConcurrentRequestRejected() (gas: 3655634)\nSuite result: ok. 22 passed; 0 failed; 0 skipped; finished in 936.42ms (929.86ms CPU time)\n\nRan 5 tests for test/CabalCoin.t.sol:CabalCoinTest\n[PASS] testFuzz_transferConservesSupply(uint256) (runs: 256, μ: 83200, ~: 83375)\nLogs:\n  Bound result 954991639303731667017308155\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.27s (1.27s CPU time)\n\nRan 5 tests for test/Launch.t.sol:ReverseOrderLaunchTest\n[PASS] test_manifestArgumentsLaunchInOneTransaction() (gas: 64802)\n[PASS] test_secondPoolThroughTheLaunchedHookIsRefused() (gas: 79085)\n[PASS] test_tradingWorksOnTheFactoryLaunchedPool() (gas: 9582585)\n[PASS] test_unspecifiedOwnerIsTheLaunchOriginatorWhoBindsTheGate() (gas: 8196345)\n[PASS] test_zeroOwnerFallsBackToTheOriginatorAndExplicitOwnerIsKept() (gas: 193196633)\nSuite result: ok. 5 passed; 0 failed; 0 skipped; finished in 1.29s (74.84ms CPU time)\n\nRan 20 tests for test/Trading.t.sol:TradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9628605, ~: 9632205)\nLogs:\n  Bound result 318592731272573426202\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 10000722)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 232962)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23797313)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5185138)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10583304)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5214501)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4637155)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5527912)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13137737)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 57084065)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5335234)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5899496)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117029)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10205744)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5330605)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100513)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 342723)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11484401)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.29s (1.34s 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, μ: 8083323, ~: 8083320)\nLogs:\n  Bound result 1000000000000000000000000\n  Bound result 416500914\n  Bound result 1922\n  Bound result 2989\n  Bound result 130\n  Bound result 2\n  Bound result 1\n\n[PASS] test_constructorRejectsDirtyHighBitsInEveryNarrowWord() (gas: 14601379)\n[PASS] test_constructorRejectsTruncatedStaticArguments() (gas: 15941603)\n[PASS] test_factoryOwnerHandoverRequiresAcceptanceAndPreservesBinding() (gas: 8584754)\n[PASS] test_failedConfigurationRollsBackHelpersAndTheAddressStaysFree() (gas: 11144655)\n[PASS] test_helpersAreCreatedByEachGateAndExistingDependenciesStayIntact() (gas: 16181963)\n[PASS] test_hookRejectsMissingCodeWrongHookWrongCabalAndDuplicateBinding() (gas: 8206321)\n[PASS] test_pinnedValidNumericEdges() (gas: 16156965)\n[PASS] test_protocolVectorPinsAllFifteenFieldsTypeStringAndDomain() (gas: 15449)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.31s (865.66ms CPU time)\n\nRan 7 tests for test/QuestionProperties.t.sol:QuestionPropertiesTest\n[PASS] testFuzz_jsonRoundTripsUntrustedPrintableAscii(bytes,bool,uint128) (runs: 1000, μ: 5000167, ~: 4452015)\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.31s (1.53s CPU time)\n\nRan 7 tests for test/ReasonEscaping.t.sol:ReasonEscapingTest\n[PASS] testFuzz_arbitraryBytesAreJudgedLikeAnIndependentDecoder(bytes) (runs: 1000, μ: 15250, ~: 12712)\n[PASS] testFuzz_oneCorruptedByteIsJudgedLikeAnIndependentDecoder(bytes32,uint16,uint16,uint8) (runs: 1000, μ: 286434, ~: 181018)\nLogs:\n  Bound result 115\n  Bound result 5\n\n[PASS] testFuzz_wellFormedTextOfEveryWidthIsCountedEscapedAndQuotedExactly(bytes32,uint16) (runs: 1000, μ: 2071172, ~: 1814791)\nLogs:\n  Bound result 77\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 (2.59s CPU time)\n\nRan 16 tests for test/AdversarialOracle.t.sol:AdversarialOracleTest\n[PASS] testFuzz_malformedSignatureLengthCannotConsumeRequest(uint8) (runs: 1000, μ: 4508850, ~: 4508707)\nLogs:\n  Bound result 25\n\n[PASS] test_attestationIssuedBeforeSubmissionIsRefused() (gas: 4589034)\n[PASS] test_callbackHasNoDependencyOnTokenNftIntakeOrPoolReads() (gas: 4632996)\n[PASS] test_configurationRejectsEveryInvalidBoundaryWithoutAdvancingVersion() (gas: 2307694)\n[PASS] test_everySignedFieldRejectsPostSignatureMutation() (gas: 22129260)\n[PASS] test_explicitVerifierReplacesGateInDomainAndBody() (gas: 4992263)\n[PASS] test_failedOraclePaymentLeavesNoRequestAndCanRetry() (gas: 3886816)\n[PASS] test_identicalReasonFromAnotherUserDoesNotShareAttestation() (gas: 6656069)\n[PASS] test_mainnetDefaultsMatchAssignment() (gas: 65683)\n[PASS] test_rejectedAndClearedIdsCannotReplayOrAlterNewActiveRequest() (gas: 10986234)\n[PASS] test_rejectionReleasesSlotAndResubmissionNeedsFreshDecision() (gas: 7694194)\n[PASS] test_signatureRejectsHighSAndInvalidV() (gas: 4683802)\n[PASS] test_signatureRejectsWrongNameVersionAndDomainChain() (gas: 4860736)\n[PASS] test_timeoutAndApprovalBoundaryAtLastPermittedSecond() (gas: 5220275)\n[PASS] test_zeroOraclePriceAndZeroReturnedIdAreHandledAtomically() (gas: 3808153)\n[PASS] test_zeroVerifierMeansThisGateAndIsStoredResolved() (gas: 3748635)\nSuite result: ok. 16 passed; 0 failed; 0 skipped; finished in 1.32s (1.31s CPU time)\n\nRan 20 tests for test/Trading.t.sol:ReverseOrderTradingTest\n[PASS] testFuzz_roundTripAccounting(uint256) (runs: 256, μ: 9663162, ~: 9666781)\nLogs:\n  Bound result 686040103840282835723\n\n[PASS] test_buyAndSellBurnFeesOwnLiquidityAndTrackBasis() (gas: 10034987)\n[PASS] test_callbacksOnlyManagerAndPermissionsMatch() (gas: 233434)\n[PASS] test_driftFromOtherTradesDoesNotInvalidateApprovalUntilDriftCap() (gas: 23929007)\n[PASS] test_estimateMatchesExecutionWithActiveLiquidity() (gas: 5219110)\n[PASS] test_executeWithInlineMinimumNeedsNoSeparateCall() (gas: 10663702)\n[PASS] test_executionRequiresRequesterCorrectSideApprovalAndOnce() (gas: 5248755)\n[PASS] test_expiryAtFiveMinutesAndClear() (gas: 4637090)\n[PASS] test_factoryCanAddCollectFeesAndRemoveDespiteSwapGate() (gas: 5566932)\n[PASS] test_fullSaleClearsBasisAndWeightedBuys() (gas: 13171434)\n[PASS] test_initializationOnceByAnySenderWithLaunchParametersAndImmutablePairAfterBinding() (gas: 15956803)\n[PASS] test_liquidityChangeCannotBypassActualImpactLimit() (gas: 5342927)\n[PASS] test_minOutputMandatoryAndFailedExecutionRollsBackAllTransfers() (gas: 5975313)\n[PASS] test_onePoolOneGateAndNoExactOutput() (gas: 117294)\n[PASS] test_protocolOwnedLiquidityAloneKeepsSubmissionsOpen() (gas: 10300540)\n[PASS] test_protocolPositionCannotBeWithdrawnAndCanCompound() (gas: 5365015)\n[PASS] test_runtimeSizeAndNoEscapeHatches() (gas: 4453752)\n[PASS] test_swapsOutsideGateRevertBothWays() (gas: 100508)\n[PASS] test_transferThatReturnsSuccessWithoutPaymentRejected() (gas: 342675)\n[PASS] test_transferredHoldingsHaveUnknownBasisAndRecordsReconcile() (gas: 11588362)\nSuite result: ok. 20 passed; 0 failed; 0 skipped; finished in 1.32s (1.42s CPU time)\n\nRan 9 tests for test/EconomicProperties.t.sol:EconomicPropertiesTest\n[PASS] testFuzz_feeCannotExceedHalfPercentAndRoundingIsBounded(uint256) (runs: 1000, μ: 17525, ~: 17678)\n[PASS] testFuzz_priceMovementSymmetricMonotoneAndBounded(uint160,uint160,uint160) (runs: 1000, μ: 51393, ~: 51343)\nLogs:\n  Bound result 161673931537559274861587291147120824310483308\n  Bound result 665508266041243158166151666374183535913461254\n  Bound result 1460836129069556984537538860841936826344825989392\n\n[PASS] testFuzz_repeatedBuySellCannotCreateImd(uint256,uint8) (runs: 1000, μ: 16324219, ~: 17465492)\nLogs:\n  Bound result 8891576875153\n  Bound result 3\n\n[PASS] test_feeAndPriceKnownBoundaries() (gas: 58513)\n[PASS] test_insufficientExecutionAllowancePreservesApprovalAndCanRetry() (gas: 5473149)\n[PASS] test_realTradesAtFeeRoundingEdges() (gas: 23365493)\n[PASS] test_sellApprovalSurvivesBalanceDropAndExecutesOnceRestored() (gas: 9891833)\n[PASS] test_sellLargerThanTrackedHoldingsClearsTheRecordWithoutUnderflow() (gas: 9679049)\n[PASS] test_sellSlippageFailureRollsBackFeePositionAndCostBasis() (gas: 10260848)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 1.32s (1.31s 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            | 1608  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | clear              | 1634  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | cycle              | 1610  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | donate             | 1621  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | reconfigure        | 1631  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refuseCallback     | 1683  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refusePayment      | 1670  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | refuseUnauthorized | 1622  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | request            | 1676  | 0       | 0        |\n|------------------------+--------------------+-------+---------+----------|\n| GateOnlyRequestHandler | resolve            | 1629  | 0       | 0        |\n╰------------------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 1\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 742518007150971580\n  Bound result 719251753383892620\n  Bound result 128\n  Bound result 3000\n  Bound result 12\n  Bound result 636\n  Bound result 22104\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 16397\n  Bound result 16\n  Bound result 3600\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 2\n  Bound result 573688670\n  Bound result 172\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 427\n  Bound result 811045106551257726\n  Bound result 3513\n  Bound result 1999\n  Bound result 5000\n  Bound result 500000000000000000\n  Bound result 1000000000000000000\n  Bound result 13\n  Bound result 54647071825257952\n  Bound result 21161\n  Bound result 554\n  Bound result 33010932\n  Bound result 528440507052760417\n  Bound result 1360\n  Bound result 8\n  Bound result 650\n  Bound result 12\n  Bound result 31\n  Bound result 19\n  Bound result 500\n  Bound result 18\n  Bound result 4\n\n[PASS] test_handlerExercisesPaymentsFailuresBothAnswersAndClearing() (gas: 18841340)\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 7.38s (7.38s 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            | 1476  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1475  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1443  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1552  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1543  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1457  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1506  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1519  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1432  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1506  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1475  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 200\n  Bound result 23\n  Bound result 866986174381644857406\n  Bound result 4009091385556280158396\n  Bound result 499999999999999699\n  Bound result 192195066069086249980\n  Bound result 667684796620568754817\n  Bound result 1515\n  Bound result 74694106082519064\n  Bound result 24\n  Bound result 4407540536140944853623\n  Bound result 4950\n  Bound result 242\n  Bound result 18\n  Bound result 235416685293440704895\n  Bound result 999999999999999999729\n  Bound result 7\n  Bound result 1590\n  Bound result 11155111\n  Bound result 24\n  Bound result 108\n  Bound result 16381\n  Bound result 3\n  Bound result 1114111\n  Bound result 999999999999999999626\n  Bound result 3599\n  Bound result 402\n  Bound result 15\n  Bound result 3720614964\n  Bound result 1\n  Bound result 29\n  Bound result 500\n  Bound result 11155111\n  Bound result 9925\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16354611)\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.04s (8.02s 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            | 1476  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | clear              | 1475  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | compound           | 1443  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | donate             | 1552  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | execute            | 1543  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | reconfigure        | 1457  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | rejectBadExecution | 1506  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | request            | 1519  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | resolve            | 1432  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | trade              | 1506  | 0       | 0        |\n|--------------+--------------------+-------+---------+----------|\n| CabalHandler | transfer           | 1475  | 0       | 0        |\n╰--------------+--------------------+-------+---------+----------╯\n\nLogs:\n  Bound result 200\n  Bound result 23\n  Bound result 866986174381644857406\n  Bound result 1983746038540546693142\n  Bound result 499999999999999699\n  Bound result 192195066069086250013\n  Bound result 667684796620568754817\n  Bound result 2976\n  Bound result 112707416\n  Bound result 74694106082519064\n  Bound result 839884766566879557238\n  Bound result 24\n  Bound result 4407540536140944853623\n  Bound result 12780\n  Bound result 242\n  Bound result 18\n  Bound result 112412735151009893208\n  Bound result 19\n  Bound result 1590\n  Bound result 11155111\n  Bound result 5\n  Bound result 108\n  Bound result 20635\n  Bound result 3\n  Bound result 1114111\n  Bound result 999999999999999999626\n  Bound result 3599\n  Bound result 402\n  Bound result 14\n  Bound result 6824\n  Bound result 1\n  Bound result 29\n  Bound result 500\n  Bound result 11058\n\n[PASS] test_handlerExercisesSuccessFailureExpiryAndCompounding() (gas: 16396718)\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.07s (8.08s CPU time)\n\nRan 25 test suites in 8.07s (37.66s CPU time): 167 tests passed, 0 failed, 0 skipped (167 total tests)\n","passed":true},{"durationMs":71,"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\":101,\"README.md\":59,\"docs/DEPLOYMENT.md\":76,\"docs/ORACLE.md\":97,\"docs/SECURITY.md\":29,\"docs/dependencies.json\":26,\"foundry.toml\":20,\"launch.json\":26,\"script/HookSaltMiner.sol\":23,\"src/CabalCoin.sol\":11,\"src/CabalGate.sol\":510,\"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\":337,\"test/CabalCoin.t.sol\":62,\"test/CabalFixture.sol\":358,\"test/EconomicProperties.t.sol\":188,\"test/GateFactoryEdges.t.sol\":267,\"test/GateLaunch.t.sol\":551,\"test/GateLaunchChecks.md\":54,\"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":"cc40001ab6260e632d144bee4222ecccdbf27500f2125106a54bc69f38f6b7e6","verifiedTreeHash":"27a3d5c03e964df7ede626eebc021ab5b436171a","verifierVersion":"0.1.0+14166f2e"}]}