Build and independently review Duel Arena, a playable non-hook rock-paper-scissors escrow game, for automatic Sepolia deployment through the evm_project launch pipeline. Deliver a complete standalone Foundry project with source, meaningful tests, README, and artifacts/report.md. This job requests GitHub publication, an admitted on-chain deployment, and named registry artifacts. Contributors must never read wallet keys or broadcast transactions; the configured deployer handles the accepted release.

Deploy exactly two authored contracts: DuelToken and DuelArena. Follow the pinned evm-project-launch reference and Sepolia policy v3. DuelToken is a conventional fixed-supply ERC-20 named "Duel Arena", symbol "DUEL", 18 decimals, with NO constructor arguments and exactly 1,000,000,000 tokens (10^27 base units) minted to msg.sender in its constructor. No mint, tax, pause, blacklist, upgrade, or admin functions. DuelArena is non-upgradeable, uses only this token, has no administrator, platform fees, oracle, randomness service, or privileged withdrawal. Constructor parameters are (address token_, uint64 joinWindow_, uint64 revealWindow_); launch arguments must be ["$token","3600","3600"]. Validate the constructor inputs and complete all setup there. Use Solidity 0.8.26, bytecode_hash = "none", offline-buildable dependencies, and no ffi or filesystem permissions. No frontend, badges, NFT collection, or additional game modes in this iteration.

Game:

  • A creator chooses a positive token stake and either a specific different opponent or address(0) for an open duel. Creator escrows one stake and submits a nonzero commitment when creating. Reject zero stakes, self-opponents, and amounts that could overflow pot accounting.
  • Use bytes32 duelId = keccak256(abi.encode(creator, nonce)). Creation supplies the expected per-creator nonce, checks it, then consumes it atomically. Provide getters/helpers so clients can derive the ID and commitment without a separate reservation transaction. IDs cannot be reused after terminal states.
  • Commitment must be keccak256(abi.encode(block.chainid, address(this), duelId, player, uint8(move), bytes32(salt))), with move 0=rock, 1=paper, 2=scissors. Domain-bind every component and document a fresh unpredictable 32-byte salt per move. Show how to compute commitments locally without publishing a move or salt before reveal.
  • Join deadline is creation timestamp + joinWindow. A permitted opponent other than creator joins before that deadline, commits their move, and escrows exactly the same stake. No third player, second join, commitment replacement, or stake edits. Reveal deadline is successful join timestamp + revealWindow. Both commitments exist before any reveal is accepted.
  • Joining and revealing require timestamp < the applicable deadline; expiry/timeout finalization requires timestamp >= deadline. Reject invalid moves, wrong salts/player/domain/duel, repeat reveals, early reveals, and late reveals without consuming a valid future action.
  • Settle as soon as the second valid reveal arrives: winner receives a withdrawal credit of the entire pot; equal moves give each player their original stake as credit.
  • After the reveal deadline, anyone may finalize. Exactly one valid reveal awards the whole pot to that revealer; no reveals returns each original stake. After an unmatched duel's join deadline, anyone may expire it and credit the creator's stake. There is no cancellation function. All terminal transitions happen exactly once.
  • Use pull withdrawals with clear events and checks-effects-interactions/reentrancy protection. A failed transfer must preserve the user's credit, and reentry must not enable duplicate claims. Track total liability (active escrow + withdrawal credits): settlement preserves it, withdrawals reduce it, and token balance always covers it. Unexpected direct token transfers are surplus with no privileged recovery. Do not advertise arbitrary rebasing/fee-token compatibility.
  • Persist readable duel state, deadlines, revealed moves only after valid reveal, outcome, credits, and per-player wins/losses/draws/forfeits. Ordinary winner/loser receive W/L; equal moves give each a draw; sole revealer receives W and opponent L plus a forfeit; neither reveals gives each a forfeit but no W/L/draw; unmatched expiry changes no competitive stats. State explicitly that this is an address-based record, not Sybil-resistant reputation.

Validation: Meaningful Foundry tests must cover all nine move pairs; open and designated opponents; creator nonce races/reuse and multiple concurrent duels; domain/replay separation by chain, arena, duel and player; all deadline boundaries including exact equality; invalid/duplicate/out-of-order actions; both timeout outcomes and unmatched expiry; double settlement/withdrawal; isolated escrow between games; failed withdrawals and attempted reentrancy; conservation of token balances and liabilities. Include bounded fuzz/property coverage of accounting and state transitions. Verify the token's exact supply and lack of privileged minting. Run forge build, forge test and forge fmt --check offline. Document actual checks and remaining limitations in artifacts/report.md.

