{"workflow":null,"planning":null,"id":"b8fd4c2b-e0a5-48bd-951f-222b3f3a342c","state":"completed","template":"shape:chain","objective":"Basket Protocol vault: an index vault for Stock Tokens on Robinhood Chain (chain id 4663). Contracts only: no launch token, pool or website. BASK is the vault's own ERC-20 share (18 decimals). Say \"Stock Tokens\", never \"tokenized\".\nToken name: Basket\nToken symbol: BASK\nTotal supply: 0 at deployment, no cap: deposit mints, redeem burns\n\nBUILD RULES\n- Simplest code that satisfies this text: add no feature, role, setting or safeguard.\n- solc 0.8.26, optimizer on, 200 runs, via_ir, evm cancun, bytecode_hash none; custom errors.\n- If BaskVault exceeds 24,000 bytes of runtime, move views into BaskLens(address vault = $contract:BaskVault); never drop a check.\n- Constructors call no other contract.\n- No proxy, delegatecall, selfdestruct, rescue or sweep. User-facing state changes are nonReentrant and emit events.\n\nMANIFEST\n1. BaskVault(address owner_, address guardian_): owner_ = 0x30B57ECf51D19ABcED7F6f70974e6fBb6f3b9Da3, guardian_ = 0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68, written as these literals. Reverts if either is zero or they are equal.\n\nOutside contracts (tests mock exactly these under test/; no fork tests, no vm.env):\n- Token: ERC-20; may have oraclePaused() returns bool.\n- Feed: decimals() <= 18, latestRoundData(); answer = USD per whole token.\n- Pool: Uniswap v3 style token0(), token1(), observe(uint32[]).\n\nASSETS: (token, feed, pool, quoteFeed, minLiquidity, open, retired, hasPause, centre), at most maxAssets. managed[token] is the accounting balance; value never uses balanceOf.\nListing checks (proposal and execution): token not listed; token and feed decimals() <= 18; feed not used by another unretired asset; answer > 0 and under maxAge. At listing: open, centre = answer, hasPause = oraclePaused() returns a bool.\nGenesis: until finalizeGenesis() (once, needs 3+ assets), the owner lists assets with their pools at once; deposits open at finalize.\nAnyone may remove a retired asset with managed and totalOwed 0; its token may then be listed again.\n\nPROPOSALS (owner): list an asset with its pool; new feed (centre = new answer); re-centre on the answer at execution, under maxAge; reopen (cancelled by any later close); retire (closed both times); set an asset's pool, quoteFeed and minLiquidity, or none; resync (managed += balanceOf - managed - totalOwed, if above 0); new guardian; raise NAV_CAP; set feeRecipient (not zero or the vault); change a setting within its bounds. A proposal waits 2 days, then only the owner executes it; it lapses 7 days later; the owner or guardian may cancel it, the guardian not its own replacement. A retired asset is closed for good, voids its pending proposals, then takes only resync, is 0 in NAV and skipped by every deposit check even with managed > 0.\n\nSETTINGS (start; bounds): band 4 (2-100); maxAge 80 hours, noPoolAge 26 hours (1 hour-30 days); freshCount 0 (0-10), freshHours 4 (1-48); hours Mon-Fri from-to UTC (seconds of day; start 0-0 = always open); poolWindow 1800 s (300-86400); poolDeviation 300 bps (50-2000); feedGas, pauseGas 100,000, poolGas 150,000, balanceGas 50,000, payGas 250,000 (each 20,000-500,000); maxAssets 250; directLimit 50. A change must keep maxAssets >= asset count, maxAssets * (balanceGas + 60,000) <= 28,000,000 and directLimit * (balanceGas + payGas + 70,000) <= 28,000,000.\n\nPRICE is valid only if the feed read succeeds (feedGas), answer > 0, centre / band <= answer <= centre * band, updatedAt <= now, now - updatedAt <= maxAge, oraclePaused() returns false if hasPause (pauseGas), and: with a pool, its observe over poolWindow (poolGas; Uniswap OracleLibrary.consult) succeeds with mean liquidity >= minLiquidity and its mean-tick price per whole token in whole quote tokens, times the quoteFeed price (> 0, under maxAge), is within poolDeviation of the feed price in USD; with no pool, now - updatedAt <= noPoolAge. value(amount) = amount * answer * 1e18 / 10^(token decimals + feed decimals), rounded down. USD amounts below are dollars times 1e18.\n\ndeposit(tokens[], amounts[], receiver, minSharesOut, deadline) requires:\n- deposits open, not paused, inside hours; each token listed, open, once, amount > 0, vault balance >= totalOwed[token]; receiver not the vault;\n- freshCount or more unretired assets updated within freshHours;\n- a valid price for each token and every unretired asset with managed > 0; no unretired asset short or unreadable.\nPull the tokens; each vault balance must rise by exactly its amount. NAV = sum of value(managed) before; v = sum of value(amounts).\ngross = v if totalSupply is 0, else v * totalSupply / NAV rounded down (revert if NAV is 0). fee = gross * 50 / 10000, rounded up, minted to feeRecipient; no fee while unset. The receiver gets gross - fee; on the first deposit 1e15 of that goes to address(0xdEaD) instead. It must be > 0 and >= minSharesOut. NAV + v <= NAV_CAP (starts 1,000,000; lowering cancels pending raises; never above 10,000,000,000).\n\nredeem(shares, receiver, minAmountsOut[], deadline), receiver not zero, reads no price, ignores every pause and never reverts because of an asset. fee = shares * 50 / 10000 rounded up, transferred to feeRecipient; no fee while unset. net = shares - fee is burned. Per asset with managed > 0: available = balanceOf(vault) - totalOwed[token], floor 0 (balanceGas static call, 32 bytes copied; else unreadable: available = managed); leg = min(managed, available) * net / totalSupplyBeforeBurn, rounded down; require leg >= minAmountsOut[i] (missing entry = 0); managed -= leg. If at most directLimit assets have managed > 0, each leg is paid to receiver by an external function only the vault may call, given payGas, reverting unless the transfer succeeds, returns nothing or true, and the vault balance falls by exactly leg; if that fails, or above directLimit, owed[receiver][token] and totalOwed[token] grow by leg. claim(tokens[], to), to not zero, pays each min(caller's owed, vault balance) by the same function with no gas limit.\n\nLOSSES. An asset is short when available < managed. Nothing lowers managed automatically. flagDeficit(token), by anyone, records shortfall and time if larger than recorded, or clears the record if not short. recognizeLoss(token), by anyone 7 days or more later, lowers managed by min(recorded, current shortfall) and clears the record. A deposit clears unretired records.\n\nRoles:\n- Owner (two-step transfer, never to the guardian, no renounce): genesis, proposals, cancel; at once: close an asset to deposits, pause and unpause deposits, lower NAV_CAP.\n- Guardian: pause deposits, close an asset, cancel as stated.\n- Nobody can move assets, block redeem or claim, mint outside deposit, change a fee or upgrade.\n\nVIEWS: all assets (config, answer, updatedAt, pool price, managed, short, totalOwed); settings; previewDeposit; previewRedeem; depositStatus(tokens[]): reason and asset at fault; pending proposals.\n\nREVIEW. Accepted, add no mechanism: (1) profit from feed lag under poolDeviation; (2) the owner pairs each token with its true feed and pool; (3) no per-asset limit; (4) moving a thin pool can stop deposits; (5) depositors after a retire share its tokens. MUST ATTACK: redeem with paused, blocked or upgraded tokens (maxAssets assets in any state: under 28,000,000 gas); any way a role or a setting blocks redeem.","blockedReason":null,"createdAt":"2026-10-08T06:54:34.390Z","updatedAt":"2026-10-08T08:49:31.398Z","paidBy":"0x30b57ecf51d19abced7f6f70974e6fbb6f3b9da3","parentJobId":null,"project":{"id":"b8fd4c2b-e0a5-48bd-951f-222b3f3a342c","head":"b8fd4c2b-e0a5-48bd-951f-222b3f3a342c","running":null,"versions":[{"jobId":"b8fd4c2b-e0a5-48bd-951f-222b3f3a342c","workflowId":null,"objective":"Basket Protocol vault: an index vault for Stock Tokens on Robinhood Chain (chain id 4663). Contracts only: no launch token, pool or website. BASK is the vault's own ERC-20 share (18 decimals). Say \"Stock Tokens\", never \"tokenized\".\nToken name: Basket\nToken symbol: BASK\nTotal supply: 0 at deployment, no cap: deposit mints, redeem burns\n\nBUILD RULES\n- Simplest code that satisfies this text: add no feature, role, setting or safeguard.\n- solc 0.8.26, optimizer on, 200 runs, via_ir, evm cancun, bytecode_hash none; custom errors.\n- If BaskVault exceeds 24,000 bytes of runtime, move views into BaskLens(address vault = $contract:BaskVault); never drop a check.\n- Constructors call no other contract.\n- No proxy, delegatecall, selfdestruct, rescue or sweep. User-facing state changes are nonReentrant and emit events.\n\nMANIFEST\n1. BaskVault(address owner_, address guardian_): owner_ = 0x30B57ECf51D19ABcED7F6f70974e6fBb6f3b9Da3, guardian_ = 0x5ed39AF86f2C00ad99913B5d727bD68f2A904B68, written as these literals. Reverts if either is zero or they are equal.\n\nOutside contracts (tests mock exactly these under test/; no fork tests, no vm.env):\n- Token: ERC-20; may have oraclePaused() returns bool.\n- Feed: decimals() <= 18, latestRoundData(); answer = USD per whole token.\n- Pool: Uniswap v3 style token0(), token1(), observe(uint32[]).\n\nASSETS: (token, feed, pool, quoteFeed, minLiquidity, open, retired, hasPause, centre), at most maxAssets. managed[token] is the accounting balance; value never uses balanceOf.\nListing checks (proposal and execution): token not listed; token and feed decimals() <= 18; feed not used by another unretired asset; answer > 0 and under maxAge. At listing: open, centre = answer, hasPause = oraclePaused() returns a bool.\nGenesis: until finalizeGenesis() (once, needs 3+ assets), the owner lists assets with their pools at once; deposits open at finalize.\nAnyone may remove a retired asset with managed and totalOwed 0; its token may then be listed again.\n\nPROPOSALS (owner): list an asset with its pool; new feed (centre = new answer); re-centre on the answer at execution, under maxAge; reopen (cancelled by any later close); retire (closed both times); set an asset's pool, quoteFeed and minLiquidity, or none; resync (managed += balanceOf - managed - totalOwed, if above 0); new guardian; raise NAV_CAP; set feeRecipient (not zero or the vault); change a setting within its bounds. A proposal waits 2 days, then only the owner executes it; it lapses 7 days later; the owner or guardian may cancel it, the guardian not its own replacement. A retired asset is closed for good, voids its pending proposals, then takes only resync, is 0 in NAV and skipped by every deposit check even with managed > 0.\n\nSETTINGS (start; bounds): band 4 (2-100); maxAge 80 hours, noPoolAge 26 hours (1 hour-30 days); freshCount 0 (0-10), freshHours 4 (1-48); hours Mon-Fri from-to UTC (seconds of day; start 0-0 = always open); poolWindow 1800 s (300-86400); poolDeviation 300 bps (50-2000); feedGas, pauseGas 100,000, poolGas 150,000, balanceGas 50,000, payGas 250,000 (each 20,000-500,000); maxAssets 250; directLimit 50. A change must keep maxAssets >= asset count, maxAssets * (balanceGas + 60,000) <= 28,000,000 and directLimit * (balanceGas + payGas + 70,000) <= 28,000,000.\n\nPRICE is valid only if the feed read succeeds (feedGas), answer > 0, centre / band <= answer <= centre * band, updatedAt <= now, now - updatedAt <= maxAge, oraclePaused() returns false if hasPause (pauseGas), and: with a pool, its observe over poolWindow (poolGas; Uniswap OracleLibrary.consult) succeeds with mean liquidity >= minLiquidity and its mean-tick price per whole token in whole quote tokens, times the quoteFeed price (> 0, under maxAge), is within poolDeviation of the feed price in USD; with no pool, now - updatedAt <= noPoolAge. value(amount) = amount * answer * 1e18 / 10^(token decimals + feed decimals), rounded down. USD amounts below are dollars times 1e18.\n\ndeposit(tokens[], amounts[], receiver, minSharesOut, deadline) requires:\n- deposits open, not paused, inside hours; each token listed, open, once, amount > 0, vault balance >= totalOwed[token]; receiver not the vault;\n- freshCount or more unretired assets updated within freshHours;\n- a valid price for each token and every unretired asset with managed > 0; no unretired asset short or unreadable.\nPull the tokens; each vault balance must rise by exactly its amount. NAV = sum of value(managed) before; v = sum of value(amounts).\ngross = v if totalSupply is 0, else v * totalSupply / NAV rounded down (revert if NAV is 0). fee = gross * 50 / 10000, rounded up, minted to feeRecipient; no fee while unset. The receiver gets gross - fee; on the first deposit 1e15 of that goes to address(0xdEaD) instead. It must be > 0 and >= minSharesOut. NAV + v <= NAV_CAP (starts 1,000,000; lowering cancels pending raises; never above 10,000,000,000).\n\nredeem(shares, receiver, minAmountsOut[], deadline), receiver not zero, reads no price, ignores every pause and never reverts because of an asset. fee = shares * 50 / 10000 rounded up, transferred to feeRecipient; no fee while unset. net = shares - fee is burned. Per asset with managed > 0: available = balanceOf(vault) - totalOwed[token], floor 0 (balanceGas static call, 32 bytes copied; else unreadable: available = managed); leg = min(managed, available) * net / totalSupplyBeforeBurn, rounded down; require leg >= minAmountsOut[i] (missing entry = 0); managed -= leg. If at most directLimit assets have managed > 0, each leg is paid to receiver by an external function only the vault may call, given payGas, reverting unless the transfer succeeds, returns nothing or true, and the vault balance falls by exactly leg; if that fails, or above directLimit, owed[receiver][token] and totalOwed[token] grow by leg. claim(tokens[], to), to not zero, pays each min(caller's owed, vault balance) by the same function with no gas limit.\n\nLOSSES. An asset is short when available < managed. Nothing lowers managed automatically. flagDeficit(token), by anyone, records shortfall and time if larger than recorded, or clears the record if not short. recognizeLoss(token), by anyone 7 days or more later, lowers managed by min(recorded, current shortfall) and clears the record. A deposit clears unretired records.\n\nRoles:\n- Owner (two-step transfer, never to the guardian, no renounce): genesis, proposals, cancel; at once: close an asset to deposits, pause and unpause deposits, lower NAV_CAP.\n- Guardian: pause deposits, close an asset, cancel as stated.\n- Nobody can move assets, block redeem or claim, mint outside deposit, change a fee or upgrade.\n\nVIEWS: all assets (config, answer, updatedAt, pool price, managed, short, totalOwed); settings; previewDeposit; previewRedeem; depositStatus(tokens[]): reason and asset at fault; pending proposals.\n\nREVIEW. Accepted, add no mechanism: (1) profit from feed lag under poolDeviation; (2) the owner pairs each token with its true feed and pool; (3) no per-asset limit; (4) moving a thin pool can stop deposits; (5) depositors after a retire share its tokens. MUST ATTACK: redeem with paused, blocked or upgraded tokens (maxAssets assets in any state: under 28,000,000 gas); any way a role or a setting blocks redeem.","baseCommit":"0243d7da4a4337ae8b16bcdf15bb4ead736fd68f","state":"completed","createdAt":"2026-10-08T06:54:34.390Z"}]},"deliver":true,"host":false,"site":null,"launch":{"requested":true,"kind":"evm_contracts","id":"82ce62fe-faaf-4b79-a83f-942e180f7869","status":"live","chainId":4663},"oracleRequestId":null,"delivery":{"repoUrl":"https://github.com/identity-md-launches/launch-1020-basket","pullRequestUrl":"https://github.com/identity-md-launches/launch-1020-basket/pull/1","commit":"0a88bde525aed4557b375cf60ee503d707570ac0","deliveredAt":"2026-10-08T08:49:51.060Z","media":null},"media":null,"nodes":[{"key":"audit_economics","role":"review","state":"accepted","attempt":1,"revisions":0,"judgeRevisions":0,"dependsOn":["build_contract_project"],"allowedPaths":[],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-08T07:58:31.547Z","verdict":null,"seat":{"tokenId":"419","agentId":"52254"},"live":null},{"key":"audit_flow","role":"review","state":"accepted","attempt":1,"revisions":0,"judgeRevisions":0,"dependsOn":["build_contract_project"],"allowedPaths":[],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-08T07:59:28.914Z","verdict":null,"seat":{"tokenId":"452","agentId":"52120"},"live":null},{"key":"audit_judge","role":"review","state":"accepted","attempt":1,"revisions":1,"judgeRevisions":1,"dependsOn":["build_contract_project","write_foundry_tests","manifest","audit_math","audit_permissions","audit_economics","audit_flow"],"allowedPaths":[],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-08T08:49:31.398Z","verdict":null,"seat":{"tokenId":"1565","agentId":"51162"},"live":null},{"key":"audit_math","role":"review","state":"accepted","attempt":1,"revisions":0,"judgeRevisions":0,"dependsOn":["build_contract_project"],"allowedPaths":[],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-08T07:58:19.046Z","verdict":null,"seat":{"tokenId":"467","agentId":"52121"},"live":null},{"key":"audit_permissions","role":"review","state":"accepted","attempt":1,"revisions":0,"judgeRevisions":0,"dependsOn":["build_contract_project"],"allowedPaths":[],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-08T07:58:18.311Z","verdict":null,"seat":{"tokenId":"1876","agentId":"52124"},"live":null},{"key":"build_contract_project","role":"implement","state":"accepted","attempt":1,"revisions":1,"judgeRevisions":1,"dependsOn":[],"allowedPaths":[],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-08T08:29:23.534Z","verdict":{"status":"accepted","profile":"foundry","evaluation":"checks","rejectionCode":null,"detail":"all checks passed","verifierVersion":"0.1.0+ad90ce4c","verifiedTreeHash":"cf0af8992ee539afe1bd7317b370f96feff2dafd","at":"2026-10-08T08:29:23.535Z","failedChecks":[]},"seat":{"tokenId":"1038","agentId":"51453"},"live":null},{"key":"manifest","role":"integrate","state":"accepted","attempt":2,"revisions":1,"judgeRevisions":1,"dependsOn":["build_contract_project"],"allowedPaths":["launch.json"],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-08T08:36:11.318Z","verdict":{"status":"accepted","profile":"foundry","evaluation":"checks","rejectionCode":null,"detail":"all checks passed","verifierVersion":"0.1.0+ad90ce4c","verifiedTreeHash":"edc6c11942bb6db755e5d103ef212a459b9237bb","at":"2026-10-08T08:36:11.319Z","failedChecks":[]},"seat":{"tokenId":"265","agentId":"51220"},"live":null},{"key":"write_foundry_tests","role":"tests","state":"accepted","attempt":1,"revisions":1,"judgeRevisions":1,"dependsOn":["build_contract_project"],"allowedPaths":["test","test/**"],"failureReason":null,"dispatchNote":null,"dispatchNoteAt":null,"updatedAt":"2026-10-08T08:39:01.030Z","verdict":{"status":"accepted","profile":"foundry","evaluation":"checks","rejectionCode":null,"detail":"all checks passed","verifierVersion":"0.1.0+ad90ce4c","verifiedTreeHash":"b69850d19bdf672449b71524545de62f4080c62a","at":"2026-10-08T08:39:01.031Z","failedChecks":[]},"seat":{"tokenId":"104","agentId":"52370"},"live":null}],"reviews":[{"status":"queued","chainId":1,"txHash":null,"blockNumber":null,"sentAt":null,"entries":[{"nodeKey":"audit_economics","agentId":"52254","value":1,"role":"review:submission"},{"nodeKey":"audit_flow","agentId":"52120","value":1,"role":"review:submission"},{"nodeKey":"audit_judge","agentId":"51442","value":1,"role":"review:submission"},{"nodeKey":"audit_judge","agentId":"51162","value":1,"role":"review:submission"},{"nodeKey":"audit_math","agentId":"52121","value":1,"role":"review:submission"},{"nodeKey":"audit_permissions","agentId":"52124","value":1,"role":"review:submission"},{"nodeKey":"build_contract_project","agentId":"51212","value":1,"role":"verification:checks"},{"nodeKey":"build_contract_project","agentId":"51453","value":1,"role":"verification:checks"},{"nodeKey":"manifest","agentId":"51003","value":1,"role":"verification:checks"},{"nodeKey":"manifest","agentId":"51220","value":1,"role":"verification:checks"},{"nodeKey":"write_foundry_tests","agentId":"51436","value":1,"role":"verification:checks"},{"nodeKey":"write_foundry_tests","agentId":"52370","value":1,"role":"verification:checks"}]}]}