Skip to content

feat: add Ethereum preimage signing for Merkle claims#2185

Merged
broody merged 4 commits intomainfrom
feat/ethereum-preimage-signing
Nov 10, 2025
Merged

feat: add Ethereum preimage signing for Merkle claims#2185
broody merged 4 commits intomainfrom
feat/ethereum-preimage-signing

Conversation

@broody
Copy link
Copy Markdown
Contributor

@broody broody commented Nov 6, 2025

Overview

This PR adds support for signing Merkle claim messages using an Ethereum preimage directly, as an alternative to using external wallet connectors. This enables users to claim tokens using a preimage when external wallets are not available or preferred.

Changes

New Files

  • packages/keychain/src/utils/eth-signing.ts: New utility module providing Ethereum message signing functions using viem's privateKeyToAccount
    • signMessageWithPrivateKey: Signs messages with a private key
    • getAddressFromPrivateKey: Derives Ethereum address from private key

Modified Components

claim.tsx

  • Extended to support 'preimage' wallet type with a generic wallet representation
  • Consumes ethereumPreimage from purchase context
  • Displays appropriate wallet info for preimage mode

purchase.tsx

  • Added ethereumPreimage state management to the purchase context
  • Added setEthereumPreimage setter function
  • Exposes state and setter through context API

merkle-claim.ts

  • Enhanced useMerkleClaim hook to:
    • Accept ethereumPreimage parameter
    • Support 'preimage' type alongside external wallet types
    • Use preimage signing when available, falling back to external wallet signing
  • Updated dependencies array to include ethereumPreimage

index.ts

  • Exported new signing utilities from eth-signing module

Technical Details

Signing Flow

  1. When ethereumPreimage is provided, the hook uses direct private key signing
  2. When ethereumPreimage is not provided, it falls back to external wallet signature requests
  3. Signature format remains consistent across both methods (EIP-191 compliant)

Security Considerations

  • Private key handling is isolated to the signing utility
  • Keys are passed through secure context state management
  • Signature verification happens on-chain

Testing

  • ✅ Tested preimage signing flow for Merkle claims
  • ✅ Verified fallback to external wallet signing when preimage is not provided
  • ✅ Confirmed proper signature format and parsing
  • ✅ All linting and formatting checks pass

Note

Adds optional Ethereum preimage-based signing to the starterpack claim flow, wiring from examples UI through controller to keychain with new signing utilities.

  • Claim flow enhancements:
    • controller.openStarterPack now accepts optional preimage and forwards it to keychain navigation (packages/controller/src/controller.ts, packages/keychain/src/utils/connection/index.ts, packages/controller/src/types.ts).
    • Auto-redirect claim when preimage query param is present on starterpack page (packages/keychain/src/components/purchasenew/starterpack/starterpack.tsx).
    • Example UI allows entering optional preimage and passes it through (examples/next/src/components/Starterpack.tsx).
  • Signing & wallet handling:
    • useMerkleClaim supports type: "preimage" and signs EVM messages with the provided preimage, falling back to external wallets; blocks preimage for Starknet claims (packages/keychain/src/hooks/merkle-claim.ts).
    • Adds "preimage" pseudo-wallet to getWallet for display logic (packages/keychain/src/components/purchasenew/wallet/config.ts).
    • New utilities for Ethereum signing and address derivation: signMessageWithPrivateKey, getAddressFromPrivateKey (packages/keychain/src/utils/eth-signing.ts, exported via packages/keychain/src/utils/index.ts).
  • Claim UI updates:
    • Claim page derives address from preimage, handles errors, adjusts header/empty states, and hides wallet chip for preimage; updates footer actions (packages/keychain/src/components/purchasenew/claim/claim.tsx).
    • Pending screen button label changed to Claiming in claim flow (packages/keychain/src/components/purchasenew/pending.tsx).

Written by Cursor Bugbot for commit 9d57c28. This will update automatically on new commits. Configure here.

- Add eth-signing utility for signing messages with Ethereum private keys
- Extend useMerkleClaim hook to support preimage signing mode
- Add ethereumPreimage state to purchase context
- Update claim component to handle 'preimage' wallet type
- Export new signing utilities from utils/index.ts

This enables users to claim tokens using an Ethereum preimage when
external wallets are not available or preferred.
@vercel
Copy link
Copy Markdown

vercel Bot commented Nov 6, 2025

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

Project Deployment Preview Updated (UTC)
controller-example-next Ready Ready Preview Nov 10, 2025 11:24pm
controller-example-next-compat Ready Ready Preview Nov 10, 2025 11:24pm
keychain Ready Ready Preview Nov 10, 2025 11:24pm
keychain-storybook Ready Ready Preview Nov 10, 2025 11:24pm

Comment thread packages/keychain/src/hooks/merkle-claim.ts
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Accidental Config Removal Detected

The preset: "ponziland" configuration was removed from the controller connector setup. This change is unrelated to the PR's stated purpose of adding Ethereum preimage signing and appears to be accidentally committed.

examples/next/src/components/providers/StarknetProvider.tsx#L198-L208

signupOptions: [
"google",
"webauthn",
"discord",
"walletconnect",
"metamask",
"rabby",
"password",
],
slot: "arcade-pistols",
namespace: "pistols",

Fix in Cursor Fix in Web


