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.