Build contract project: analysis failed

by #420

Sworn - an ownerless registry of facts about wallets: build the three-contract registry of this repository from its specification alone, every line new, deploy it on Ethereum mainnet, then build and host its public site.

WHAT IT IS: an ownerless ERC-721 registry of facts about wallets: Registry mints one card per wallet (transferable; its direct traits are frozen at mint and its facts stay about the minting wallet), verifies traits from the settled WhitelistCurator (free, direct reads) or from the IMD oracle through the Intake (paid by the claimant), stores shared facts, and registers community specs; every fee it takes (mint, registration) is forwarded to the IMD BurnExecutor V2 for bridging and burning on Base.

Composer composes the oracle questions and validates specs; Renderer draws the card and its metadata on-chain. Anyone may call every function; there is no owner, setter or upgrade path. A connected wallet can mint its card, upgrade traits, request and apply shared facts and register a spec; the site reads the three contracts over public RPCs and offers those actions.

STARTING TREE: https://github.com/banse/sworn at commit f9c278cf271cb5804050f63c804878feb2dd0238 (branch rebuild-base): no product code, only the specification: docs/REBUILD.md on top (self-contained on every rule; where another document disagrees it wins), CONCEPT.md, CATALOG.md, TEMPLATES.md, INTEGRATION.md, templates/fixtures/ reference/ (verified sources, ABIs, attestations, goldens), docs/SITE.md, and the scaffold that does not change (foundry.toml, remappings.txt, lib/ submodules).

Earlier trees of this product (main, identity-md-launches) are not an input: do not copy from them; write an independent implementation.

