[#88] Replace recoverMessageAddress with verifyMessage#96
Conversation
…allet support Uses publicClient.verifyMessage() which handles both EOA and EIP-1271 contract wallet signatures, enabling Smart contract wallet users (Safe, Argent, etc.) to submit ratings. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Summary
The signature verification change is directionally correct, but this PR introduces a request-shape regression that makes rating submissions fail from the current UI.
Findings
- [high] The API now requires
address, but the existing rating client does not send it, so every browser submission will hitMissing address, signature, or message.- File:
src/app/api/ratings/route.ts:68 - Suggestion: Either include
addressin the POST body fromsrc/components/RatingWidget.tsx:120, or preserve backward-compatible verification behavior in the API while updating the client in the same PR.
- File:
Decision
Requesting changes because the current diff breaks the only in-repo caller for /api/ratings, so issue #88 is not fully fixed yet.
project7-interns
left a comment
There was a problem hiding this comment.
T2b Review: APPROVE
Change Summary
Single file changed: src/app/api/ratings/route.ts (+12 / -7). Replaces recoverMessageAddress() with publicClient.verifyMessage() to support EIP-1271 contract wallet signatures, and adds a caller-supplied address field to the request body.
Review Against Criteria
1. Correctly replaces recoverMessageAddress with publicClient.verifyMessage?
Yes. The recoverMessageAddress import is removed. publicClient.verifyMessage({ address, message, signature }) is used correctly, handling both EOA (ecrecover) and EIP-1271 (on-chain isValidSignature). The publicClient is a proper viem PublicClient connected to Base/Base Sepolia.
2. Contract addresses imported (not hardcoded)?
No hardcoded addresses in this diff. Token address comes from the database; rater address from the request body. Clean.
3. Security issues?
None blocking. The address is now caller-supplied, but verifyMessage still cryptographically proves the claimed address produced the signature (EOA) or that the contract confirms it (EIP-1271). The signed message format still binds to a specific action, preventing replay.
4. Minimal and focused?
Yes. One file, surgical change. Branch naming and PR body follow conventions.
Nits (non-blocking)
| # | Severity | Description |
|---|---|---|
| 1 | Nit | No isAddress() validation on the caller-supplied address before passing to verifyMessage. Fails safely (catch block returns 400) but gives an opaque "Failed to verify signature" error instead of "Invalid address format". Nice-to-have for DX. |
LGTM — correct EIP-1271 migration, security model preserved, minimal diff.
Fixes client-side regression: the caller must now send the wallet address so the API can use verifyMessage for EIP-1271 support. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
T2b Review — APPROVE
Correct migration from recoverMessageAddress() to publicClient.verifyMessage() — supports EIP-1271 contract wallet signatures (Safe, Argent, etc.).
- No hardcoded addresses
- Minimal, focused change (+12/-7, single file)
- No security issues with the verification logic
One non-blocking nit: no isAddress() pre-validation on the caller-supplied address field — fails safely but gives an opaque error. Fine to address later.
LGTM ✓
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: APPROVE
Summary
The PR now correctly switches rating signature verification to publicClient.verifyMessage() and updates the existing client to send the claimed address, so the EIP-1271 fix is complete without breaking the current submission flow.
Findings
- No blocking findings.
Decision
Approving because the change now matches issue #88, stays minimal, and the refreshed lint/typecheck run passed.
Summary
Fixes #88
recoverMessageAddress()withpublicClient.verifyMessage()insrc/app/api/ratings/route.tsverifyMessagehandles both EOA and EIP-1271 contract wallet signatures, enabling Smart contract wallet users (Safe, Argent, etc.) to submit ratingsaddressfield to request body so the caller provides their address for verificationChecklist
recoverMessageAddresswithverifyMessagenpm run lintpassesnpm run typecheckpassesTest plan
🤖 Generated with Claude Code