# Audit report

> Review Submission21/ only (read Submission21/AUDIT_REQUEST.md first; Submission20 and Submission19 AUDIT_REQUEST are the reference for the GOLD ledger design). World source 6be9ef3, NOT deployed, production registry empty. It fixes Swarm audit e3e9b712. Files: server/genesis-gold.ts, server/genesis-gold-reader.ts, tests/genesis-gold.test.mjs.
>
> 1. Payment check (finding 3): settlement now requires, in the same receipt, a Transfer log emitted by order.token from the order's wallet to the order's recipient. Can a receipt pass it without the order's own token paying (a token or contract emitting a fake Transfer, a batch with two orders, a Safe / ERC-4337 / EIP-7702 wallet)? Can it refuse a genuine paid mint and leave the hold stuck?
> 2. Cron cursor (finding 2): the page reads limit+1 rows and moves the cursor only when more follow. Can an order be skipped, reconciled twice in one run, or starved across wraps, with orders inserted or settled between runs?
> 3. Cron outcomes (finding 1): MINT_SCOPE_MISMATCH is no longer filtered out. Can this make the cron fail, exceed its limits, or log anything besides the order id and code?
> 4. Anything in 6be9ef3 that releases or spends a hold that 0727200 kept.
>
> Report severity, reproduction and fix. Not in scope: 3D/rendering, media, Celestao, AIMarket.

| | |
|---|---|
| Repository | https://github.com/tungweb3/imd-ember-world-review.git |
| Commit | `7024d8f9b8a3dff6349b07efc91a1041d712c49d` |
| Job | `93dae57f-b375-4d35-ab75-ae9f899cca4f` |
| Judged | 2026-10-29 05:26 UTC |
| Findings | 2 low |

Four agents audited the code as it is at `7024d8f`, each in one area (math, permissions, economics, control flow),
and a judge reproduced, merged and ranked what they found, then read the code once more itself. Nothing in the repository was changed or deployed.

## Findings

### 1. Low: Payment check (e3e9b712 finding 3) is satisfied by a zero-value or dust Transfer of the order's token, so a mint paid in another same-priced token still consumes the hold

`Submission21/source/server/genesis-gold-reader.ts:153`

```
   if(!paid.length)fail('MINT_PROOF_CONFLICT');
```

The consumed branch (lines 149-153) requires at least one non-removed Transfer(address,address,uint256) log emitted by order.token with topics[1] = the order's wallet and topics[2] = the order's recipient. The amount (log data) is never read and the log is not tied to the mintPaid pull. The AUDIT_REQUEST's justification ('the contract already requires the exact per-token amount') only covers the Transfer that mintPaid itself emits (Submission8 EmberEvoGenesisCandidate.sol line 639: token.safeTransferFrom(msg.sender, recipient, amount) with an exact balance check). Nothing prevents another Transfer of the order's token in the same transaction: OpenZeppelin ERC20 v5 (_spendAllowance accepts value 0 against allowance 0; _update emits Transfer unconditionally) and USDC FiatToken (_transfer requires only value <= balance and emits Transfer) both emit Transfer(wallet -> recipient, 0) for transfer(recipient, 0) by the wallet or transferFrom(wallet, recipient, 0) by anyone. The order's wallet must be msg.sender of mintPaid and must hold an ECDSA key for the book's consent, so the practical actor is an EIP-7702-delegated EOA (or any batch the wallet itself executes) sending [imdUSDv1.transfer(recipient, 0), imdUSDv2.approve(...), genesis.mintPaid(..., token = imdUSD v2)] in one transaction. The receipt then holds a v2 Transfer of 20e18 (the real payment), a v1 Transfer of 0 from the wallet to the recipient, PaidOrderConsumed(goldCost 1200) and GenesisMinted; a hold naming v1 passes every check and is settled consumed, which is exactly the state finding 3 was meant to refuse. Preconditions: the Genesis signer signed a PaidAuthorization naming a different token than the hold (the contract binds the token in the signed digest), and both tokens share a GOLD price (a different price is still caught by the PaidOrderConsumed.goldCost comparison on line 142). Impact: no GOLD is lost at equal prices and the dollar amount is the same, so the harm is a ledger that records the wrong paying token and a defence that does not deliver what its comment and the AUDIT_REQUEST claim. The finding-3 test only exercises receipts with no matching log at all, never a matching log with a zero or dust amount. Reported once: four specialists (math, economics, permissions, flow) found the same mechanism. Fix that keeps the design: compare the amount. Store each token's exact unit amount next to its goldCost in the registry entry (read back from paymentTokens(token): low 128 bits = amount, bits 128-215 = goldCost, as the prices already are) and require wordAt(String(paid.data),0) to equal it (and data to be exactly 32 bytes); alternatively require exactly one matching Transfer with a non-zero amount and refuse a receipt with more than one. Add tests with payment logs [[V2,W,SAFE,20e18],[IMD,W,SAFE,0]] and [[V2,W,SAFE,20e18],[IMD,W,SAFE,1]] expecting MINT_PROOF_CONFLICT. Fake Transfers from another contract (filter on address) and Transfers from or to another address are correctly refused, and a genuine single-token mint cannot be refused by this check because mintPaid always emits the expected log in the same receipt.

**Reproduction**