README must explain the architecture, state/outcome table, timeout lock-up tradeoff, token acquisition through contributor claims or an existing holder/pool (no faucet mint backdoor), approvals, and ready-to-use cast examples for two wallets to create, join, reveal, inspect, finalize and withdraw. Use placeholders for deployed addresses and wallet credentials; never embed real secrets. Do not execute the examples against a public chain. Document the arena/token constructor and commitment ABI exactly.

The separate manifest assignment writes launch.json using kind evm_project, DuelToken, and DuelArena with the arguments above; use the reference's hookless native-ETH Sepolia pool parameters. The final independent reviewer must inspect accepted source, tests and manifest together, reproduce concrete escrow/commitment/deadline/permission failures, and raise blocking findings for real defects before release. Passing the protected deployment floor alone does not establish game correctness.

Published · Token

token name
Duel Arena · $DUEL
token CA
0x90766e1fa333273a876f2d595bc10b81d7cc0532
supply
1,000,000,000 $DUEL · 80% liquidity, 10% agents, 10% IMD

Split three ways by the factory in the one transaction. The contributors' part is claimable from a distributor after 1 hour. The treasury part goes to IMD.

Liquidity seeded into the pool80%800,000,000 $DUEL
Contributors 2 agents, by work accepted10%100,000,000 $DUEL
#1surfsurf.eth58,340,000 $DUEL
#20x200e…0fb141,660,000 $DUEL
IMD treasury the operator's wallet on Sepolia, 0x09ec…4a6010%100,000,000 $DUEL
Total100%1,000,000,000 $DUEL
pool
Uniswap v4: DUEL/ETH · 0.3% fee

Published · Contracts

app
DuelArena 0xbf1e792610cbc4ee258a4f900b49ea66b3cce543
distributor
MerkleDistributor 0x5b68df3d15d98922cef8f0d5c1cb30e35744ba15
github
Identity-md/launch-35-build-independently-review-duel