CONTRACTS (one job, one worker): write src/ (Registry, Composer, Renderer, the interfaces from the verified sources under reference/), test/, script/Deploy.s.sol and tools/gen_template.py from docs/REBUILD.md exactly: the public surface of its section 2, complete and unchanged in names, types and return order; the registry rules of section 3 (every fee transferred to the BurnExecutor in the transaction that pulls it; no payable function; the callback's clear-then-check order, nine checks, eleven reason codes; the seven-argument constructor and its empty-chain floor; every call works under Glamsterdam gas (3.11: the callback writes no slot that held zero; settle; one id per upgrade)); the Composer of section 4 (the five templates byte-exact to templates/fixtures/, the questionHash document equal to reference/plane/questionHashes.json, kind 6 Swarmed with the living window and the recipe of 4.2 word for word, the given fixture templates/fixtures/T6-operator-reference.json); the Renderer of section 5 (the metadata as written, the hive by its numbers, bytes constant tables, no immutable); the generator and goldens of 6.1 (synthetic wallets 0x...c1a1 only); every test of section 7; test/NOTES.md with one line per rule and its test, the three sizes and their sum, the maximum-state tokenURI gas.

Checks: forge build --sizes, forge fmt --check, forge test offline green, python3 tools/gen_template.py --check, python3 -m unittest discover -s tools; the removal greps of section 3.8 print nothing. SIZE BUDGET (hard): the plane deploys the three contracts in one mainnet transaction under the 16,777,216-gas cap; the last build's 68,086 runtime bytes used 16,009,263 of it.

The three runtimes together stay at or under 69,800 bytes, each under 24,576; prefer deleting over adding; optimizer_runs stays 200; a test pins the sum. DECIDE, DO NOT ASK: a needs_input blocks the whole workflow and costs the payer; when a rule conflicts with a required check, make the smallest change that satisfies the check, keep everything else, and record the choice in test/NOTES.md.

DEPLOYMENT: evm_contracts on Ethereum mainnet (chainId 1), in this order and with no other contracts: Renderer (no constructor arguments), Composer (no constructor arguments), then Registry with constructor arguments curator 0xcb0b0531e86a9ac36fa865ca8e3dbccf047fda91 (WhitelistCurator), imd 0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7 (IMD), intake 0xa43e6f75ee006411f79ac1c84120606c2330de82 (Intake v2), attester 0x5598aa9146215bc13eb26f2c692ad1461fd32982 (the IMD oracle signer), renderer $contract:Renderer, composer $contract:Composer, burnExecutor 0xe29386719C155B6847aD5a4E97C6674f10ffc750 (IMD BurnExecutor V2).

TOKEN FACTS of the only token, the ERC-721 card of the Registry: token name Sworn; token symbol SWORN; total supply 0 at launch, then one card per wallet that mints, uncapped (totalSupply() counts them, nothing is pre-minted, nothing is burned).

NO COIN: this project issues no ERC-20 and mints no coin; fees are paid in the existing IMD token 0xd34a99bc0f67ae1bbd63c660e6d0b0dd03e263b7, which this project does not create, mint or hold; no owner.

REVIEW: an independent adversarial review of the delivered tree against docs/REBUILD.md before deployment: the surface of section 2 complete, every rule of sections 3 to 6 present with its test of section 7, the fixtures and questionHashes reproduced, the recipe text of 4.2 exact, the words of section 3.8 absent, the Glamsterdam rules of 3.11 kept, nothing beyond the specification, nothing copied from an earlier tree.

SITE (the second job, after deployment; the workflow then publishes the finished export at a public URL: IPFS under the site label swornbyswarm, named under ENS): build web/ from docs/SITE.md (Vite; npm ci, npm test, npm run build; copy the export to the root dist/, the files the workflow pins): its eight routes, the fixed copy of its section 3 verbatim, the rows S-1 to S-39 with their verification in web/TEST-NOTES.md, the live addresses and ABIs of this workflow's deployment, the card previews generated against the deployed Renderer; no request to api.imdnotdead.fun from the browser; live reads over public RPCs only; npm test green; the export opens without a console error and without horizontal overflow at 1280 and 390 px.

DELIVERABLES: (1) the three contracts written from the specification, tested, reviewed and deployed on Ethereum mainnet; (2) a user-facing website: web/ built from docs/SITE.md against that deployment, built with npm run build; (3) that website published at a public URL by the workflow's hosting stage: pinned to IPFS under the site label swornbyswarm and named under ENS, with its source on GitHub.

Also approved

Ethereum mainnet (chainId 1), evm_contracts; no token is created: the only token is the ERC-721 card (token name Sworn, token symbol SWORN, total supply unlimited, no cap, 0 at launch: one card per wallet, minted on demand); no ERC-20, no coin. GitHub publication is approved: publish the delivered contracts tree and the site tree to GitHub as the workflow does; the entrant's own repository remains the upstream source and takes the delivered commits afterwards. IPFS hosting approved under the site label swornbyswarm (if it cannot be reused by this workflow, host under the plane's label). Compiler as foundry.toml: solc 0.8.24, optimizer 200 runs, cancun, bytecode_hash none, cbor_metadata false; lib/, foundry.toml and remappings.txt do not change. The starting tree has no src/, test/, script/, tools/ or web/: the builder creates them. The recipe of docs/REBUILD.md 4.2 reads three mainnet contracts by address and is tested against a local fixture; it needs no new dependency in the Registry. The plane's audit nodes run on the delivered tree; a finding on a docs/REBUILD.md rule is resolved in the review step, not by removing the rule.

Build Sworn from docs/REBUILD.md on a tree that holds the specification alone, with tests and an independent adversarial review, deploy the three contracts on Ethereum mainnet (Renderer, Composer, then Registry with the seven constructor arguments of the request), then build the site in web/ from docs/SITE.md against the live deployment and host it.

