{"assessments":[],"deployments":[],"fuzz":[],"identity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"interpretation":"Records acceptance and evidence. Neither completion nor an AI assessment establishes correctness, safety, or independent review.","jobId":"35ad518a-570e-40a7-8d9c-f8536f18440e","kind":"shape:chain","nodes":[{"acceptedSubmissionHash":"10adf7148531b5ac5f47bb824588e633d3a77b3f33594626baa1bede90b13d2f","dependsOn":[],"execution":{"mustProduce":["dist/index.html"],"network":true,"profile":"none","requires":["network"],"skillHash":"d85feeeba61710fcde95b6484d4ed21af1a49b2b609a1b0ea33f16d5a47ec9ca","skillId":"import-site","tools":[]},"key":"import_site","kind":"code","role":"implement","skillHash":"d85feeeba61710fcde95b6484d4ed21af1a49b2b609a1b0ea33f16d5a47ec9ca","skillId":"import-site","state":"accepted"},{"acceptedSubmissionHash":"34bab4f991c5d642b8e15ba5ebb36c79715888acbf75eda13e1efc9b08e780f5","dependsOn":["import_site"],"execution":{"network":false,"profile":"foundry","requires":[],"skillHash":"8189a3059fc9bb774ad7dcee66b87f32e25d781025f0e9f82a4c75182fe0ef19","skillId":"site-content-check","tools":[]},"key":"site_content_check","kind":"code","role":"review","skillHash":"8189a3059fc9bb774ad7dcee66b87f32e25d781025f0e9f82a4c75182fe0ef19","skillId":"site-content-check","state":"accepted"}],"objective":"PepesFamily is a static website (HTML/JS, no backend) for a fair-launch token launchpad on Robinhood Chain and Ethereum: it lists tokens, launches and trades them on Uniswap v4, and lets holders claim IMD rewards, all through the visitor’s own browser wallet.","parentJobId":null,"planHash":"fda706df52c4e6e088799df23103a0b7e417b1ae79b3a702622888b635568b40","previousHash":"0000000000000000000000000000000000000000000000000000000000000000","projectId":"35ad518a-570e-40a7-8d9c-f8536f18440e","publication":{"commit":null,"deliveredAt":null,"repoUrl":null},"receiptIdentity":{"adapter":"0xde152afb7db5373f34876e1499fbd893a82dd336","chainId":1,"collection":"0x0000ec93127baa929e58e97dd0095a2bfb38ec1d","registry":"0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"},"registry":"0xb6d0a187b050fa5bb0b87033a203f37becf4a775","research":[],"schema":"identitymd-work-v1","signals":[{"agentId":"51300","feedbackHash":"e7cbbda9c7837ff620fcd44ac000d4a85fd6edf5324d5c490df77be7f1c97349","nodeKey":"import_site","submissionHash":"10adf7148531b5ac5f47bb824588e633d3a77b3f33594626baa1bede90b13d2f","tag1":"verification:structural","tag2":"acceptance-v2","value":1},{"agentId":"51030","feedbackHash":"cc109ffb31ba7a71d76be99bde07d430d64684949b3d91839c0b17465cdea291","nodeKey":"site_content_check","submissionHash":"34bab4f991c5d642b8e15ba5ebb36c79715888acbf75eda13e1efc9b08e780f5","tag1":"review:submission","tag2":"acceptance-v2","value":1}],"site":null,"snapshotHash":"51949b0bcdf32b81e6530f80bfecb73eea1f3ff5e49a1a62e08b77b562cb3921","state":"completed","submissions":[{"artifacts":[],"attempt":1,"bundleHash":"d292abe20c4b31731369297613629d64acb5c3feb797b3da58118b15097a0ec8","device":"05778e691c371384","findings":[],"hash":"10adf7148531b5ac5f47bb824588e633d3a77b3f33594626baa1bede90b13d2f","nodeId":"5df75749-bfd2-4cd8-b5e9-6a82f2e85e34","outcome":"completed","summary":"Built the site with **npm** using `npm run build`. The build wrote [dist/index.html](/root/.identitymd/work/35ad518a-570e-40a7-8d9c-f8536f18440e/5df75749-bfd2-4cd8-b5e9-6a82f2e85e34/dist/index.html) and its assets to `dist/`.\n\nThe export matches the configured copy from `web/`, with the API folder and `vercel.json` excluded. Its total size is about 780 KiB. The source uses root-relative links, so hosting beneath an IPFS path prefix may affect those links.","treeHash":"a543814eda9f6800ccb17cd86ad47a648eb39c40","usage":{"cachedInputTokens":91520,"inputTokens":23001,"model":"gpt-6-sol","outputTokens":2304,"runtime":"codex","turns":3,"wallClockMs":43089}},{"artifacts":[],"attempt":1,"bundleHash":null,"device":"06486f6fefb50394","findings":[{"citation":"resolved","description":"The token page disables Claim whenever withdrawableDividendOf minus expired rewards is zero, without considering pendingHolderFees. Fees from third-party routers are still held by the launchpad until claim() flushes and distributes them, so a holder can have a payable claim while this view returns zero. The Rewards page also omits both per-token Claim and Claim all for this state (lines 1723-1731, 1745, 1758 and 1770); the NFT claim uses the same zero-balance gate. Holders cannot collect through the normal claim UI until somebody separately triggers distribution. PadToken.claim() at contracts/src/PadToken.sol:290 flushes first, and the existing test_claimFlushesPendingFees test confirms this succeeds. This advisory UI defect is also present in web/index.html.","line":2839,"path":"dist/index.html","reproduction":"Launch a default holder-reward token, buy it as Alice, then make a second buy as Bob through an external Uniswap v4 router that does not call launchpad.flush. Before anyone flushes, Alice holds tokens, withdrawableDividendOf(Alice) is zero and pendingHolderFees(token) is positive. Connect Alice and open /#/t/<token>: Claim is disabled. Open /#/rewards: no Claim or Claim all control is offered. Expected: Alice can invoke claim(), which distributes the pending fees and pays her share. Actual: the page prevents it. Confirmed in Chromium using an RPC-equivalent fixture with a 100-token holder balance, zero withdrawable dividends and 1 IMD pending holder fees; separately ran the existing Foundry test_claimFlushesPendingFees successfully.","severity":"medium","snippet":"    $(\"#claim\").disabled = ready === 0n;","title":"Claim controls prevent holders from collecting pending router fees"},{"citation":"resolved","description":"loadPosition() continues after asynchronous balance/reward reads without checking whether its token page is still active. Its global #pos selector and setSide() then update whichever token page is currently displayed, including the buy/sell label, balances, amount label, quick-amount buttons and quote. The newer page's #trade.onclick still closes over the newer token address. A slow response from token A can therefore label the button and quote as token A while clicking sends a trade for token B. renderToken and these asynchronous updates need a navigation-generation or equivalent guard. The identical issue exists in web/index.html. This is an advisory transaction-UI race, not evidence of a concealed drainer.","line":2837,"path":"dist/index.html","reproduction":"Use two listed tokens, ALPHA at 0x1111111111111111111111111111111111111111 and BETA at 0x3333333333333333333333333333333333333333 in a local read fixture, and connect a holder. Delay ALPHA.balanceOf(holder), open ALPHA's page, then navigate to BETA and let BETA's position load. Now release ALPHA's delayed balance response. Expected: BETA's controls remain unchanged. Actual in Chromium using the unchanged rendering/onclick functions: the heading remains Beta but the button becomes BUY $ALPHA and the position says Holding 100 $ALPHA. Enter 1 IMD and click that button: the captured router.buy call targets 0x3333333333333333333333333333333333333333 with amountIn=1000000000000000000 (BETA). The same timing is possible with a slow RPC while switching between real token pages.","severity":"medium","snippet":"    $(\"#pos\").innerHTML = `Holding <b>${fmt(b)}</b> $${esc(info.symbol)} (${share}% of supply)<br/>\n      Claimable: <b>${fmt(ready, 6)} ${Q}</b> · Claimed so far: ${fmt(w, 6)} ${Q}${lostR === null ? \" (may include expired rewards)\" : lostR > 0n ? ` · ${fmt(lostR, 6)} ${Q} expired earlier` : \"\"}${ex ? `<br/>${ex.left === null ? \"\" : ex.left > 0 ? `⏳ Claim within <b>${dur(ex.left)}</b> to keep all of it.` : \"⏳ Your older rewards are expiring: claim now to keep the rest.\"}${ex.expired > 0n ? ` ${fmt(ex.expired, 6)} ${Q} already expired (goes to the $PEPES buyback).` : \"\"}` : \"\"}`;\n    $(\"#claim\").disabled = ready === 0n;\n    setSide(tradeSide);","title":"Late position responses relabel another token's trade controls"},{"citation":"resolved","description":"shareCard() and tokenShareCard() return data:image/png URLs, but this fetch is blocked by the page's connect-src policy at line 6, which permits HTTPS/WSS and local RPC endpoints but not data:. Consequently Copy image reports that the browser blocked copying and the native Share button is never enabled, even when the browser supports those features. The same code is in web/index.html. This is an advisory functionality defect, not a hosting blocker.","line":1863,"path":"dist/index.html","reproduction":"In a browser supporting ClipboardItem, open /#/rewards/<address> for a wallet with earned rewards, wait for its share card, and press Copy image. Expected: the PNG is copied. Actual: fetch(data:image/png;base64,...) is refused by CSP and the page displays \"Your browser blocked copying: use Download image instead\". On browsers supporting navigator.canShare({files}), Share also stays hidden because the same fetch fails first. Confirmed in Chromium against the unchanged dist/index.html: fetching a canvas.toDataURL(\"image/png\") throws TypeError: Failed to fetch under this policy.","severity":"low","snippet":"    const blob = () => fetch(url).then((x) => x.blob());","title":"The content security policy blocks copying and sharing reward cards"},{"citation":"resolved","description":"The home page advertises 3% of every trade paid to holders, and the Rewards introduction at line 1694 applies that claim across every PepesFamily token. New v5 launches can instead select Creator-backed (1% holders) or Deflationary (0% holders), as defined at lines 477-480 and sent to launchWithSplit at line 2679. The selected split is correctly disclosed on the launch and individual token pages, so this is stale global financial copy rather than substantiated intentional deception. Update the general reward claims to reflect the per-token split. web/index.html has the same wording.","line":1224,"path":"dist/index.html","reproduction":"Open /#/create on a live v5 launchpad and select Deflationary: the displayed split is 1% protocol and 3% burned, with zero holder rewards. Then open /#/ and /#/rewards: the home banner still promises 3% of every trade paid to holders and Rewards says it applies across every token. Expected: these statements explain that holder rewards depend on the token's immutable split. Confirmed the rendered strings in Chromium with feeSplit returning [0,0,300]; the existing Foundry test_split_deflationaryBurnsAndEveryoneCanExit passes and asserts pendingHolderFees(token)==0 after buys.","severity":"low","snippet":"      <p>1B fixed supply · liquidity locked forever · paired with $IMD · 3% of every trade paid to holders in IMD</p>","title":"Global reward copy promises 3% to holders even for zero-holder-fee tokens"}],"hash":"34bab4f991c5d642b8e15ba5ebb36c79715888acbf75eda13e1efc9b08e780f5","nodeId":"2e04b80e-472a-43a2-9dd9-3ff31ae59bd6","outcome":"completed","summary":"Saved [`.imd-findings.json`](/home/imd-worker/.identitymd/work/35ad518a-570e-40a7-8d9c-f8536f18440e/2e04b80e-472a-43a2-9dd9-3ff31ae59bd6/.imd-findings.json): **2 medium and 2 low findings; no critical or high findings**.\n\nRead both hosted pages, all inline scripts/styles, and bundled assets. Confirmed findings with Chromium fixtures and two passing Foundry checks. Validated every quoted snippet. Only the required report was created.","treeHash":null,"usage":{"cachedInputTokens":4146432,"inputTokens":191979,"model":"gpt-6-astra","outputTokens":20656,"runtime":"codex","turns":7,"wallClockMs":670327}}],"verification":[{"checks":[],"detail":"paths and tree verified; no suite was run for this kind of work","evaluation":"structural","profile":"none","status":"accepted","submissionHash":"10adf7148531b5ac5f47bb824588e633d3a77b3f33594626baa1bede90b13d2f","verifiedTreeHash":"a543814eda9f6800ccb17cd86ad47a648eb39c40","verifierVersion":"0.1.0+fdeb4d4a"}]}