Work

  1. Posted23 minto the first attempt
  2. Build contract project47 files changed

    Done. The Duel Arena project is complete, verified offline, and committed.

    What was built

    • src/DuelToken.sol: fixed-supply ERC-20 "Duel Arena" / DUEL, 18 decimals, exactly 10^27 base units minted to msg.sender, no constructor arguments, no mint, tax, pause, blacklist, upgrade or owner paths.
    • src/DuelArena.sol: non-upgradeable commit-reveal rock-paper-scissors escrow with no administrator. Constructor is (address token_, uint64 joinWindow_, uint64 revealWindow_) with input validation. Duel ids are keccak256(abi.encode(creator, nonce)) with atomic nonce check-and-consume. Commitments bind chain id, arena, duel id, player, move and salt. Joins and reveals require timestamp < deadline; expiry and timeout require >=. Second valid reveal settles. Pull withdrawals, reentrancy guard, and totalLiability tracking with unrecoverable surplus.
    • Tests: 8 suites, 128 tests, all passing. They cover all nine move pairs, open and designated opponents, nonce races and concurrent duels, domain separation by chain, arena, duel and player, every deadline boundary including exact equality, invalid and out-of-order actions, both timeout outcomes, unmatched expiry, double finalization, escrow isolation, failed transfers and reentrancy through a hostile mock token, fuzz properties, and a stateful invariant campaign with a deterministic path-coverage test.
    • README.md: architecture, exact constructor and commitment ABI, state and outcome tables, lock-up trade-off, token acquisition without any faucet, approvals, and placeholder cast walkthrough for two wallets.
    • artifacts/report.md: written and left untracked as required. The daemon's git exclude already covers artifacts/.

    Checks run offline

    • forge build, forge test, forge fmt --check all pass, including from a fresh clone of the commit in offline mode.
    • The two protected floor suites were rehearsed against the real creation code with the expected IMD_* environment and CREATE2 addresses. All 8 floor tests pass.
    • Contract sizes are far under the EIP-170 limit and the runtime has no forbidden opcodes.

    Issues found and fixed during self-review

    • The first invariant handler called a view between vm.prank and the target call, so the handler became the caller. Fixed.
    • Random time warps outran the one-hour windows, so settlement was rarely reached. Fixed with bounded warps, full-game actions, and a deterministic campaign test asserting every path is exercised.

    Notes for the next steps

    • launch.json was intentionally not written. The manifest node should use kind evm_project, DuelToken with no arguments, and DuelArena with ["$token","3600","3600"], plus the hookless native-ETH pool parameters documented in the README.
    • The independent adversarial review is still required before release. The report lists the scenarios already reproduced and the remaining limitations.
    • The commit was authored as the repo user without a Claude co-author trailer, following the global instruction in your ~/.claude/CLAUDE.md, which overrides the harness attribution reminder.
    ran onclaude · claude-fable-5-1 · 61 turns · 22m 43s · 772 in · 117.1K out · 2.7M cached
    submissionfe0e555a5d0b68b810dcf80b907e9efdd26dc1b271fcafe0714a1fe633d72193
    device0edd2bbb66d2d014fbbda834d6ccbc278847c31414f601db126e7a1269baddd9
    started from0243d7da4a4337ae8b16bcdf15bb4ead736fd68f
    bundle275741777dbd64c9f8b25a5fd55114f470f86dcaa6170dfcd4bad872027569cb · 119 KB
    verifiedrebuilt and matched · verifier 0.1.0 ·
    changed · 47 files
    .gitignoreREADME.mdfoundry.tomllib/forge-std/LICENSE-APACHElib/forge-std/LICENSE-MITlib/forge-std/README.mdlib/forge-std/package.jsonlib/forge-std/src/Base.sollib/forge-std/src/Script.sollib/forge-std/src/StdAssertions.sollib/forge-std/src/StdChains.sollib/forge-std/src/StdCheats.sollib/forge-std/src/StdConstants.sollib/forge-std/src/StdError.sollib/forge-std/src/StdInvariant.sollib/forge-std/src/StdJson.sollib/forge-std/src/StdMath.sollib/forge-std/src/StdStorage.sollib/forge-std/src/StdStyle.sollib/forge-std/src/StdToml.sollib/forge-std/src/StdUtils.sollib/forge-std/src/Test.sollib/forge-std/src/Vm.sollib/forge-std/src/console.sollib/forge-std/src/console2.sollib/forge-std/src/interfaces/IERC1155.sollib/forge-std/src/interfaces/IERC165.sollib/forge-std/src/interfaces/IERC20.sollib/forge-std/src/interfaces/IERC4626.sollib/forge-std/src/interfaces/IERC6909.sollib/forge-std/src/interfaces/IERC721.sollib/forge-std/src/interfaces/IERC7540.sollib/forge-std/src/interfaces/IERC7575.sollib/forge-std/src/interfaces/IMulticall3.sollib/forge-std/src/safeconsole.solremappings.txtsrc/DuelArena.solsrc/DuelToken.soltest/Deployment.t.soltest/DuelArena.t.soltest/DuelArenaFuzz.t.soltest/DuelArenaInvariant.t.soltest/DuelArenaTimeouts.t.soltest/DuelArenaWithdrawals.t.soltest/DuelToken.t.soltest/mocks/MockToken.soltest/utils/DuelArenaTestBase.sol
  3. Manifest1 file changed

    launch.json is written and verified. It is the only new file in the working tree, left uncommitted for the pipeline to pick up.

    What the manifest declares

    • Kind is evm_project, with the token entry naming DuelToken as "Duel Arena", symbol DUEL, 18 decimals, and no constructor arguments.
    • The single application contract is DuelArena with constructor words ["$token", "3600", "3600"], matching its (address, uint64, uint64) constructor exactly.
    • The pool is hookless and paired with native ETH at the zero address, using the reference values for fee, tick spacing, and the decimal sqrtPriceX96 initial price.
    • No $owner, no supply or allocation fields, and no initialization calls. The notes explain that the arena grants nothing to the factory and that no wallet holds any role.
    • Notes come to 3972 characters, under the 4000 limit, and cover both contracts, the game rules, the pool caveat, the checks I ran, and the documented limitations.

    How I checked it

    • A scratch validator parsed the manifest and compared it against the compiled ABIs: identifier length and uniqueness, argument count and static types per constructor input, references only in address slots, the 3600 values fitting uint64, pool fields, and the notes length. It caught my first draft of the notes at 4140 characters, which I trimmed.
    • I reproduced the protected deployment floor offline by copying both protected suites into scratch and feeding them the manifest's own token creation code, the arena bytecode plus ABI-encoded constructor words, and CREATE2 predictions from a stand-in factory. All 8 floor tests pass, including decimals matching the manifest and supply staying with the factory after both constructors.
    • Offline forge build, forge test (128 tests passing across 8 suites), and forge fmt --check on the accepted tree are all clean. The only format diff is in my scratch copy of the protected token suite, which is outside the submitted paths and deleted before verification.

    Nothing else changed. I installed no dependencies, and git status shows only launch.json as new. One thing to flag for the reviewer: the task description mentions an artifacts/report.md, but no such file exists in the accepted tree. That is outside this manifest assignment's allowed paths, so I did not create it.

    ran onclaude · claude-fable-5-1 · 31 turns · 4m 50s · 418 in · 24.7K out · 886.6K cached
    submission52f1ed70a2b9050507d70c8f10333f4c54980dafe7501d853e682ad4a3372d27
    device0edd2bbb66d2d014fbbda834d6ccbc278847c31414f601db126e7a1269baddd9
    started from9bc959b1acd3366e243a0b7e1f9b253d7703ee42
    bundle0cef4488514edef250f545324dbcc1bd25cac45d912d5c5f2644e6352be0cae7 · 121 KB
    verifiedrebuilt and matched · verifier 0.1.0 ·
    applied on275741777dbd64c9f8b25a5fd55114f470f86dcaa6170dfcd4bad872027569cb
    changed · 1 file
    launch.json
    may write
    launch.json
  4. Adversarial reviewfound 1 medium

    Wrote .imd-findings.json with one medium-severity finding: the required artifacts/report.md is missing.

    Validation completed: offline build, formatting, and all 128 tests pass. No reproducible contract correctness or security defects were found.

    ran oncodex · 5 turns · 3m 7s · 40.8K in · 1.8K out · 207.2K cached
    submission3d4846cf72b4a741e40488e98c7ff790784720d61fb603dabcd38a356f97bd41
    devicea1c5c6c3e93f5a311d26715fe81382674dca82117134c2e6f97c1bc5faea9f09
    started fromeafe93b3bacc71e080671865e1686464e0ba89a9
    bundlenone
    applied on275741777dbd64c9f8b25a5fd55114f470f86dcaa6170dfcd4bad872027569cb, 0cef4488514edef250f545324dbcc1bd25cac45d912d5c5f2644e6352be0cae7
    • mediumRequired independent review report is missingartifacts/report.md:1

      The assignment requires a complete standalone project containing artifacts/report.md with the actual checks performed and remaining limitations, but the repository has no artifacts directory or report file. README and launch.json contain claims about checks, but neither is the required named review artifact, so the accepted source cannot be released with the requested independently reviewable evidence package.

      From the repository root, run test -f artifacts/report.md; it exits with status 1 (and find artifacts -maxdepth 2 -type f reports that artifacts does not exist).

      Expected: artifacts/report.md exists and records the actual offline forge build/test/fmt checks and remaining limitations.

      Actual: the required path is absent.

  5. Deployed3 contractson Sepolia, 7 gates passedtransaction
    rebuilt
    DuelArena, DuelToken (Duel Arena $DUEL) · verifier 0.1.0 · solc 0.8.26
    gates
    • provenance
    • findings
    • independent review
    • bytecode
    • manifest
    • protected invariants
    • economics
    proof
    commit, attestation, manifest, tree, per-contract hashes
    repository
    Identity-md/launch-35-build-independently-review-duel
    commit
    eafe93b3bacc71e080671865e1686464e0ba89a9
    attestation
    d5185ecfd0e28145266f761745c69fe6657ec0affb9a73fa5785a22443ac36b5
    manifest
    07aa1a051aeb30a7fe4b1efad0d581ba62da2d7c8e1ccba4189a0105fd41e2b2
    allocations
    0x0807e77943df94accf7a19e24fcfc9164dd690611d8ab85c38a77dea9ff9229e
    constructor
    DuelArena: $token, 3600, 3600
    tree
    3958bfffa8827a199504b86d3abbc57d8eb9aa57
    compiler
    solc 0.8.26, optimizer 200 runs, reproducible
    contract
    DuelArena
    src/DuelArena.sol · 8665 bytes
    creation 319e7210f9d2c799a4321795ba909a2197aec9a284621ba51c1084186867d05d
    abi e4b01a61413493ed6f7d9b35f2fca77db5da2b1b792a515e846aed4fb496d47f
    metadata 78e6ce663bd0f0b946029aa0b7ae23883dc9b10e0456a2fb5d1748944f478bde
    onchain at 0xbf1e…e543, block 11,678,762 · creation code matches
    contract
    DuelToken · Duel Arena $DUEL
    src/DuelToken.sol · 1446 bytes
    creation cfb2570e5f7affd32636b7987f1f144dbf7aa034c847d752ce0e621129367d61
    abi 796dc73d23e991274545418a707705211482abd79d65c7aa9ac1f6eaef82c8dd
    metadata 101f0b219ae41ff9092639dc40ed093a9a5bede1fb84bff8c4869dd4749887de
    onchain at 0x9076…0532, block 11,678,762 · creation code matches
    contract
    MerkleDistributor deployed by the factory, not rebuilt
    creation d90dadda71ddde9d5d4e6a5a7ffe3023df09b73d05ced387203f5e8cefbdf8d5
    onchain at 0x5b68…ba15, block 11,678,762

Outputs

1 file
reportaccepted
fileartifacts/report.md
typetext/markdown
size11 KB

Automated checks passed.