{"workflow":null,"planning":null,"id":"1761697b-d19b-4483-9653-e881ba693417","state":"blocked","template":"shape:chain","objective":"Project: SwapADay, a daily-play prize-pot contract. Chain id 11155111. NO launch token, NO pool, NO distributor: application contracts only. The contract holds real user funds, so every rule below is a hard requirement. Do not claim an audit was performed.\n\nGAME. A play costs a buy of IMDO plus a 1 USDC entry. One play per address per UTC day. The whole 1 USDC goes into ONE running pot. Every play gets one verifiable random roll and wins with probability 1 in ODDS (default 2500, an immutable constructor argument, minimum 2). On a win the ENTIRE pot is split 50/50: half to the winner, half to an immutable offsetsRecipient; any odd unit goes to offsetsRecipient; the pot resets to zero. There is no daily payout; the pot only grows until someone wins.\n\nplay(uint256 minTokensOut) external payable nonReentrant:\n1. Revert if the caller already played in the current UTC day (day = block.timestamp / 1 days).\n2. Chainlink VRF v2.5 DIRECT FUNDING, native payment: read the VRF wrapper's calculateRequestPriceNative for the callback gas limit; that fee is taken from msg.value; the remainder is swapEth.\n3. Require swapEth to be worth at least MIN_SWAP_USD (default 5 USD, immutable) using a Chainlink ETH/USD AggregatorV3 feed (immutable address). Reject a stale (older than 1 hour), zero or negative answer. Allow 2% tolerance below the minimum.\n4. Swap swapEth for the game token with the Uniswap v4 PoolManager (unlock/swap/settle/take, native ETH in) through the configured pool key, delivering the tokens straight to msg.sender. Revert if tokens received < minTokensOut. Measure the output by the recipient's balance change, never by a return value alone. The swap is a BUY only.\n5. Pull exactly ENTRY_USDC (1,000,000 units of a 6-decimals USDC, immutable) from msg.sender with transferFrom (the caller approves first) and add it to pot.\n6. Request one random word and store requestId => player. Emit Played(player, requestId, day, swapEth, tokensOut).\n\nfulfillRandomWords(requestId, words): callable ONLY by the VRF wrapper (rawFulfillRandomWords pattern). It must NEVER revert. If words[0] % ODDS == 0: prize = pot / 2; offsets = pot - prize; pot = 0; credit prize to the player and offsets to offsetsRecipient by trying a USDC transfer in a try/catch and, if that transfer fails, recording the amount in claimable[address] so a blacklisted or reverting recipient cannot block the callback. Provide claim() for anyone to withdraw their own claimable balance. Emit Settled(requestId, player, won, prize, offsets). A requestId settles at most once. Out-of-order and concurrent fulfillments must each be evaluated against the pot at that moment.\n\nCONFIG (the ONLY mutable thing): the game token and its v4 pool key (currency0 native ETH, currency1 token, fee, tickSpacing, hooks) may be changed by an owner (a Safe multisig, set in the constructor) through a TIMELOCK: proposeConfig(...) starts a delay of CONFIG_DELAY (default 48 hours, immutable), applyConfig() executes only after the delay, cancelConfig() cancels. Emit events for each. While a proposal is pending, play() keeps using the old config. The owner can do NOTHING else: no pause, no withdraw, no change to the pot, the odds, the entry fee, the minimum, the 50/50 split, offsetsRecipient, USDC, the price feed or the VRF settings, and cannot move user funds or the pot. Say exactly what the owner can call in the README. Immutable constructor arguments: usdc, offsetsRecipient, vrfWrapper, ethUsdFeed, poolManager, odds, minSwapUsd, entryUsdc, configDelay, owner, and the initial token and pool key.\n\nSAFETY. Reentrancy-guard every external entry point; follow checks-effects-interactions; no ERC-777 or fee-on-transfer assumptions for USDC; handle USDC 6 decimals and the ETH/USD feed decimals correctly; use safe-transfer patterns; no unchecked arithmetic on money. The contract must never hold ETH beyond a transaction (refund any excess msg.value after the swap and the VRF fee).\n\nBUILD REPRODUCIBILITY: the repository MUST contain a root foundry.toml setting bytecode_hash = \"none\" under [profile.default]; pin solc, optimizer runs and evm_version. The README must quote foundry.toml verbatim and list every constant and who can call what.\n\nTESTS (Foundry; a different worker writes them). Use mocks for the VRF wrapper, the ETH/USD feed, the PoolManager swap and USDC. Cover: one play per address per UTC day and the rollover at 00:00 UTC; the whole 1 USDC enters the pot; the exact 50/50 split with an odd-unit pot; the pot resets to zero after a win; forced words that do and do not win at ODDS; only the VRF wrapper can fulfill; fulfillment never reverts even when a recipient reverts or is blacklisted (claimable fallback); a request settles once; concurrent pending plays settle against the pot at fulfillment; stale, zero and low-value price feeds are rejected; the 2% tolerance boundary; minTokensOut slippage; excess msg.value refunded and no ETH left in the contract; reentrancy attempts via a malicious token and a malicious recipient; the timelock (apply before the delay reverts, cancel works, old config stays live while pending); the owner cannot move funds or touch any immutable; a fuzz/invariant test that pot plus claimable plus paid out equals USDC received. Keep the contract small and readable.","blockedReason":"node manifest: runtime_error","createdAt":"2026-10-03T23:47:29.860Z","updatedAt":"2026-10-04T00:46:27.958Z","paidBy":"0x28aa88fb640ef295a41b2759fe240c5c7578c2db","parentJobId":null,"project":{"id":"1761697b-d19b-4483-9653-e881ba693417","head":"1761697b-d19b-4483-9653-e881ba693417","running":null,"versions":[{"jobId":"1761697b-d19b-4483-9653-e881ba693417","workflowId":null,"objective":"Project: SwapADay, a daily-play prize-pot contract. Chain id 11155111. NO launch token, NO pool, NO distributor: application contracts only. The contract holds real user funds, so every rule below is a hard requirement. Do not claim an audit was performed.\n\nGAME. A play costs a buy of IMDO plus a 1 USDC entry. One play per address per UTC day. The whole 1 USDC goes into ONE running pot. Every play gets one verifiable random roll and wins with probability 1 in ODDS (default 2500, an immutable constructor argument, minimum 2). On a win the ENTIRE pot is split 50/50: half to the winner, half to an immutable offsetsRecipient; any odd unit goes to offsetsRecipient; the pot resets to zero. There is no daily payout; the pot only grows until someone wins.\n\nplay(uint256 minTokensOut) external payable nonReentrant:\n1. Revert if the caller already played in the current UTC day (day = block.timestamp / 1 days).\n2. Chainlink VRF v2.5 DIRECT FUNDING, native payment: read the VRF wrapper's calculateRequestPriceNative for the callback gas limit; that fee is taken from msg.value; the remainder is swapEth.\n3. Require swapEth to be worth at least MIN_SWAP_USD (default 5 USD, immutable) using a Chainlink ETH/USD AggregatorV3 feed (immutable address). Reject a stale (older than 1 hour), zero or negative answer. Allow 2% tolerance below the minimum.\n4. Swap swapEth for the game token with the Uniswap v4 PoolManager (unlock/swap/settle/take, native ETH in) through the configured pool key, delivering the tokens straight to msg.sender. Revert if tokens received < minTokensOut. Measure the output by the recipient's balance change, never by a return value alone. The swap is a BUY only.\n5. Pull exactly ENTRY_USDC (1,000,000 units of a 6-decimals USDC, immutable) from msg.sender with transferFrom (the caller approves first) and add it to pot.\n6. Request one random word and store requestId => player. Emit Played(player, requestId, day, swapEth, tokensOut).\n\nfulfillRandomWords(requestId, words): callable ONLY by the VRF wrapper (rawFulfillRandomWords pattern). It must NEVER revert. If words[0] % ODDS == 0: prize = pot / 2; offsets = pot - prize; pot = 0; credit prize to the player and offsets to offsetsRecipient by trying a USDC transfer in a try/catch and, if that transfer fails, recording the amount in claimable[address] so a blacklisted or reverting recipient cannot block the callback. Provide claim() for anyone to withdraw their own claimable balance. Emit Settled(requestId, player, won, prize, offsets). A requestId settles at most once. Out-of-order and concurrent fulfillments must each be evaluated against the pot at that moment.\n\nCONFIG (the ONLY mutable thing): the game token and its v4 pool key (currency0 native ETH, currency1 token, fee, tickSpacing, hooks) may be changed by an owner (a Safe multisig, set in the constructor) through a TIMELOCK: proposeConfig(...) starts a delay of CONFIG_DELAY (default 48 hours, immutable), applyConfig() executes only after the delay, cancelConfig() cancels. Emit events for each. While a proposal is pending, play() keeps using the old config. The owner can do NOTHING else: no pause, no withdraw, no change to the pot, the odds, the entry fee, the minimum, the 50/50 split, offsetsRecipient, USDC, the price feed or the VRF settings, and cannot move user funds or the pot. Say exactly what the owner can call in the README. Immutable constructor arguments: usdc, offsetsRecipient, vrfWrapper, ethUsdFeed, poolManager, odds, minSwapUsd, entryUsdc, configDelay, owner, and the initial token and pool key.\n\nSAFETY. Reentrancy-guard every external entry point; follow checks-effects-interactions; no ERC-777 or fee-on-transfer assumptions for USDC; handle USDC 6 decimals and the ETH/USD feed decimals correctly; use safe-transfer patterns; no unchecked arithmetic on money. The contract must never hold ETH beyond a transaction (refund any excess msg.value after the swap and the VRF fee).\n\nBUILD REPRODUCIBILITY: the repository MUST contain a root foundry.toml setting bytecode_hash = \"none\" under [profile.default]; pin solc, optimizer runs and evm_version. The README must quote foundry.toml verbatim and list every constant and who can call what.\n\nTESTS (Foundry; a different worker writes them). Use mocks for the VRF wrapper, the ETH/USD feed, the PoolManager swap and USDC. Cover: one play per address per UTC day and the rollover at 00:00 UTC; the whole 1 USDC enters the pot; the exact 50/50 split with an odd-unit pot; the pot resets to zero after a win; forced words that do and do not win at ODDS; only the VRF wrapper can fulfill; fulfillment never reverts even when a recipient reverts or is blacklisted (claimable fallback); a request settles once; concurrent pending plays settle against the pot at fulfillment; stale, zero and low-value price feeds are rejected; the 2% tolerance boundary; minTokensOut slippage; excess msg.value refunded and no ETH left in the contract; reentrancy attempts via a malicious token and a malicious recipient; the timelock (apply before the delay reverts, cancel works, old config stays live while pending); the owner cannot move funds or touch any immutable; a fuzz/invariant test that pot plus claimable plus paid out equals USDC received. Keep the contract small and readable.","baseCommit":"0243d7da4a4337ae8b16bcdf15bb4ead736fd68f","state":"blocked","createdAt":"2026-10-03T23:47:29.860Z"}]},"deliver":true,"host":false,"site":null,"launch":{"requested":true,"kind":"evm_contracts","id":null,"status":null,"chainId":null},"oracleRequestId":null,"delivery":null,"media":null,"nodes":[{"key":"audit_economics","role":"review","state":"waiting","attempt":0,"revisions":0,"judgeRevisions":0,"dependsOn":["implement_contract","write_foundry_tests","manifest"],"allowedPaths":[],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-03T23:47:29.860Z","verdict":null,"seat":null,"live":null},{"key":"audit_flow","role":"review","state":"waiting","attempt":0,"revisions":0,"judgeRevisions":0,"dependsOn":["implement_contract","write_foundry_tests","manifest"],"allowedPaths":[],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-03T23:47:29.860Z","verdict":null,"seat":null,"live":null},{"key":"audit_judge","role":"review","state":"waiting","attempt":0,"revisions":0,"judgeRevisions":0,"dependsOn":["implement_contract","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"allowedPaths":[],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-03T23:47:29.860Z","verdict":null,"seat":null,"live":null},{"key":"audit_math","role":"review","state":"waiting","attempt":0,"revisions":0,"judgeRevisions":0,"dependsOn":["implement_contract","write_foundry_tests","manifest"],"allowedPaths":[],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-03T23:47:29.860Z","verdict":null,"seat":null,"live":null},{"key":"audit_permissions","role":"review","state":"waiting","attempt":0,"revisions":0,"judgeRevisions":0,"dependsOn":["implement_contract","write_foundry_tests","manifest"],"allowedPaths":[],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-03T23:47:29.860Z","verdict":null,"seat":null,"live":null},{"key":"implement_contract","role":"implement","state":"accepted","attempt":1,"revisions":2,"judgeRevisions":0,"dependsOn":[],"allowedPaths":["src/SwapADay.sol","script/Deploy.s.sol","README.md","foundry.toml"],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-04T00:28:10.577Z","verdict":{"status":"accepted","profile":"foundry","evaluation":"checks","rejectionCode":null,"detail":"all checks passed","verifierVersion":"0.1.0+6698e07d","verifiedTreeHash":"61962d29b5f679f7e48325bfd7189ab4757eb24f","at":"2026-10-04T00:04:44.302Z","failedChecks":[]},"seat":{"tokenId":"1548","agentId":"50971"},"live":null},{"key":"manifest","role":"integrate","state":"failed","attempt":3,"revisions":0,"judgeRevisions":0,"dependsOn":["implement_contract","write_foundry_tests"],"allowedPaths":["launch.json"],"failureReason":"runtime_error","dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-04T00:46:27.958Z","verdict":{"status":"rejected","profile":"foundry","evaluation":"checks","rejectionCode":"analysis_failed","detail":"launch.json: SwapADay: expected 3 constructor arguments, got 16","verifierVersion":"0.1.0+6698e07d","verifiedTreeHash":"8bfeb2ed8a01559d064733cd5aa742349d729edc","at":"2026-10-04T00:44:03.146Z","failedChecks":[]},"seat":null,"live":null},{"key":"write_foundry_tests","role":"tests","state":"accepted","attempt":1,"revisions":2,"judgeRevisions":0,"dependsOn":["implement_contract"],"allowedPaths":["test/SwapADay.t.sol"],"failureReason":null,"dispatchNote":"write_foundry_tests findings unresolved after 2 revisions: no revision budget left for implement_contract (2 revisions) — Required root Foundry configuration is missing","dispatchNoteAt":"2026-10-04T00:34:49.893Z","updatedAt":"2026-10-04T00:34:49.893Z","verdict":{"status":"accepted","profile":"foundry","evaluation":"checks","rejectionCode":null,"detail":"all checks passed","verifierVersion":"0.1.0+6698e07d","verifiedTreeHash":"47e83eb2f173eb6d268d5e04cbd13f4d394e5957","at":"2026-10-04T00:34:49.893Z","failedChecks":[]},"seat":{"tokenId":"1120","agentId":"50957"},"live":null}],"reviews":[{"status":"sent","chainId":1,"txHash":"0x3cb8eb7ecf14121fe924730a018521e469eb0bfed0e2021c7047d077e4736967","blockNumber":26116472,"sentAt":"2026-10-04T04:03:14.850Z","entries":[{"nodeKey":"implement_contract","agentId":"50971","value":1,"role":"verification:checks"},{"nodeKey":"manifest","agentId":"50971","value":0,"role":"verification:checks"},{"nodeKey":"write_foundry_tests","agentId":"50957","value":1,"role":"verification:checks"}]}]}