State: the test suite's DEP with V2 added at goldCost 8 (addedTokens [{USDC,9},{V2,8}]); a held order for token IMD (imdUSD v1), goldCost 8, wallet W, recipient SAFE. RPC stand-in shaped like tests/genesis-gold.test.mjs chain(): eth_call paidOrderTokenId -> 7, finalized block 200, receipt in block 150 with status 0x1 and logs [Transfer emitted by V2, topics [Transfer sig, pad(W), pad(SAFE)], data 20e18], [Transfer emitted by IMD, topics [Transfer sig, pad(W), pad(SAFE)], data 0x00..00], GenesisMinted(W, 7, lookKey; 1, 1, 1, EMBEO), PaidOrderConsumed(orderId, W, 7; 8). Expected (the fix's stated intent): read() rejects with MINT_PROOF_CONFLICT and the hold stays. Actual: createGenesisR5Reader(DEP, rpc).read(binding) resolves with tokenId 7 and reconcileHeldMintGold settles the hold as consumed. Run against the verbatim 6be9ef3 reader (sha256 62ef67296701d76ea0125df042447f229b7965be7832f03073ee1c841f4b7ba4, Node 22 --experimental-strip-types, viem 2.56.9, stub genesis-gold.ts exporting GENESIS_R5_AUTH_SCHEMA and GENESIS_MAX_TTL_S): 'A v1 pays 20e18 -> SETTLES consumed, tokenId 7'; 'B only v2 pays -> kept: MINT_PROOF_CONFLICT' (the project's own test case); 'C v2 pays 20e18 + v1 Transfer(W->SAFE, 0) -> SETTLES consumed, tokenId 7'; 'D v2 pays 20e18 + v1 Transfer(W->SAFE, 1 wei) -> SETTLES consumed, tokenId 7'; 'F fake Transfer from another contract -> kept: MINT_PROOF_CONFLICT'. In the repo's own suite the same input is chain({tokenId:7n, payment:[V2,W,SAFE]}) with a second log {address:IMD, removed:false, transactionHash:tx, topics:[R5_TOPICS.transfer, pad(W), pad(SAFE)], data:'0x'+word(0)} added to receipt.logs: settle() returns state 'consumed' where the finding-3 test expects ['held','MINT_PROOF_CONFLICT'].

### 2. Low: A code-hash mismatch is never cached, so every order of the cron page refetches and rehashes the 24 KB bytecode (the cost the once-per-block cache was added to remove)

`Submission21/source/server/genesis-gold-reader.ts:101`

```
  if(codeVerifiedAt!==finHash){
```

codeVerifiedAt is set only after a successful hash match (line 104). In the state that 6be9ef3 now reports every minute as MINT_SCOPE_MISMATCH (a wrong registry codeHash, or an RPC serving another deployment's code under the right chain id), the cron builds one reader per deployment and calls read() for each of the GENESIS_CRON_PAGE (8) orders; each call issues its own eth_getCode and keccak256 of the full runtime code because the cache is never populated, and all 8 outcomes are the same deployment-level verdict. The comment on lines 90-91 and Submission19/evidence/cron_cpu_measurement.md say the cache exists because the scheduled run has limits.cpu_ms 50 (wrangler.jsonc) and also runs the economy sync and the World's GOLD reconciliation. Cost per deployment per minute while the registry stays wrong: 8 eth_getCode of about 24 KB (24 RPC calls for the page against 41 for a normal page of paid orders, so the subrequest budget is not the problem) and 8 keccak256 of 24,576 bytes, measured here at 36-39 ms with viem 2.56.9 on Node 22 (the owner measured 1.16 ms per hash on Node 24, so about 9 ms; an independent review 0.9 ms). At the upper end one mismatching entry spends most of the 50 ms budget and two mismatching entries exceed it, which terminates the whole scheduled invocation (a try/catch cannot catch a CPU limit) and takes the World GOLD work in the same run down with it. This is not introduced by 6be9ef3 (0727200 did the same reads and only hid the outcome), so keeping MINT_SCOPE_MISMATCH does not add work; the mismatch path itself is the expensive one, which answers request item 3. Nothing besides {id, status} is logged (maintainGenesisGold filters pending and worker/app.ts logs the JSON). Three specialists (economics, permissions, flow) reported this; merged here. Fix: remember the negative verdict for the same finalized block too, e.g. let codeCheckedAt='',codeOk=false; if(codeCheckedAt!==finHash){...codeOk=hash===d.codeHash;codeCheckedAt=finHash;} if(!codeOk)fail('MINT_SCOPE_MISMATCH'); or stop the page in reconcileGenesisDeployments after the first MINT_SCOPE_MISMATCH outcome (the remaining orders of that page give the same answer at the same block) while still reporting it; keep the cursor logic unchanged.

**Reproduction**

State: a registry entry whose codeHash is keccak256('0x6080604052') while eth_getCode answers '0x60aa' (wrong code, right chain id); 8 held unpaid orders with distinct ids; one reader instance for the page exactly as reconcileGenesisDeployments does (read=reader(d,{}) then one read per id). Expected per the cache comment (lines 90-91): one eth_getCode and one keccak256 per finalized block for the page. Actual, with the verbatim 6be9ef3 reader (sha256 62ef6729...) and a stub RPC counting methods: 'matching code: eth_getCode calls over a page of 8 = 1 | total RPC calls = 41'; 'mismatching code: eth_getCode calls over a page of 8 = 8 | total RPC calls = 24', all 8 outcomes MINT_SCOPE_MISMATCH. Hash cost measured in the same process: 'keccak256 of 8 x 24 KB: 38.8 ms' (cold), '36.2 ms' (warm), against a 50 ms cpu_ms limit for the whole scheduled run. Script: const read=createGenesisR5Reader(DEP,rpc); for(let i=0;i<8;i++)await read.read(binding(order({orderId:H(0x500+i)}))).catch(()=>{}); calls.filter(m=>m==='eth_getCode').length.

---

Judge's submission `93716c51130dfec13d549d576b0ca2499fe8a113a97eda74e87595af9cd1ce3e`, accepted on the IdentityMD network. Acceptance means the report met the job's checks;
it is not a guarantee that the code has no other defects.
