From b15fc72c4a67a7a0ec6d3bbb4febc19ea727b6f1 Mon Sep 17 00:00:00 2001 From: RBKunnela Date: Sat, 23 May 2026 01:19:44 +0300 Subject: [PATCH] fix(micropayment-engine): correct EIP-55 checksum + bytes32 nonce (Story 15.1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two related blockers preventing the signing path from working with viem 2.49+ strict validation: 1. verifyingContract literal had wrong EIP-55 checksum (4 letter case-swaps). Canonical address (verified via viem getAddress()): 0x50b0f7224fFC5F4F7685DbcE1B8b7e7B8b8A4A23 2. generateNonce() returned un-prefixed 64-char hex but the call site cast it as `0x${string}` — a type-system lie. viem rejected at hashTypedData with BytesSizeMismatchError ("expected bytes32, got bytes64"). Fixed at the source: nonce is now genuinely 0x-prefixed and the return type is honest. Verified locally with an ad-hoc smoke script (not committed) — signTypedData returns a 65-byte (132-char hex) signature and a 32-byte (66-char hex) nonce after these two fixes. Test file in Story 15 (tests/micropayment-engine.test.ts) will exercise this path properly post-merge. Audit pass (Task 15.1.3) found no other hardcoded addresses in this file and the remaining `as` casts on hex types are pre-existing patterns out of scope for this hotfix. Closes Task #18 Co-Authored-By: Claude Opus 4.7 --- src/micropayment-engine.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/micropayment-engine.ts b/src/micropayment-engine.ts index b22af6a..c6969a0 100644 --- a/src/micropayment-engine.ts +++ b/src/micropayment-engine.ts @@ -229,7 +229,7 @@ export class MicropaymentEngine { name: 'PayBot', version: '1', chainId: 8453, - verifyingContract: '0x50b0f7224fFc5f4f7685DbcE1B8b7E7B8B8A4A23' as Address, + verifyingContract: '0x50b0f7224fFC5F4F7685DbcE1B8b7e7B8b8A4A23' as Address, }; const nonce = this.generateNonce() as `0x${string}`; @@ -338,11 +338,12 @@ export class MicropaymentEngine { return `${whole}${fraction}`.replace(/^0+/, '') || '0'; } - private generateNonce(): string { + private generateNonce(): `0x${string}` { const buf = new Uint8Array(32); webcrypto.getRandomValues(buf); - return Array.from(buf) + const hex = Array.from(buf) .map(b => b.toString(16).padStart(2, '0')) .join(''); + return `0x${hex}`; } } \ No newline at end of file