Skip to content

feat(evm): EIP-2612 permit signing helper (Node SDK + Rust CLI)#187

Open
teyrebaz33 wants to merge 1 commit intoopen-wallet-standard:mainfrom
teyrebaz33:feat/eip-2612-permit-helper
Open

feat(evm): EIP-2612 permit signing helper (Node SDK + Rust CLI)#187
teyrebaz33 wants to merge 1 commit intoopen-wallet-standard:mainfrom
teyrebaz33:feat/eip-2612-permit-helper

Conversation

@teyrebaz33
Copy link
Copy Markdown

Summary

Adds a purpose-built signPermit helper that eliminates the boilerplate currently required to sign EIP-2612 permits via OWS. Closes #132

What's included

Node SDK — signPermit()

import { signPermit } from '@open-wallet-standard/core/evm/permit';

const sig = await signPermit(ownerAddress, 'eip155:8453', {
  token:    '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base
  spender:  '0xYourProtocol',
  value:    '1000000',
  deadline: Math.floor(Date.now() / 1000) + 3600,
}, owsSignTypedData);
// → { v, r, s, signature, typedData }

CLI — ows sign permit

ows sign permit   --wallet my-wallet   --chain  eip155:8453   --token  0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913   --spender 0xYourProtocol   --value  1000000   --deadline 1800000000   --json

Domain resolution

The hard part of EIP-2612 is getting the domain separator right. signPermit resolves it in three stages:

  1. eip712Domain() (EIP-5267) — self-describing; works for USDC v2.2+, OZ ERC20Permit 5.x
  2. Well-known override table — USDC ("2"), DAI ("1"), Base USDT
  3. name() + default version "1" — generic fallback

Tokens that omit version from their domain are handled correctly — the EIP712Domain type array is built dynamically.

Tests

✔ returns correct v / r / s from mock signature
✔ builds correct EIP-712 typed data structure
✔ resolves domain via eip712Domain()
✔ falls back to name() + override when eip712Domain() reverts
✔ auto-fetches nonce when not supplied
✔ uses supplied nonce without RPC call
✔ omits version field in EIP712Domain when token has no version
✔ chainId matches CAIP-2 chain segment
✔ throws when token name is empty and no override exists
✔ throws when RPC is unreachable
✔ DAI fallback domain version is 1
✔ Ethereum USDC fallback domain version is 2

12 passed, 0 failed — fully offline, no network required

Files changed

File Description
bindings/node/src/evm/permit.mjs SDK function
bindings/node/__test__/permit.spec.mjs 12 offline tests
docs/examples/eip2612-permit.md Usage guide
ows/crates/ows-lib/src/ops.rs sign_permit() Rust implementation
ows/crates/ows-lib/src/types.rs PermitParams, PermitSignResult types
ows/crates/ows-lib/Cargo.toml Added ureq for sync HTTP
ows/crates/ows-cli/src/commands/sign_permit.rs CLI command handler
ows/crates/ows-cli/src/commands/mod.rs Module registration
ows/crates/ows-cli/src/main.rs Permit subcommand + handler

Checklist

  • Node SDK signPermit()
  • CLI ows sign permit
  • 12 offline tests, all passing
  • Rust workspace builds without errors
  • Documentation
  • Follows existing code patterns (sign_message, sign_transaction)

Adds signPermit() to the Node SDK and `ows sign permit` to the CLI.
Closes open-wallet-standard#132

Node SDK (bindings/node/src/evm/permit.mjs):
- signPermit(ownerAddress, chainId, params, signTypedData) function
- Auto-fetches permit nonce from chain when not supplied
- Domain resolution: eip712Domain() (EIP-5267) → well-known override
  table (USDC v2, DAI v1) → name() + version fallback
- Handles tokens that omit version from their EIP712Domain
- No new runtime dependencies (raw fetch + minimal ABI decode)

Rust CLI (ows sign permit):
- New sign_permit() in ows-lib with synchronous ureq HTTP calls
- PermitParams and PermitSignResult types in ows-lib
- ows sign permit --wallet --chain --token --spender --value --deadline
  [--nonce] [--rpc-url] [--json] [--index]
- Follows existing sign_message / sign_transaction command patterns

Tests (bindings/node/__test__/permit.spec.mjs):
- 12 offline tests, all passing
- Covers: v/r/s splitting, typed data structure, eip712Domain() path,
  fallback path, nonce auto-fetch, nonce skip, version omission,
  chainId, error cases, known token versions

Docs (docs/examples/eip2612-permit.md):
- SDK and CLI usage examples
- Domain resolution strategy explained
- Supported chains and tokens table
@teyrebaz33 teyrebaz33 requested a review from njdawn as a code owner April 4, 2026 13:24
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 4, 2026

@teyrebaz33 is attempting to deploy a commit to the MoonPay Team on Vercel.

A member of the Team first needs to authorize it.

@socket-security
Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedcargo/​ureq@​2.12.19710093100100

View full report

@socket-security
Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
License policy violation: cargo webpki-roots under CDLA-Permissive-2.0

License: CDLA-Permissive-2.0 - the applicable license policy does not allow this license (4) (webpki-roots-0.26.11/Cargo.toml)

License: CDLA-Permissive-2.0 - the applicable license policy does not allow this license (4) (webpki-roots-0.26.11/LICENSE)

From: ?cargo/ureq@2.12.1cargo/webpki-roots@0.26.11

ℹ Read more on: This package | This alert | What is a license policy violation?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Find a package that does not violate your license policy or adjust your policy to allow this package's license.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore cargo/webpki-roots@0.26.11. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

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.

RFC: EIP-2612 permit signing helper

1 participant