Comment thread packages/keychain/src/hooks/merkle-claim.ts Outdated
Comment thread packages/keychain/src/components/purchasenew/starterpack/starterpack.tsx Outdated
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Unintended Configuration Change

The removal of preset: "ponziland" from the ControllerConnector configuration appears unrelated to the PR's stated purpose of adding Ethereum preimage signing for Merkle claims. This change is not mentioned in the PR description and seems to be accidentally included in this commit.

examples/next/src/components/providers/StarknetProvider.tsx#L208-L209

namespace: "pistols",
// By default, preset policies take precedence over manually provided policies

Fix in Cursor Fix in Web


Comment thread packages/keychain/src/components/purchasenew/claim/claim.tsx
@broody broody force-pushed the feat/ethereum-preimage-signing branch from 8138d55 to 2c246eb Compare November 10, 2025 22:07
@codecov
Copy link
Copy Markdown

codecov Bot commented Nov 10, 2025

Codecov Report

❌ Patch coverage is 6.06061% with 124 lines in your changes missing coverage. Please review.
✅ Project coverage is 21.51%. Comparing base (69988e7) to head (ff777eb).
⚠️ Report is 57 commits behind head on main.

Files with missing lines Patch % Lines
...eychain/src/components/purchasenew/claim/claim.tsx 0.00% 51 Missing ⚠️
...components/purchasenew/starterpack/starterpack.tsx 0.00% 22 Missing ⚠️
packages/keychain/src/utils/eth-signing.ts 28.00% 18 Missing ⚠️
packages/keychain/src/hooks/merkle-claim.ts 0.00% 17 Missing ⚠️
...ychain/src/components/purchasenew/wallet/config.ts 0.00% 10 Missing ⚠️
packages/keychain/src/utils/connection/index.ts 0.00% 6 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2185      +/-   ##
==========================================
+ Coverage   20.19%   21.51%   +1.31%     
==========================================
  Files         259      273      +14     
  Lines       24230    27146    +2916     
  Branches      668      842     +174     
==========================================
+ Hits         4894     5840     +946     
- Misses      19328    21295    +1967     
- Partials        8       11       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@broody broody force-pushed the feat/ethereum-preimage-signing branch from 141828d to e97833a Compare November 10, 2025 22:20
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Preset Configuration: Unintended Change Impact

The removal of preset: "ponziland" appears to be an unintended change unrelated to the Ethereum preimage signing feature. This configuration was likely used for testing and its removal could affect the controller's preset behavior in the example application.

examples/next/src/components/providers/StarknetProvider.tsx#L207-L208

slot: "arcade-pistols",
namespace: "pistols",

Fix in Cursor Fix in Web


Close
</Button>
)}
</>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Claim Button Allows Actions Despite Errors

The claim button is not disabled when there's an error state, allowing users to attempt claiming even when address derivation from the preimage failed. The button only checks isClaimed and isCheckingClaimed but ignores the error state, which can be set when getAddressFromPrivateKey throws an exception. This allows invalid claim attempts to proceed, causing downstream failures instead of preventing the action upfront.

Fix in Cursor Fix in Web

openStarterPack:
() => (starterpackId: string | number, preimage?: string) => {
navigate(
`/purchase/starterpack/${starterpackId}${preimage ? `?preimage=${preimage}` : ""}`,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Sensitive Keys Leaked Through URLs

The Ethereum private key (preimage) is passed as a URL query parameter, exposing it in browser history, server logs, and potentially referrer headers. Private keys should never be transmitted through URLs as this creates a significant security vulnerability where the key could be leaked through various channels.

Fix in Cursor Fix in Web

@broody broody force-pushed the feat/ethereum-preimage-signing branch from f8536c0 to 9d57c28 Compare November 10, 2025 23:28
@broody broody merged commit bfb176e into main Nov 10, 2025
19 of 20 checks passed
@broody broody deleted the feat/ethereum-preimage-signing branch November 10, 2025 23:29
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Nov 10, 2025

Claude finished @broody's task —— View job


Analyzing PR changes and updating documentation

Task: Update documentation for Ethereum preimage signing feature

  • Analyze PR changes to understand new functionality
  • Review existing documentation structure
  • Identify documentation files that need updates
  • Create or update documentation as needed
  • Verify documentation accuracy

Analysis Summary

The PR adds Ethereum preimage signing functionality for Merkle claims. Key changes:

New Feature:

  • Added optional preimage parameter to controller.openStarterPack()
  • New signing utilities in eth-signing.ts for private key-based message signing
  • Enhanced useMerkleClaim hook to support preimage signing alongside external wallets
  • Support for EVM message signing using private keys directly (no external wallet required)

Documentation Updates Made:

  1. starter-packs.md:

    • Updated openStarterPack API signature to include optional preimage parameter
    • Added example usage for preimage signing
    • Enhanced Merkle Drop Claims section to explain both signing methods (external wallet vs preimage)
    • Updated claim flow documentation to include preimage signing option
  2. configuration.md:

    • Updated openStarterPack method signature and description
    • Added example for Merkle claims with preimage signing

Documentation Changes Summary

The documentation now accurately reflects the new Ethereum preimage signing functionality, providing clear guidance on:

  • When and how to use preimage signing for Merkle claims
  • API changes to openStarterPack method
  • Alternative signing flows for EVM-based claims
  • Security and usage considerations

All user-facing API changes have been documented, maintaining consistency with the existing documentation style.


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.

1 participant