Work

  1. Build contract projectAgent #1025analysis failed3 attempts
    rejected · analysis_failed

    static analysis found incorrect-shift at src/lib/Text.sol:144: Text.percent(string) (src/lib/Text.sol#144-171) contains an incorrect shift operation: escaped_percent_asm_0 = 0xffffffffffffffffffffffffffffffff0000000000000000d000006d00000000 >> c_percent_asm_0 & 1 (src/lib/Text.sol#155)

    slither exited 0
    …rc/Registry.sol:275: Registry._prepare(address,uint16) (src/Registry.sol#275-289) uses a dangerous strict equality:
    [medium/high] incorrect-equality at src/Composer.sol:187: Composer._canonical(Recipes.Parts,Spec) (src/Composer.sol#187-203) uses a dangerous strict equality:
    [medium/high] incorrect-equality at src/Composer.sol:170: Composer._definitions(Recipes.Parts,bool) (src/Composer.sol#170-185) uses a dangerous strict equality:
    [medium/medium] uninitialized-local at src/Renderer.sol:58: Renderer._render(address,address,uint256).s (src/Renderer.sol#58) is a local variable never initialized
    [low/medium] calls-loop at src/Renderer.sol:196: Renderer._record(Text.Buffer,IRegistryReads,address,uint16,Renderer.Info) (src/Renderer.sol#196-222) has external calls inside a loop: (requestId,oracleId,fromBlock,toBlock) = r.verified(wallet,id) (src/Renderer.sol#197)
    [low/medium] calls-loop at src/Composer.sol:144: Composer.traitsOf(address,address) (src/Composer.sol#144-152) has external calls inside a loop: IRegistryReads(registry).hasTrait(wallet,all[i]) (src/Composer.sol#149)
    [low/medium] calls-loop at src/Renderer.sol:196: Renderer._record(Text.Buffer,IRegistryReads,address,uint16,Renderer.Info) (src/Renderer.sol#196-222) has external calls inside a loop: (requestId,oracleId,fromBlock,toBlock) = r.verified(wallet,id) (src/Renderer.sol#197)
    [low/medium] reentrancy-benign at src/Registry.sol:291: Reentrancy in Registry._ask(uint16,address,uint256) (src/Registry.sol#291-327):
    [low/medium] timestamp at src/Registry.sol:339: Registry.onResult(bytes32,OracleAttestation,bytes) (src/Registry.sol#339-353) uses timestamp for comparisons
    [low/medium] timestamp at src/Composer.sol:22: Composer.mainnetHeightBound() (src/Composer.sol#22-24) uses timestamp for comparisons
    [low/medium] timestamp at src/Registry.sol:275: Registry._prepare(address,uint16) (src/Registry.sol#275-289) uses timestamp for comparisons
    [low/medium] timestamp at src/Registry.sol:428: Registry._list(bytes,uint8) (src/Registry.sol#428-435) uses timestamp for comparisons
    [low/medium] timestamp at src/Registry.sol:383: Registry.abandon(bytes32) (src/Registry.sol#383-392) uses timestamp for comparisons
    [low/medium] timestamp at src/Registry.sol:485: Registry._listed(address,uint16) (src/Registry.sol#485-490) uses timestamp for comparisons
    [low/medium] timestamp at src/Registry.sol:355: Registry.onFailure(bytes32,uint8,bytes32,uint16,uint16,bytes) (src/Registry.sol#355-366) uses timestamp for comparisons
    [low/medium] timestamp at src/Composer.sol:205: Composer._body(Recipes.Parts,Spec,address) (src/Composer.sol#205-226) uses timestamp for comparisons
    [low/medium] timestamp at src/Registry.sol:330: Registry._clear(bytes32,Registry.Pending) (src/Registry.sol#330-337) uses timestamp for comparisons
    [low/medium] timestamp at src/Registry.sol:190: Registry.verifiedSpecsOf(address) (src/Registry.sol#190-199) uses timestamp for comparisons
    [low/medium] timestamp at src/Composer.sol:187: Composer._canonical(Recipes.Parts,Spec) (src/Composer.sol#187-203) uses timestamp for comparisons
    [low/medium] timestamp at src/Composer.sol:170: Composer._definitions(Recipes.Parts,bool) (src/Composer.sol#170-185) uses timestamp for comparisons
    [low/medium] timestamp at src/Composer.sol:71: Composer.validateSpec(Spec,uint256) (src/Composer.sol#71-119) uses timestamp for comparisons
    [low/medium] timestamp at src/Registry.sol:291: Registry._ask(uint16,address,uint256) (src/Registry.sol#291-327) uses timestamp for comparisons
    [low/medium] timestamp at src/Registry.sol:468: Registry._store(bytes32,Registry.Pending,OracleAttestation) (src/Registry.sol#468-483) uses timestamp for comparisons
    [low/medium] timestamp at src/Composer.sol:154: Composer.compose(uint16,Spec,address,address,address) (src/Composer.sol#154-168) uses timestamp for comparisons
    [low/medium] timestamp at src/Registry.sol:394: Registry._check(Registry.Pending,OracleAttestation,bytes) (src/Registry.sol#394-422) uses timestamp for comparisons
    #1484Claudetests failed

    Committed. Time is up, so here is the state of the delivery.

    Outcome: partial. The three contracts, the table generator and a test suite are committed, but the tree is not yet deployable because the Composer exceeds EIP-170. The spec in docs/REBUILD.md is several weeks of work and the budget was under two hours, so I prioritised the Registry rules, byte-exact catalog bodies and the callback flows.

    What passes:

    • forge build, forge fmt --check, python3 tools/gen_template.py --check and the generator's unittest.
    • 23 of 24 tests under the verifier's fuzz seed: mint fee forwarding and the frozen snapshot, transfers keeping the claimant, every upgrade guard, RequestIdTaken, clear-then-check with miss reasons 2, 5, 7, 8, 10 and replay 1, onFailure, settle (11, 5, 8, success, NotPending), shared facts including the amount-list refusal, spec grammar and field rules, the constructor floor, abandon boundaries, and a state-diff test that a delivery writes no slot from zero.
    • The seven catalog fixtures and the T6 fixture are byte-exact, and their plane questionHash values are reproduced.

    What is open:

    • Composer runtime is 30,620 bytes, 6,044 over EIP-170. The sum is 75,398 against the 69,800 budget. Causes and the remaining lever (a template interpreter over the text blob plus the minimal parser 3.6 permits) are recorded in test/NOTES.md.
    • test_communityFixtures (T2, T4, T5 composed bodies) still fails on an undiagnosed byte mismatch.
    • Not delivered: SVG goldens, the maximum-state tokenURI gas number, hostile-registry cases, the attestation-vector test, fork tests, script/Deploy.s.sol, and the section-10 document updates beyond README.md and test/NOTES.md.

    Everything is in commit 700de63 on this branch.

    ran onclaude · claude-fable-5-1 · 61 turns · 27m 7s · 1.4K in · 125.8K out · 9M cached
    submissiona6d71498d014fc13faeeae6f047d83f903d3c868940999da086bbdfeff3313bf
    deviceddfb1efa72fe9a944b35a41fae3d545fecd8a16eddcd9989e5e9cf62dce9b119
    started fromf9c278cf271cb5804050f63c804878feb2dd0238
    bundleb6fbb36357df3429c5baab657de761ebe8ed96daa73c8927cc1c660d751e5221 · 41 KB
    changed · 13 files
    README.mdsrc/Composer.solsrc/HiveTables.solsrc/Registry.solsrc/Renderer.solsrc/Texts.solsrc/Types.soltest/Composer.t.soltest/NOTES.mdtest/Registry.t.soltest/mocks/Mocks.soltools/gen_template.pytools/test_gen_template.py
    #560Claudeanalysis failed

    All green. Final state:

    Delivered (all new, from the specification alone):

    • src/Registry.sol, src/Composer.sol (+ Grammar.sol), src/Renderer.sol (+ generated HiveTables.sol), src/Types.sol.
    • test/Composer.t.sol, test/Registry.t.sol, test/Mocks.sol, test/NOTES.md; script/Deploy.s.sol; tools/gen_template.py with its unit test; README.md rewritten.

    Checks run (all pass):

    • forge build --sizes: Composer 24,336, Registry 23,278, Renderer 17,577 bytes; sum 65,191 under the 69,800 budget, each under EIP-170, no immutables.
    • forge test with the verifier's fuzz seed: 24 tests, 0 failures. Every one of the 11 fixture bodies is reproduced byte for byte and every canonical-document keccak equals the plane's questionHash (the fault that rejected the previous attempt: panel 11/7 vs 5/3 for T4 and T5 community bodies). The protocol's EIP-712 vector digest and callback selector match.
    • forge fmt --check, python3 tools/gen_template.py --check, python3 -m unittest discover -s tools.

    What the tests cover: fee forwarding to the executor, frozen direct snapshot and transfers, the constructor floor and off-floor checks, one-id upgrade with its reverts, the callback through a mock Intake v2's real 200,000-gas call with the miss reasons 2 to 10 in order, replay as reason 1, a 262,144-byte answer ending as a miss, onFailure, the shared fact (head exact, amount words below 2**80 refused, apply with hash and membership), settle (reason 11 before completion, 5/8/2 reverts, one store, NotPending after), the 31-day strict abandon and the early abandon of a completed undelivered request, RequestIdTaken, the 601 living window stored and compared, community ids of a card holder, sizes and determinism, and state-diff assertions that no delivery writes a slot from zero.

    Not delivered, recorded in test/NOTES.md: SVG golden files under test/fixtures/, fork tests behind SWORN_FORK_RPC, the maximal-spec fuzz and the hostile-registry renderer cases. Two documented choices: a kind-5 spec's item must be empty, and off mainnet validateSpec uses its blockNumber argument, which the Registry fills with mainnetHeightBound().

    ran onclaude · claude-fable-5-1 · 72 turns · 34m 26s · 1.5K in · 143.3K out · 10.3M cached
    submissiond4372c9cba6a3b87f633954a4af1c49ef235e43f70fc2481fdfb5296f8d74f8a
    deviceca075d17c94a854b1fe62aca56a0429037b7c1243b841fe919215375b710a27a
    started fromf9c278cf271cb5804050f63c804878feb2dd0238
    bundle6a7a736782bb371357c263fd807bb1de4e99128916c5fdd8f577f642333c6147 · 44 KB
    changed · 14 files
    README.mdscript/Deploy.s.solsrc/Composer.solsrc/Grammar.solsrc/HiveTables.solsrc/Registry.solsrc/Renderer.solsrc/Types.soltest/Composer.t.soltest/Mocks.soltest/NOTES.mdtest/Registry.t.soltools/gen_template.pytools/test_gen_template.py
    #1025Codexanalysis failed

    Implemented Renderer, Composer and Registry, with ABI exports, deterministic generators, tests and operational documentation.

    Validation passed: forge build, forge fmt --check, 49 Foundry tests, four Python tests, generator and ABI checks.

    Two optional fork tests were skipped because the Foundry RPC connection was refused. Limitations and measurements are recorded in test/NOTES.md.

    ran oncodex · gpt-6-astra · 13 turns · 53m 41s · 342.3K in · 112.1K out · 13M cached
    submission72febd8b456246566b5340ffb8560a8323297dc430b42fb2cffb3d6a1a223093
    device18527ba42d5b89d70709a5a23dcf11d4b9d613f59242e342175dc5281e4995ba
    started fromf9c278cf271cb5804050f63c804878feb2dd0238
    bundlefb8b498f0e2fd36dca5319eef1e57309af9a39dfdaf12bf34b3b528695349d9b · 120 KB
    changed · 130 files
    CATALOG.mdCONCEPT.mdDISCLOSURE.mdINTEGRATION.mdREADME.mddocs/DEPENDENCY_CHECKS.mddocs/abi/Composer.jsondocs/abi/README.mddocs/abi/Registry.jsondocs/abi/Renderer.jsonscript/Deploy.s.solsrc/Composer.solsrc/Registry.solsrc/Renderer.solsrc/Types.solsrc/interfaces/Dependencies.solsrc/interfaces/IOracleConsumer.solsrc/interfaces/IWhitelistCurator.solsrc/lib/Catalog.solsrc/lib/Grammar.solsrc/lib/Hive.solsrc/lib/Recipes.solsrc/lib/Text.soltest/Artifacts.t.soltest/Base.t.soltest/Composer.t.soltest/Gas.t.soltest/Goldens.t.soltest/Invariants.t.soltest/MaximumState.t.soltest/Mocks.soltest/NOTES.mdtest/OracleConformance.t.soltest/Registry.t.soltest/RenderMocks.soltest/Text.t.soltest/fixtures/cases.jsontest/fixtures/community_13.jsontest/fixtures/community_13.svgtest/fixtures/community_13.uritest/fixtures/community_26.jsontest/fixtures/community_26.svgtest/fixtures/community_26.uritest/fixtures/community_39.jsontest/fixtures/community_39.svgtest/fixtures/community_39.uritest/fixtures/community_40.jsontest/fixtures/community_40.svgtest/fixtures/community_40.uritest/fixtures/community_5000.jsontest/fixtures/community_5000.svgtest/fixtures/community_5000.uritest/fixtures/community_70.jsontest/fixtures/community_70.svgtest/fixtures/community_70.uritest/fixtures/community_8192.jsontest/fixtures/community_8192.svgtest/fixtures/community_8192.uritest/fixtures/dot_1001.jsontest/fixtures/dot_1001.svgtest/fixtures/dot_1001.uritest/fixtures/dot_1101.jsontest/fixtures/dot_1101.svgtest/fixtures/dot_1101.uritest/fixtures/dot_1102.jsontest/fixtures/dot_1102.svgtest/fixtures/dot_1102.uritest/fixtures/dot_1103.jsontest/fixtures/dot_1103.svgtest/fixtures/dot_1103.uritest/fixtures/dot_1104.jsontest/fixtures/dot_1104.svgtest/fixtures/dot_1104.uritest/fixtures/dot_1105.jsontest/fixtures/dot_1105.svgtest/fixtures/dot_1105.uritest/fixtures/dot_1201.jsontest/fixtures/dot_1201.svgtest/fixtures/dot_1201.uritest/fixtures/dot_202.jsontest/fixtures/dot_202.svgtest/fixtures/dot_202.uritest/fixtures/dot_801.jsontest/fixtures/dot_801.svgtest/fixtures/dot_801.uritest/fixtures/dot_901.jsontest/fixtures/dot_901.svgtest/fixtures/dot_901.uritest/fixtures/empty.jsontest/fixtures/empty.svgtest/fixtures/empty.uritest/fixtures/escape.jsontest/fixtures/escape.svgtest/fixtures/escape.uritest/fixtures/generated.sha256test/fixtures/partial_201.jsontest/fixtures/partial_201.svgtest/fixtures/partial_201.uritest/fixtures/partial_301.jsontest/fixtures/partial_301.svgtest/fixtures/partial_301.uritest/fixtures/partial_302.jsontest/fixtures/partial_302.svgtest/fixtures/partial_302.uritest/fixtures/partial_401.jsontest/fixtures/partial_401.svgtest/fixtures/partial_401.uritest/fixtures/partial_402.jsontest/fixtures/partial_402.svgtest/fixtures/partial_402.uritest/fixtures/partial_403.jsontest/fixtures/partial_403.svgtest/fixtures/partial_403.uritest/fixtures/partial_501.jsontest/fixtures/partial_501.svgtest/fixtures/partial_501.uritest/fixtures/partial_502.jsontest/fixtures/partial_502.svgtest/fixtures/partial_502.uritest/fixtures/single.jsontest/fixtures/single.svgtest/fixtures/single.uritest/fixtures/widest.jsontest/fixtures/widest.svgtest/fixtures/widest.uritest/fork/Mainnet.t.soltools/export_abi.pytools/gen_recipes.pytools/gen_template.pytools/test_generator.py
  2. Audit economics
    waits onBuild contract project
  3. Audit flow
    waits onBuild contract project
  4. Audit math
    waits onBuild contract project
  5. Audit permissions
    waits onBuild contract project
  6. Manifest
    waits onBuild contract project
    may write
    launch.json
  7. Write foundry tests
    waits onBuild contract project
    may write
    testtest/**
  8. Audit judge
    waits onBuild contract project, Write foundry tests, Manifest, Audit math, Audit permissions, Audit economics, Audit flow
  9. Deployed
  10. Website built
  11. Website published
  12. Hosted
  13. Checked