Skip to content

fix(server): use unwrapped signature for root EOA merchant key#1054

Open
gakonst wants to merge 1 commit intomainfrom
joshie/fix-merchant-fee-signature
Open

fix(server): use unwrapped signature for root EOA merchant key#1054
gakonst wants to merge 1 commit intomainfrom
joshie/fix-merchant-fee-signature

Conversation

@gakonst
Copy link
Copy Markdown
Contributor

@gakonst gakonst commented Feb 15, 2026

Summary

Fix Route.merchant fee signature validation failure when the merchant uses their root EOA private key directly.

Closes ithacaxyz/relay#1516

Details

  • Route.merchant always signed feePayerDigest with wrap: true (default), producing a 98-byte wrapped signature
  • On-chain, IthacaAccount.unwrapAndValidateSignature handles wrapped sigs via getKey(keyHash) lookup — which fails if the key is not explicitly registered on the account
  • When a merchant passes their root EOA private key to Route.merchant (the common case for simple setups), the root EOA is implicitly valid via the 65-byte ecrecover path but is typically not registered as a named key
  • Now, when the signing key is secp256k1 and its derived address matches the merchant address (i.e. it is the root EOA), Key.sign uses wrap: false to produce a 65-byte raw ECDSA signature
  • Non-root secp256k1 admin keys and P256 keys still use wrap: true

Areas Touched

  • porto Library (src/server)

Prompted by: joshie

Route.merchant always signed feePayerDigest with wrap:true, producing a
98-byte wrapped signature. On-chain, IthacaAccount validates wrapped
signatures via keyHash lookup, which fails when the merchant's root EOA
key is not registered as a named key on their account.

Now, when the signing key is secp256k1 and its derived address matches
the merchant address (i.e. it is the root EOA), sign with wrap:false to
produce a 65-byte raw ECDSA signature that goes through the ecrecover
path — always valid for the root EOA without key registration.

Closes ithacaxyz/relay#1516

Amp-Thread-ID: https://ampcode.com/threads/T-019c6121-e174-7506-8cd1-ca4204b31df0
Co-authored-by: Amp <amp@ampcode.com>
@gakonst gakonst requested a review from jxom February 15, 2026 12:12
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Feb 15, 2026

⚠️ No Changeset found

Latest commit: 09f47be

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 15, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dialog.porto Error Error Feb 15, 2026 0:13am
docs.porto Error Error Feb 15, 2026 0:13am
id.porto Error Error Feb 15, 2026 0:13am
playground.porto Error Error Feb 15, 2026 0:13am
wagmi.porto Error Error Feb 15, 2026 0:13am
3 Skipped Deployments
Project Deployment Actions Updated (UTC)
interop.porto Ignored Ignored Preview Feb 15, 2026 0:13am
porto-ui Ignored Ignored Preview Feb 15, 2026 0:13am
proxy.porto Ignored Ignored Preview Feb 15, 2026 0:13am

Request Review

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Feb 15, 2026

Open in StackBlitz

npm i https://pkg.pr.new/porto@1054

commit: 09f47be

@github-actions
Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size Loading time (3g) Running time (snapdragon) Total time
import { Porto } from 'porto' 63.69 KB (0%) 1.3 s (0%) 27 ms (+100.36% 🔺) 1.4 s
import { porto } from 'porto/wagmi/Connector' 17.92 KB (0%) 359 ms (0%) 71 ms (+311.59% 🔺) 429 ms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fee sponsorship via merchant server seems broken

2 participants