{"assessments":[],"deployments":[],"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":"419a453b-0db0-4119-be46-9357aa6e7612","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"2425de0acd1ba15baa61f598cf4a8aa8801fe53a5b9672e276844d8572d3660c","dependsOn":["write_foundry_tests","frontend_for_contract"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"6b037a7b6601e883cf8a906c1520c0624817d42d8310b65c2f43679204608af3","skillId":"adversarial-review","tools":[]},"key":"adversarial_review","kind":"code","role":"review","skillHash":"6b037a7b6601e883cf8a906c1520c0624817d42d8310b65c2f43679204608af3","skillId":"adversarial-review","state":"accepted"},{"acceptedSubmissionHash":"033ad0eb30ccfc3442d36fbf1bbe63a92e9abaec1bb3b77c4e3b5e1a03686954","dependsOn":["write_foundry_tests","frontend_for_contract"],"execution":{"network":true,"optionalTools":["browser"],"profile":"none","requires":["network"],"skillHash":"fd33b6741366d364a55a4c0ba2bc4f5d329cec0b62f27a83289dc5b30ab03575","skillId":"design-critic","tools":[]},"key":"design_critic","kind":"code","role":"review","skillHash":"fd33b6741366d364a55a4c0ba2bc4f5d329cec0b62f27a83289dc5b30ab03575","skillId":"design-critic","state":"accepted"},{"acceptedSubmissionHash":"addcf113ffecd299cc15b483f182beae561b8a3a8867420ffa308784b93aaa93","dependsOn":["write_foundry_tests"],"execution":{"mustProduce":["dist/index.html"],"network":true,"optionalTools":["browser"],"profile":"none","requires":["network"],"skillHash":"7a8712ac362fd9796a2d33fcee6ee3ad1adaefb41673944a34b3d34ef78b3e37","skillId":"frontend-for-contract","tools":[]},"key":"frontend_for_contract","kind":"code","role":"implement","skillHash":"7a8712ac362fd9796a2d33fcee6ee3ad1adaefb41673944a34b3d34ef78b3e37","skillId":"frontend-for-contract","state":"accepted"},{"acceptedSubmissionHash":"c9596110fab358a4a358c9bd56c91e2dbe536c99c687701e6333595d1bef588a","dependsOn":[],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","tools":[]},"key":"write_foundry_tests","kind":"code","role":"tests","skillHash":"4c76766b00591dfe982fe85d3de589fdb2f810e5137c301155d1c5e36a1d3b23","skillId":"write-foundry-tests","state":"accepted"}],"objective":"RESUME the Crown Model 2 (Throne) project from its accepted build. The build_contract_project node of the previous job was ACCEPTED - ThroneRegistry and CrownHook are built in this project workspace and their Foundry checks passed (verifiedTreeHash 547b5b33ceca12d11e16bef2d4046bd574ffe473). The write_foundry_tests node then failed with a runtime error (infrastructure, attempt 3), which is the only reason this continuation exists. Do NOT rebuild or redesign the contracts; work with the accepted build as it stands. Remaining work, in order: (1) the Foundry test suite for the existing contracts, (2) the canonical ticker site wired to them, (3) the independent adversarial review - after which the project's own launch stage proceeds as originally briefed.\n\nKey specification values the tests must pin down (from the accepted build's brief): hook cut default 100 bps per pool, configurable 0-500; in afterSwap the hook settles its delta via PoolManager.mint(address(this), currency.toId(), cut) and credits crownOwed[beneficiary][currency]; claim() redeems the hook ERC-6909 claim in its own unlock and pays the caller, zeroing first; during settlement only PoolManager calls and the registry staticcall read are allowed; challenge bond 0.01 ETH; stake window 72 hours; timelock 24 hours; quorum 0.05 ETH total staked; losing side 20% slashed (half pro-rata to winning stakers, half to treasury 0xf19F11Dee16a341671E6Ed3e209b704C1Bbc3E57), all refunds pull-pattern; failed-challenge cooldown 3 days; registry token address immutable per ticker; demo registry MIN_REIGN = 0 with the production default 7 days retained in code.\n\nRequired test coverage: registry and challenge math exact to the wei (bond, quorum, slash split, refunds); the hook delta fully settled on every swap (no CurrencyNotSettled); crownOwed backed 1:1 by the hook ERC-6909 claim balance at all times; claim() correctness and double-claim safety; a malicious-contract-beneficiary test whose receive() attempts to leave PoolManager debt, proving swaps still settle and fees still accrue; and the integration test - buy, challenge, stake, finalize, buy - asserting accrual flips to the new beneficiary and the registry token address is byte-identical before and after the dethrone.","parentJobId":"fde2af58-028f-491f-95b6-f9b5f1eddf69","planHash":"0d29a546b44e617efdd494bf694017601229750521437e868acb261952bf3dd6","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"9685c19c-ce28-4580-919f-92dff08e27a3","publication":{"commit":null,"deliveredAt":null,"repoUrl":"https://github.com/identity-md-launches/launch-1884-crown-model-2-throne"},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"52165","feedbackHash":"a61e59b74a82b7b7f3b2fa92d6d2aec81ea6b0a206e338dc739b58b5c2c280a6","nodeKey":"adversarial_review","submissionHash":"2425de0acd1ba15baa61f598cf4a8aa8801fe53a5b9672e276844d8572d3660c","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51250","feedbackHash":"b44714ed967e5bcd5e3d36b634f6edc45b6e76ecc3f976c91b1c7d300e5b19f9","nodeKey":"design_critic","submissionHash":"033ad0eb30ccfc3442d36fbf1bbe63a92e9abaec1bb3b77c4e3b5e1a03686954","tag1":"review:submission","tag2":"acceptance-v2","value":1},{"agentId":"51023","feedbackHash":"78e2d6ceb0f3039e76fcfb6ec3725a697018e4ce574d9ce8304ca7adf0718b6a","nodeKey":"frontend_for_contract","submissionHash":"addcf113ffecd299cc15b483f182beae561b8a3a8867420ffa308784b93aaa93","tag1":"verification:structural","tag2":"acceptance-v2","value":1},{"agentId":"52598","feedbackHash":"fc32069f549abec6e7c0ef518d5c66798d8b63604ff1a65da1adb32db2a7965c","nodeKey":"write_foundry_tests","submissionHash":"c9596110fab358a4a358c9bd56c91e2dbe536c99c687701e6333595d1bef588a","tag1":"verification:checks","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"ac75c0f4f561789819115574423ea1c6d408951375a14450f1f7ca8e823249b5","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":null,"device":"0cf632e317dfab7a","findings":[{"citation":"unresolved","description":"Now: in the shipped export (deployment.json has null addresses) the throne card's 'Crown fees, all reigns' table prints the literal numbers 0 for ETH and THRONE accrued and claimed, in the same cells and type that the live table uses for values read from crownPaid/crownClaimed. The only hint that these are not readings is the status line above the card. Change to: replace the four literal 0 cells with the same '…' token the placeholder holder line already uses (App.tsx line 520 prints '…' when configured but not yet read), or an empty cell with aria-label 'Not read yet', so the table makes no claim; the layout stays identical. Why: the reference calls a made-up balance faked ('a made-up balance, sample data shown as live'); a visitor who skims past the status line reads '0 ETH accrued' as a fact about the contracts, which the page has not read and which will be wrong the moment the pool trades.","line":528,"path":"web/src/App.tsx","reproduction":"Width 390 (also 1440). Open dist/index.html with the shipped dist/deployment.json (registry, hook, token all null). The status line reads 'Not launched yet…', then the dark throne card shows the table Currency / Accrued / Claimed with rows 'ETH 0 0' and 'THRONE 0 0'. Probe screenshot test/scratch/taste/shots/390.png shows both rows with 0 in every cell; no RPC read was issued (useThrone is disabled while isConfigured is false, hooks.ts: query enabled: configured).","severity":"medium","snippet":"                  <tr><th scope=\"row\">ETH</th><td>0</td><td>0</td></tr>\n                  <tr><th scope=\"row\">THRONE</th><td>0</td><td>0</td></tr>","title":"fidelity: the pre-launch fee table shows 0 accrued and 0 claimed before anything was read from the chain"},{"citation":"unresolved","description":"Now: in the pre-launch state the footer is the only place the page names the treasury, and it prints short(TREASURY), i.e. '0xf19F…3E57', with no link, no copy control and no title holding the full value. The full address (0xf19F11Dee16a341671E6Ed3e209b704C1Bbc3E57, pinned by the brief) is rendered only inside the Refunds panel, which is not mounted until the contracts are configured. Change to: print the full address in the footer with the site's own .mono class, e.g. `Chain ${chain.id}. Treasury ` followed by <span className=\"mono\">{TREASURY}</span>; body already has overflow-wrap: anywhere, so the 42 characters wrap at 320 without horizontal scroll. Why: the reference rule 'Critical text (an address, an amount, a command, a name) is never clipped, ellipsized or shrunk to fit'; the treasury is the recipient of every slash, which the brief fixes to one address, and the page should let a visitor check it.","line":543,"path":"web/src/App.tsx","reproduction":"Width 390 and 1440. Open dist/index.html with the shipped deployment.json (addresses null). Scroll to the footer: it reads 'Chain 4663. Treasury 0xf19F…3E57.' Select or inspect the text: no element on the page carries the full 42-character address (probe screenshot test/scratch/taste/shots/390-full.png, last line; grep of the rendered DOM for '0xf19F11Dee16a341671E6Ed3e209b704C1Bbc3E57' finds nothing because the Refunds panel is gated on isConfigured in App.tsx line 506).","severity":"medium","snippet":"        <span className=\"muted\">{data ? `Reads refresh every 12 seconds from ${chain.name}.` : `Chain ${chain.id}. Treasury ${short(TREASURY)}.`}</span>","title":"bug: the treasury address is only ever shown shortened before launch, so a visitor cannot verify it"},{"citation":"unresolved","description":"Now: hooks.ts sets `challenge` to null until the separate challenges(liveId) read resolves, and throne.ts phaseOf(ticker, null, …) returns kind 'open'. So on first load, and on every refetch where the base read lands before the challenge read, a ticker with liveChallenge != 0 renders the 'Open to challenge' badge, the candidate input and the enabled 'Open challenge for 0.01 ETH' control for one poll cycle; a connected visitor who presses it sends a transaction the registry rejects with ChallengeLive. Change to: in Challenge, before the phase switch, render a single line 'Reading the live challenge…' (the site's existing .note class) when `t.ticker.liveChallenge !== 0n && !c`, and skip both branches; or in throne.ts make phaseOf return a 'loading' kind when the ticker has a live challenge id and no challenge data. Why: the reference asks that every state 'says only what the app knows'; here the page asserts an open throne it has not confirmed.","line":245,"path":"web/src/App.tsx","reproduction":"Width 390, configured state (any deployment.json with registry, hook and token set) against a registry whose tickerState(THRONE).liveChallenge = 1. Steps: load the page and watch the 'Challenge the throne' panel on the first render, or throttle the RPC so challenges(1) answers after tickerState. Expected: a loading line. Actual: badge 'Open to challenge' and the candidate form; evidence in source: hooks.ts `challenge: liveId > 0n && challenge.data ? (challenge.data as Challenge) : null` and throne.ts phaseOf line `if (challenge && ticker.liveChallenge !== 0n && !challenge.finalized)` falling through to `{ kind: \"open\", … }`.","severity":"low","snippet":"      {c && phase.kind !== \"open\" && (() => {","title":"bug: while the live challenge is still being read, the panel shows the open-challenge form as if no challenge existed"}],"hash":"033ad0eb30ccfc3442d36fbf1bbe63a92e9abaec1bb3b77c4e3b5e1a03686954","nodeId":"56ea0445-81c7-4183-85f6-8ec1f6168cc2","outcome":"completed","summary":"The findings file is valid, the snippets match the tree, and the scratch output is removed. The tree is clean apart from the findings file. Here is the review.\n\n| Area | Count |\n| --- | --- |\n| Brief requirements | 9 met, 0 missing, 0 faked, 3 after review or needs the requester |\n| Broken features | 0 (1 low transient-state bug) |\n| Product on first screen at 390 | yes |\n| taste@1 checks passed | 16 of 16 |\n| Copy findings | 0 |\n| Share card | present (title, favicon, og:title, og:image 1200x630, description) |\n\n**Requirements, from the site's assignment**\n\n- \"the single THRONE token and its pool links\": met once configured, by the Pool panel in `web/src/App.tsx` (token, hook, registry, PoolManager, pool id, pool key, chart link). The addresses and chart URL are null until the launch publishes them, so the live values are after review.\n- \"the current throne holder (controller and beneficiary)\": met, ThroneCard reads tickerState and states that controller and beneficiary are one wallet, which matches the registry.\n- \"accrued and claimed fee totals\": met, crownPaid and crownClaimed for ETH and THRONE in the fee table.\n- \"a working claim action\": met, Claim ETH and Claim THRONE call the hook's claim(bytes32,address) with the ticker; sending needs a wallet, which a review cannot do.\n- \"the reign history timeline\": met, History reads reignCount and reigns with paging of 20.\n- \"live challenge state (window, both stakes, time remaining)\": met, countdown anchored to the latest block, both stakes, quorum, the stake bar.\n- \"stake and challenge actions\": met, openChallenge with exactly 0.01 ETH, stake with the side select (0 reigning, 1 challenger, matching the enum), finalize, claimStake, claimTreasury.\n- \"a plain-English how-it-works section\": met, five steps using the spec constants (1 percent, 0.01 ETH bond, 72 hours, 24 hours, 0.05 ETH quorum, 20 percent slash, 3-day cooldown, MIN_REIGN zero with the 7-day production default named).\n- \"wired to the deployed contracts\": chain 4663, public RPC, explorer and treasury match the brief; the deployment itself comes from the launch stage, so after review.\n\n**The idea.** A ticker dashboard whose one visual device is the single dark moss card for the throne on a cream page, with gold reserved for the throne's own title. Nothing competes with it.\n\n**Findings, in the file**\n\n1. Medium, fidelity. The pre-launch fee table prints literal zeros for accrued and claimed in the same cells the live table uses, though nothing was read from the chain. Replace them with the placeholder token the holder line already uses.\n2. Medium, bug. Before launch the treasury address appears only in the footer, shortened, with no copy control or full value anywhere on the page. Print it in full with the site's mono class.\n3. Low, bug. While the challenges(id) read is pending, the panel shows an enabled open-challenge form for a ticker that already has a live challenge. Show a reading line instead.\n\n**Not verified.** No WebKit run was possible on this machine, so Safari rendering is unchecked. The configured, connected and voting states were judged from source and the builder's own validation notes, since nothing is deployed and no wallet is available. The coverage record marks eight contract entry points as unreached, including registerTicker, the token's ERC-20 functions, the factory and the hook's receive and unlockCallback bodies. No high findings, so no proof tests were written.","treeHash":null,"usage":{"cachedInputTokens":757714,"inputTokens":354,"model":"claude-fable-5-1","outputTokens":15406,"runtime":"claude","turns":16,"wallClockMs":250392}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"e12f98dda6acc55f","findings":[{"citation":"resolved","description":"_registerPool validates currencies, hook address and a nonzero price, but not the parts of the key and price that PoolManager.initialize itself rejects: tickSpacing outside [1, 32767], fee above MAX_LP_FEE (1_000_000) without the dynamic flag, and initialSqrtPriceX96 outside [TickMath.MIN_SQRT_PRICE, MAX_SQRT_PRICE). Registration is permanent (hasCanonicalPool[ticker] is set and every later registerPool for the ticker reverts PoolAlreadyRegistered), and afterInitialize pins the pool to the registered key and exact price. A single mistyped deployer call therefore leaves the ticker with a canonical pool that can never be initialized, so no swap can ever accrue fees for that ticker through this hook; recovery requires mining and deploying a new hook address. This is a deployer-only input and strands no funds, so it is not a vulnerability, but it is an irreversible failure path that the hook could reject at zero cost. The existing tests only cover the branches that are checked (bad currency pair, wrong hook, missing token, zero price, fee > 500 bps).","line":133,"path":"src/CrownHook.sol","proof":"// SPDX-License-Identifier: MIT\npragma solidity 0.8.26;\n\nimport {Test} from \"forge-std/Test.sol\";\nimport {PoolManager} from \"v4-core/src/PoolManager.sol\";\nimport {IPoolManager} from \"v4-core/src/interfaces/IPoolManager.sol\";\nimport {IHooks} from \"v4-core/src/interfaces/IHooks.sol\";\nimport {PoolKey} from \"v4-core/src/types/PoolKey.sol\";\nimport {Currency} from \"v4-core/src/types/Currency.sol\";\nimport {ThroneRegistry} from \"src/ThroneRegistry.sol\";\nimport {ThroneToken} from \"src/ThroneToken.sol\";\nimport {CrownHook, IThroneRegistry} from \"src/CrownHook.sol\";\nimport {CrownHookFactory} from \"src/CrownHookFactory.sol\";\n\n/// Registering a pool whose key PoolManager.initialize can never accept permanently\n/// consumes the ticker's only canonical-pool slot on this hook: no corrected key can be\n/// registered afterwards, so the ticker can never have a fee-accruing pool on this hook.\ncontract RegisterPoolBrickTest is Test {\n    bytes32 constant TICKER = keccak256(\"THRONE\");\n    uint160 constant PRICE = 1 << 96;\n    address payer = makeAddr(\"payer\");\n    ThroneRegistry registry;\n    ThroneToken token;\n    IPoolManager manager;\n    CrownHookFactory factory;\n    CrownHook hook;\n\n    function setUp() public {\n        registry = new ThroneRegistry(0);\n        token = new ThroneToken(payer, 1e24);\n        registry.registerTicker(TICKER, address(token), payer);\n        manager = IPoolManager(address(new PoolManager(payer)));\n        factory = new CrownHookFactory();\n        bytes32 hash = factory.initCodeHash(IThroneRegistry(address(registry)), payer);\n        uint256 i;\n        while (true) {\n            address predicted = address(\n                uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(factory), bytes32(i), hash))))\n            );\n            if (uint160(predicted) & 0x3fff == 0x1044 && predicted.code.length == 0) break;\n            ++i;\n        }\n        hook = factory.deploy(IThroneRegistry(address(registry)), payer, bytes32(i));\n        vm.prank(payer);\n        hook.configurePoolManager(manager);\n    }\n\n    function testUninitializableKeyMustBeRejectedAtRegistration() public {\n        // tickSpacing 0 is rejected by PoolManager.initialize (TickSpacingTooSmall).\n        PoolKey memory bad = PoolKey(Currency.wrap(address(0)), Currency.wrap(address(token)), 3000, 0, IHooks(address(hook)));\n        PoolKey memory good = PoolKey(Currency.wrap(address(0)), Currency.wrap(address(token)), 3000, 60, IHooks(address(hook)));\n        vm.startPrank(payer);\n        // Expected: the hook refuses a key the manager cannot initialize.\n        // Actual on current code: registration succeeds, the slot is consumed, and the\n        // corrected key is refused forever with PoolAlreadyRegistered.\n        vm.expectRevert(CrownHook.InvalidPool.selector);\n        hook.registerPool(bad, TICKER, PRICE);\n        hook.registerPool(good, TICKER, PRICE);\n        manager.initialize(good, PRICE);\n        vm.stopPrank();\n    }\n\n    function testOutOfRangePriceMustBeRejectedAtRegistration() public {\n        // sqrtPriceX96 = 1 is below TickMath.MIN_SQRT_PRICE; initialize reverts and\n        // afterInitialize pins the pool to that exact price forever.\n        PoolKey memory k = PoolKey(Currency.wrap(address(0)), Currency.wrap(address(token)), 3000, 60, IHooks(address(hook)));\n        vm.startPrank(payer);\n        vm.expectRevert(CrownHook.InvalidPool.selector);\n        hook.registerPool(k, TICKER, 1);\n        hook.registerPool(k, TICKER, PRICE);\n        manager.initialize(k, PRICE);\n        vm.stopPrank();\n    }\n}","reproduction":"With a configured hook and registered ticker: deployer calls registerPool(PoolKey(ETH, token, 3000, tickSpacing=0, hook), TICKER, 1<<96). Expected: revert InvalidPool. Actual: succeeds; manager.initialize(key, 1<<96) then reverts TickSpacingTooSmall, and registerPool(PoolKey(ETH, token, 3000, 60, hook), TICKER, 1<<96) reverts PoolAlreadyRegistered forever. Same with a valid key and initialSqrtPriceX96 = 1 (below MIN_SQRT_PRICE): registration succeeds, initialize reverts, the price cannot be corrected because afterInitialize requires sqrtPriceX96 == p.initialSqrtPriceX96.","severity":"low","snippet":"        if (\n            ticker == bytes32(0) || token == address(0) || address(key.hooks) != address(this)\n                || Currency.unwrap(key.currency0) >= Currency.unwrap(key.currency1)\n                || (Currency.unwrap(key.currency0) != token && Currency.unwrap(key.currency1) != token)\n                || initialSqrtPriceX96 == 0\n        ) revert InvalidPool();","title":"registerPool accepts keys/prices PoolManager can never initialize, permanently consuming the ticker's only canonical-pool slot on the hook"},{"citation":"resolved","description":"This is consistent with the README's 'deployer calls PoolManager.initialize directly' and prevents front-running, so it is a documented trust choice rather than a defect. It is recorded because launch tooling that initializes via PositionManager or a deployment script contract will see the pool refuse to initialize with UnexpectedInitialization, and the deployer must call PoolManager.initialize from the deployer EOA itself.","line":155,"path":"src/CrownHook.sol","reproduction":"After registerPool(key, TICKER, PRICE) by the deployer, any address other than the deployer (or a contract the deployer calls through) invokes manager.initialize(key, PRICE). Expected per README: revert. Actual: revert UnexpectedInitialization (already asserted in test/CrownHook.t.sol testUnconfiguredManagerAndInvalidPoolSettings). Only a direct call from the deployer succeeds.","severity":"info","snippet":"            sender != deployer || p.ticker == bytes32(0) || p.initialized\n                || sqrtPriceX96 != p.initialSqrtPriceX96","title":"afterInitialize requires the raw PoolManager.initialize caller to be the deployer, so initialization through any periphery contract (e.g. PositionManager.initializePool or a multicall) is rejected"}],"hash":"2425de0acd1ba15baa61f598cf4a8aa8801fe53a5b9672e276844d8572d3660c","nodeId":"40185e66-e709-44fd-9892-402b5852d741","outcome":"completed","summary":"Review complete. The findings file is written and the coverage record answers all 25 entry points plus three invariants.\n\n**Verdict: the accepted build is sound on every audited axis.** I found no critical, high, or medium defects. What I checked and concluded:\n\n- **Delta settlement.** In every afterSwap branch the hook's net transient delta is zero: the returned positive delta of `cut` is exactly offset by `PoolManager.mint(address(this), id, cut)`, and the early-return branches touch no delta. The unspecified-currency selection is correct for all four direction/exactness combinations, and the fuzz test pins it against the raw swap event.\n- **ERC-6909 backing.** Only afterSwap mints and only claim burns, each paired with an equal change to `crownOwed`. Nobody else can burn the hook's claims, so backing is exactly 1:1. The invariant suite also asserts this.\n- **claim() safety.** Both claim paths are guarded by nonReentrant, zero state before the unlock, and transfer only after the manager relocks. Forged callbacks are rejected by the pending-callback gate. Double claims revert with NothingToClaim on every path, and that is tested.\n- **Challenge math.** Strict majority plus a 0.05 ETH total quorum, 20% slash, half to winners pro-rata and the rest to the fixed treasury, with floor dust released only after every depositor claims. The per-wallet payouts can never exceed the pool. All refunds are pull-pattern.\n- **Token immutability.** No code path writes the ticker's token field after registration, and the dethrone test asserts byte-identity.\n\n**One low finding, with a failing proof test.** The hook's pool registration does not reject keys or prices that PoolManager.initialize itself rejects, such as tickSpacing 0 or a sqrt price below the minimum. Because registration is permanent and afterInitialize pins the exact price, one mistyped deployer call strands the ticker without an initializable canonical pool on that hook. No funds are at risk and a new hook can be deployed, so I ranked it low. The proof is in `test/scratch/RegisterPoolBrick.t.sol` and fails on the current code.\n\n**One info note.** Pool initialization must come directly from the deployer address, so periphery-driven initialization is refused. That matches the README and is a documented trust choice, not a defect.","treeHash":null,"usage":{"cachedInputTokens":433766,"inputTokens":226,"model":"claude-fable-5-1","outputTokens":21007,"runtime":"claude","turns":15,"wallClockMs":308216}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"6ef494db85781eec","findings":[],"hash":"370169d6a752859989ad0fc84aaec9a0dd29f9c19e48612b61b0f489d4819889","nodeId":"48ed5bb8-c824-4b64-ad2d-866c577b9a7a","outcome":"failed","summary":"bundle upload failed (502)","treeHash":null,"usage":{"cachedInputTokens":1671947,"inputTokens":482,"model":"claude-fable-5-1","outputTokens":59086,"runtime":"claude","turns":38,"wallClockMs":1155309}},{"artifacts":[],"attempt":1,"bundleHash":"464fd9785eb159d9ca2d8f68b0c34f9cdab03bc83eef6f09c6d345d16bcbe401","device":"ca080fd306399669","findings":[],"hash":"addcf113ffecd299cc15b483f182beae561b8a3a8867420ffa308784b93aaa93","nodeId":"1d064cae-0528-498f-b94f-80d623ac7aff","outcome":"completed","summary":"The canonical THRONE ticker page is built, validated and committed.\n\n**What was delivered**\n\n- A Vite, React and TypeScript app in `web/`, exported with a relative base to `dist/` and committed with its lockfile. The page shows the single THRONE token and pool facts, the throne holder, accrued and claimed fees with Claim controls, the reign history, the live challenge with both stakes, quorum and countdown, and a plain-English how-it-works section.\n- Every primary contract action has a control: open challenge (exact 0.01 ETH bond), stake on either side, finalize, claim ETH and THRONE fees, recover a stake by challenge number, and pay the treasury. Each control follows the connect, switch-network, act sequence with its own pending and error state.\n- Wallets connect by EIP-6963, by open-in links on phones, and by Coinbase Smart Wallet, with no relay or project id. A wallet that does not know chain 4663 is offered `wallet_addEthereumChain` after the switch fails.\n- Configuration is in one place, `web/src/config.ts`, plus the runtime `dist/deployment.json` with null addresses until launch. No private credentials exist in the bundle.\n- `DESIGN.md` at the root documents the tokens, type scale, layout and components of the final source. The README gained a section on installing, building, previewing and configuring the page.\n\n**Validation results** are in `docs/validation-site.md`. Typecheck passed, 14 unit tests passed, the design probe passed 16 of 16 checks on the final export, and a mocked-wallet Chromium script passed 64 of 64 interaction checks across 320, 390 and 1440 widths. The 390 first screen shows the holder, the fee table and the claim control alongside Connect, and nothing scrolls sideways with full addresses.\n\n**Limitations to know about**\n\n- No deployment handoff or `network.json` was supplied, so addresses are null, no `dist/imd-deployment.json` was emitted, and swaps are off with the reason shown on the page. Nothing was run against the live chain and no transaction was broadcast.\n- Checks ran in Chromium only. Screen reader, WebKit and physical devices were not tested.\n- The submission is one commit on top of the accepted tree, with `node_modules` removed and the pack size still under 1 MiB.","treeHash":"e5db6e8cbb076c074070321bbea37f29959e62b6","usage":{"cachedInputTokens":4700934,"inputTokens":834,"model":"claude-fable-5-1","outputTokens":86668,"runtime":"claude","turns":69,"wallClockMs":1364196}},{"artifacts":[],"attempt":2,"bundleHash":"211a1a680c265c2c393efd922c9b737aa8160cbfbfb1048a60268d660b450d26","device":"2b170a76e3d9adca","findings":[{"description":"openChallenge only rejects address(0) and the current beneficiary as candidate. If the winning candidate is the PoolManager, the CrownHook itself, or a contract with no receive(), CrownHook.afterSwap still mints ERC-6909 claims and credits crownOwed[candidate][currency] for every swap during that reign, but nothing can ever call claim() as that address, so the hook holds claims nobody can redeem until the ticker is dethroned again. The accounting stays consistent (crownOwed remains 1:1 backed, swaps still settle), so this is a value-stranding griefing path that costs the attacker a winning 0.05 ETH vote, not a solvency bug. The tests assert the consistent accounting; they do not assert that such a reign is desirable.","line":166,"path":"src/ThroneRegistry.sol","reproduction":"Demo registry (MIN_REIGN 0): open a challenge with candidate = address(poolManager), stake 0.05 ETH on the challenger side, warp 96h, finalize. Swap token->ETH for 1 ether. Expected (per brief): fees accrue to a controllable beneficiary. Actual: hook.crownOwed(address(poolManager), ETH) == 9871580343970612 wei and manager.balanceOf(hook, 0) equals it; no path exists to redeem it. Same with candidate = address(hook) (9678589273850043 wei accrued). Suggested fix: reject candidate == address(this), and document that contract candidates must be able to receive ETH; optionally let the registry reject the PoolManager address once configured.","severity":"low","title":"A challenge may nominate an address that can never claim (PoolManager, the hook, or any contract without receive), permanently stranding that reign's fee stream"},{"description":"claimStake moves the per-wallet floor dust to treasuryOwed only when principalClaimed == total. A staker whose address cannot accept ETH (contract without receive) can never claim, so principalClaimed never reaches total and the dust (at most one wei per claimant) stays in the contract forever. The staker's own principal is also stuck, which is their choice. Funds are never lost to a third party and the balance == obligations invariant still holds, so this is informational. The initialTreasury share is unaffected and claimable immediately.","line":255,"path":"src/ThroneRegistry.sol","reproduction":"Contract without receive() opens a challenge (0.01 ETH bond); candidate stakes 0.03 ETH challenger, reigning stakes 0.03 ETH; warp to finalizableAt; finalize (challenger loses: 0.04 vs 0.03 but quorum 0.07 >= 0.05 and 0.04 > 0.03 -> challenger wins; adjust amounts as desired). After the two EOAs claim, registry balance is 13750000000000000 wei: 10750000000000000 claimable by the stuck contract plus 3000000000000000 treasuryOwed; any floor dust from the EOA claims is never credited to treasuryOwed. Expected: dust reaches treasury eventually. Actual: it requires the unreachable claim. Possible fix: sweep dust when payoutsClaimed + remaining claimable of unclaimed wallets equals the remaining pool, or allow treasury to sweep after a long grace period.","severity":"info","title":"Rounding dust of a finalized challenge is only swept to treasury after every staker has claimed, so one staker that cannot receive ETH blocks the sweep indefinitely"}],"hash":"c9596110fab358a4a358c9bd56c91e2dbe536c99c687701e6333595d1bef588a","nodeId":"48ed5bb8-c824-4b64-ad2d-866c577b9a7a","outcome":"completed","summary":"The Foundry suite for the accepted Crown Model 2 build is complete and committed. `forge test` passes with the verifier's seed and without it.\n\n**Result**\n\n| | |\n|---|---|\n| Tests passing | 55 of 55 across 7 suites |\n| Invariant calls | 3,840 registry, 1,920 hook, zero reverts |\n| Commit | `04baeca` on top of the accepted build, tests only |\n\n**What I added** (the accepted build already shipped 32 passing unit tests, which I kept untouched):\n\n- **Registry invariants** in `test/ThroneRegistry.invariant.t.sol`. A handler opens challenges with right and wrong bonds, stakes on both sides, warps time, finalizes, claims stakes and treasury in random order, with a re-entering staker in rotation. After every call the registry balance equals treasury owed plus open stakes plus unclaimed payouts, ETH is conserved, the slash split is exact, only the latest challenge can be live, reign history matches the beneficiary, and the token binding never changes.\n- **Hook invariants** in `test/CrownHook.invariant.t.sol`. A handler swaps in both directions and both modes against the real v4 PoolManager, claims as every beneficiary, and dethrones through the registry. A hostile contract beneficiary that tries to mint claims and re-enter on payment is in rotation. The hook's ERC-6909 balance always equals the sum of crownOwed and equals lifetime accrued minus claimed, every swap settles, nothing is stranded in hook or router, and token, pool, fee and supply are permanent.\n- **Challenge math to the wei** in `test/ThroneRegistryMath.t.sol`. Fuzzed at 1000 runs: any wrong bond is refused, the win rule is strict majority plus quorum, and a six-staker pro-rata split floors per wallet with at most one wei of dust each, swept to treasury only after the last claim. Boundary cases cover one wei below quorum, majority by one wei, one-wei stakes with no winners, an out-of-range side, timelock staking and late finalization.\n- **Claim safety** in `test/CrownHookClaims.t.sol`. Double claims are refused on every path, strangers and wrong tickers take nothing, a former beneficiary keeps accrued fees after a dethrone, an unpayable beneficiary rolls back cleanly while swaps keep accruing, direct ETH and forged unlock callbacks are rejected, and exact-output swaps charge the input side.\n\n**Defects reported, not tested around.** Two low-severity observations went to `.imd-findings.json` in the repository root, which is gitignored so it stays in the working tree for the harness. Neither breaks solvency or settlement, so no proof file was required:\n\n- A winning candidate can be the PoolManager, the hook, or a contract with no receive function, stranding that reign's fee stream in unredeemable claims.\n- A staker that cannot receive ETH blocks the rounding-dust sweep to treasury for that challenge indefinitely.\n\nFork runs against the live Robinhood Chain PoolManager are still owed, since this machine and the verifier have no network. The ticker site wiring and the adversarial review are the next nodes in the project plan and were outside this assignment.","treeHash":"555066904fadb34b9e01701a618ef908ae05705f","usage":{"cachedInputTokens":2274588,"inputTokens":642,"model":"claude-fable-5-1","outputTokens":57445,"runtime":"claude","turns":45,"wallClockMs":1036407}}],"verification":[{"checks":[],"detail":"paths and tree verified; no suite was run for this kind of work","evaluation":"structural","profile":"none","status":"accepted","submissionHash":"addcf113ffecd299cc15b483f182beae561b8a3a8867420ffa308784b93aaa93","verifiedTreeHash":"e5db6e8cbb076c074070321bbea37f29959e62b6","verifierVersion":"0.1.0+63e0a393"},{"checks":[{"durationMs":33745,"exitCode":0,"name":"build","output":"Compiling 79 files with Solc 0.8.26\nSolc 0.8.26 finished in 33.07s\nCompiler run successful!\n","passed":true},{"durationMs":1319,"exitCode":0,"name":"test","output":"No files changed, compilation skipped\n\nRan 2 tests for test/ThroneToken.t.sol:ThroneTokenTest\n[PASS] testConstructorRequiresExplicitPayerAndNonzeroSupply() (gas: 5773)\n[PASS] testFixedSupplyTransfersAllowancesAndInvalidRecipients() (gas: 264153)\nSuite result: ok. 2 passed; 0 failed; 0 skipped; finished in 1.18ms (1.62ms CPU time)\n\nRan 9 tests for test/CrownHookClaims.t.sol:CrownHookClaimsTest\n[PASS] testBeneficiaryWithoutReceiveCannotClaimEthButTokenAndOthersUnaffected() (gas: 2101335)\n[PASS] testClaimByWrongTickerOrStrangerTakesNothing() (gas: 501189)\n[PASS] testConstructorRejectsZeroAddresses() (gas: 6457)\n[PASS] testDoubleClaimIsRefusedOnEveryPath() (gas: 1218044)\n[PASS] testExactOutputChargesInputSideAndSettles() (gas: 439040)\n[PASS] testFormerBeneficiaryKeepsAccruedFeesAfterDethrone() (gas: 1541831)\n[PASS] testHookRefusesDirectEthAndForgedCallbacks() (gas: 909002)\n[PASS] testRegistrationRejectsForeignPoolShapes() (gas: 254757)\n[PASS] testSwapWhileChallengeLiveAccruesToReigningBeneficiaryUntilFinalized() (gas: 1485915)\nSuite result: ok. 9 passed; 0 failed; 0 skipped; finished in 47.03ms (3.67ms CPU time)\n\nRan 15 tests for test/CrownHook.t.sol:CrownHookTest\n[PASS] testBuyChallengeStakeFinalizeBuyPreservesTokenPoolAndAccruals() (gas: 1830188)\n[PASS] testCallbacksAndConfigurationRejectUnauthorizedCalls() (gas: 182421)\n[PASS] testClaimWithinAnotherUnlockIsRefusedWithoutLosingAccrual() (gas: 1552539)\n[PASS] testClaimsAcrossMultipleTickersAndBoundedClaimRemoval() (gas: 2091913)\n[PASS] testFuzzBothDirectionsExactInputAndOutput(uint96,bool,bool) (runs: 256, μ: 420943, ~: 420122)\nLogs:\n  Bound result 287900849244191567\n\n[PASS] testMaliciousBeneficiaryCannotBreakSwapAndCanClaimWhenLocked() (gas: 1964996)\n[PASS] testNativeAndTokenClaimsAreExactAndIndependentDuringLiveChallenge() (gas: 1707742)\n[PASS] testPartialFillChargesActualAmountNotRequestedAmount() (gas: 402520)\n[PASS] testPermissionsCanonicalPoolAndImmutableSettings() (gas: 158737)\n[PASS] testRegistryGasExhaustionSkipsFee() (gas: 253545)\n[PASS] testRegistryReadFailuresSkipFeesAndNeverBreakSwaps() (gas: 1052150)\n[PASS] testRejectedClaimRollsBackOnlyClaimAndSwapsContinue() (gas: 2133148)\n[PASS] testSubWeiCutRoundsToZeroAndSwapStillSettles() (gas: 216996)\n[PASS] testUnconfiguredManagerAndInvalidPoolSettings() (gas: 19028692)\n[PASS] testZeroFeeAndMaximumFeePools() (gas: 2218377)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 47.17ms (49.87ms CPU time)\n\nRan 15 tests for test/ThroneRegistry.t.sol:ThroneRegistryTest\n[PASS] testBelowQuorumFailsEvenWithMajorityAndNoDefenders() (gas: 835689)\n[PASS] testBondIsExactAndCountsAsOpenerStake() (gas: 467952)\n[PASS] testBothSidesSingleWalletAndClaimsDuringLaterChallenge() (gas: 1140919)\n[PASS] testClaimsCannotPrecedeFinalizationAndUnknownWalletCannotClaim() (gas: 584638)\n[PASS] testExactSlashSplitAndWinnerRewards() (gas: 1437888)\n[PASS] testFuzzConservationRoundingAndClaimOrder(uint96,uint96,bool) (runs: 256, μ: 1506359, ~: 1506409)\nLogs:\n  Bound result 264337593543950335\n  Bound result 264337593543950335\n\n[PASS] testInvalidCandidatesUnknownIdsAndConcurrentChallenge() (gas: 470555)\n[PASS] testProductionDefaultAndMinReignBoundary() (gas: 836320)\n[PASS] testQuorumExactlyWinsAndTokenNeverChanges() (gas: 822810)\n[PASS] testRegistrationIsPermanentAndNormalized() (gas: 225100)\n[PASS] testRejectingAndReentrantStakerCannotBlockResolutionOrOthers() (gas: 1401760)\n[PASS] testRejectingTreasuryCannotBlockFinalizationOrStakerClaims() (gas: 966205)\n[PASS] testTieFailsAndCooldownStartsAtFinalization() (gas: 1044868)\n[PASS] testTreasuryCanClaimBeforeStakersAndCannotRedirectFunds() (gas: 975890)\n[PASS] testWindowAndTimelockExactBoundaries() (gas: 699047)\nSuite result: ok. 15 passed; 0 failed; 0 skipped; finished in 109.13ms (49.03ms CPU time)\n\nRan 12 tests for test/ThroneRegistryMath.t.sol:ThroneRegistryMathTest\n[PASS] testExactQuorumBoundaryOneWeiBelow() (gas: 1113111)\n[PASS] testFuzzBondMustBeExact(uint256) (runs: 1000, μ: 58132, ~: 58025)\nLogs:\n  Bound result 42000000000000000\n\n[PASS] testFuzzSlashSplitExactForManyStakers(uint96[3],uint96[3],bool) (runs: 1000, μ: 2268755, ~: 2268745)\nLogs:\n  Bound result 71945423573\n  Bound result 1\n  Bound result 953916119430901062497157\n  Bound result 50618285218071317919290537\n  Bound result 36516172480094109180567374\n  Bound result 4584804155063599407627975595\n\n[PASS] testFuzzWinRuleIsStrictMajorityAndQuorum(uint96,uint96) (runs: 1000, μ: 738282, ~: 709513)\nLogs:\n  Bound result 609979252645\n  Bound result 74542384433415291\n\n[PASS] testLateFinalizationStillResolvesAndStartsCooldownFromThen() (gas: 494723)\n[PASS] testMajorityByOneWeiWins() (gas: 827277)\n[PASS] testOneWeiStakesAndEmptyWinningSide() (gas: 969132)\n[PASS] testOutOfRangeSideIsRejectedWithoutTakingFunds() (gas: 377161)\n[PASS] testProductionRegistryKeepsSevenDayDefaultAndDemoIsZero() (gas: 26143)\n[PASS] testSecondTickerSameTokenAndSameTickerDifferentTokenAreRejected() (gas: 815013)\n[PASS] testStakeRejectedInTimelockAndAfterFinalization() (gas: 571973)\n[PASS] testTreasuryIsTheFixedAddressAndNeverPaidTwice() (gas: 626452)\nSuite result: ok. 12 passed; 0 failed; 0 skipped; finished in 116.60ms (336.56ms CPU time)\n\nRan 1 test for test/CrownHook.invariant.t.sol:CrownHookInvariantTest\n[PASS]\nCrownHookInvariantTest invariants:\n[PASS] invariant_assetsBackClaimsAndNothingStranded\n[PASS] invariant_crownOwedBackedByClaims\n[PASS] invariant_hostileBeneficiaryContained\n[PASS] invariant_tokenPoolAndFeePermanent\n CrownHookInvariantTest invariants (runs: 48, calls: 1920, reverts: 0)\n\n╭-------------+-------------+-------+---------+----------╮\n| Contract    | Selector    | Calls | Reverts | Discards |\n+========================================================+\n| HookHandler | claimAll    | 480   | 0       | 0        |\n|-------------+-------------+-------+---------+----------|\n| HookHandler | claimTicker | 466   | 0       | 0        |\n|-------------+-------------+-------+---------+----------|\n| HookHandler | flip        | 472   | 0       | 0        |\n|-------------+-------------+-------+---------+----------|\n| HookHandler | swap        | 502   | 0       | 0        |\n╰-------------+-------------+-------+---------+----------╯\n\nLogs:\n  Bound result 16559\n  Bound result 30000\n  Bound result 3600\n  Bound result 829939685546914408\n  Bound result 96\n  Bound result 200\n  Bound result 604800\n  Bound result 100942074225264152\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 969.50ms (948.85ms CPU time)\n\nRan 1 test for test/ThroneRegistry.invariant.t.sol:ThroneRegistryInvariantTest\n[PASS]\nThroneRegistryInvariantTest invariants:\n[PASS] invariant_balanceEqualsOutstandingObligations\n[PASS] invariant_conservation\n[PASS] invariant_finalizedMathExactAndSolvent\n[PASS] invariant_reentrancyNeverSucceeds\n[PASS] invariant_singleLiveChallenge\n[PASS] invariant_tokenImmutableAndReignsConsistent\n ThroneRegistryInvariantTest invariants (runs: 64, calls: 3840, reverts: 0)\n\n╭-----------------+----------------+-------+---------+----------╮\n| Contract        | Selector       | Calls | Reverts | Discards |\n+===============================================================+\n| RegistryHandler | claimStake     | 637   | 0       | 0        |\n|-----------------+----------------+-------+---------+----------|\n| RegistryHandler | claimTreasury  | 628   | 0       | 0        |\n|-----------------+----------------+-------+---------+----------|\n| RegistryHandler | finalizeLatest | 626   | 0       | 0        |\n|-----------------+----------------+-------+---------+----------|\n| RegistryHandler | open           | 638   | 0       | 0        |\n|-----------------+----------------+-------+---------+----------|\n| RegistryHandler | stakeOn        | 662   | 0       | 0        |\n|-----------------+----------------+-------+---------+----------|\n| RegistryHandler | warp           | 649   | 0       | 0        |\n╰-----------------+----------------+-------+---------+----------╯\n\nLogs:\n  Bound result 2604529648706350178\n  Bound result 5171\n  Bound result 323123\n  Bound result 551\n  Bound result 3000000000000000000\n  Bound result 50000000000000000\n  Bound result 305707\n  Bound result 10000\n  Bound result 1000\n  Bound result 500\n  Bound result 2999999999999999987\n  Bound result 234292909\n  Bound result 122\n  Bound result 312\n  Bound result 1372398272\n  Bound result 1000000000000000\n  Bound result 6800\n  Bound result 196020\n  Bound result 3\n\nSuite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.04s (1.04s CPU time)\n\nRan 7 test suites in 1.04s (2.33s CPU time): 55 tests passed, 0 failed, 0 skipped (55 total tests)\n","passed":true},{"durationMs":187,"exitCode":0,"name":"source-index","output":"{\"v\":1,\"entryPoints\":[\"CrownHook.afterInitialize(address,(address,address,uint24,int24,address),uint160,int24)\",\"CrownHook.afterSwap(address,(address,address,uint24,int24,address),(bool,int256,uint160),int256,bytes)\",\"CrownHook.claim(address)\",\"CrownHook.claim(bytes32,address)\",\"CrownHook.configurePoolManager(address)\",\"CrownHook.receive()\",\"CrownHook.registerPool((address,address,uint24,int24,address),bytes32,uint16,uint160)\",\"CrownHook.registerPool((address,address,uint24,int24,address),bytes32,uint160)\",\"CrownHook.unlockCallback(bytes)\",\"CrownHookFactory.deploy(address,address,bytes32)\",\"ProductionThroneRegistry.claimStake(uint256)\",\"ProductionThroneRegistry.claimTreasury()\",\"ProductionThroneRegistry.finalize(uint256)\",\"ProductionThroneRegistry.openChallenge(bytes32,address)\",\"ProductionThroneRegistry.registerTicker(bytes32,address,address)\",\"ProductionThroneRegistry.stake(uint256,uint8)\",\"ThroneRegistry.claimStake(uint256)\",\"ThroneRegistry.claimTreasury()\",\"ThroneRegistry.finalize(uint256)\",\"ThroneRegistry.openChallenge(bytes32,address)\",\"ThroneRegistry.registerTicker(bytes32,address,address)\",\"ThroneRegistry.stake(uint256,uint8)\",\"ThroneToken.approve(address,uint256)\",\"ThroneToken.transfer(address,uint256)\",\"ThroneToken.transferFrom(address,address,uint256)\"],\"files\":{\".gitignore\":6,\"README.md\":186,\"docs/demo-evidence.json\":188,\"docs/dependencies.md\":26,\"docs/dependencies.sha256\":84,\"docs/validation.md\":23,\"foundry.toml\":25,\"site/abi.json\":1,\"site/app.js\":342,\"site/deployment.json\":15,\"site/index.html\":53,\"site/styles.css\":1,\"site/vendor/ethers.LICENSE.md\":21,\"site/vendor/ethers.umd.min.js\":1,\"src/CrownHook.sol\":271,\"src/CrownHookFactory.sol\":39,\"src/ThroneRegistry.sol\":284,\"src/ThroneToken.sol\":57,\"test/CrownHook.invariant.t.sol\":103,\"test/CrownHook.t.sol\":424,\"test/CrownHookClaims.t.sol\":217,\"test/ThroneRegistry.invariant.t.sol\":145,\"test/ThroneRegistry.t.sol\":337,\"test/ThroneRegistryMath.t.sol\":268,\"test/ThroneToken.t.sol\":45,\"test/helpers/DemoRouter.sol\":94,\"test/helpers/HookFixture.sol\":110,\"test/helpers/HookHandler.sol\":232,\"test/helpers/RegistryHandler.sol\":218,\"tools/check-site.mjs\":83,\"tools/demo.mjs\":174,\"tools/export-abi.mjs\":11,\"tools/local-provider.mjs\":54,\"tools/mine-hook.mjs\":29,\"tools/vendor/linkedom.LICENSE\":15,\"tools/vendor/linkedom.mjs\":12761},\"excluded\":[\"lib/\",\"node_modules/\"],\"truncated\":false}","passed":true}],"detail":"all checks passed","evaluation":"checks","profile":"foundry","status":"accepted","submissionHash":"c9596110fab358a4a358c9bd56c91e2dbe536c99c687701e6333595d1bef588a","verifiedTreeHash":"555066904fadb34b9e01701a618ef908ae05705f","verifierVersion":"0.1.0+63e0a393"}]}