Skip to content

feat(client): gasless transactions for POLY_PROXY (Magic Link proxy wallet)#8

Merged
cesarenaldi merged 1 commit into
mainfrom
claude/dreamy-tharp-141b15
Apr 23, 2026
Merged

feat(client): gasless transactions for POLY_PROXY (Magic Link proxy wallet)#8
cesarenaldi merged 1 commit into
mainfrom
claude/dreamy-tharp-141b15

Conversation

@cesarenaldi
Copy link
Copy Markdown
Collaborator

@cesarenaldi cesarenaldi commented Apr 22, 2026

Summary

  • Extends prepareGaslessTransaction to support WalletType.POLY_PROXY alongside the existing Safe flow
  • Adds a new SignGaslessHashRequest workflow step for raw-hash personal signing
  • Updates all three wallet adapters (viem, ethers-v5, privy) to handle the new signing step
  • Adds relayHub address to EnvironmentConfig (production: 0xD216153c06E857cD7f72665E0aF1d7D82172F494)
  • Adds encodeProxyCall() in abis.ts to encode the proxy factory proxy(...) ABI call

Why the proxy flow is different from Safe

Safe uses EIP-712 typed-data over a SafeTx struct. Proxy uses the original GSN relay hub signing protocol:

keccak256("rlx:" ++ from ++ to ++ data ++ relayerFee ++ gasPrice ++ gasLimit ++ nonce ++ relayHub ++ relay)

…then personal-sign (EIP-191) over that 32-byte hash. The calldata targets the proxy factory (proxyFactory address), not the wallet, and the relayer request type is PROXY not SAFE.

The implementation was verified against:

  • relayer-v2/packages/api/pkg/signatures/hash.go — hash construction
  • relayer-v2/packages/api/pkg/signatures/verify.go — personal-sign semantics
  • relayer-v2/packages/api/pkg/validate/validate.goisValidProxySigParams requirements
  • builder-relayer-client/src/builder/proxy.ts — client-side reference

Files changed

File What
environments.ts Add relayHub: EvmAddress to config type + production value
abis.ts Add encodeProxyCall()
workflow.ts Add SignGaslessHashRequest
viem.ts / ethers-v5.ts / privy.ts Handle signGaslessHash in completeWith
account.ts Export deriveProxyWalletAddress as @internal
actions/gasless.ts Proxy branch in prepareGaslessTransaction; buildProxyTransactionHash
testing.ts deriveProxyAddress test helper
gasless.test.ts / clients.test.ts Proxy wallet classification + workflow shape tests

Invariants preserved

  • Safe flow is unchanged
  • prepareGaslessWallet remains Safe-only
  • EOA accounts still rejected by the invariant guard
  • Public API surface is minimal — no new exported action functions

Test plan

  • pnpm lint — passes (biome, no fixes needed)
  • pnpm typecheck — passes (zero tsc errors)
  • gasless.test.ts proxy suite — verifies signGaslessHash shape and rejects EOA
  • clients.test.ts proxy classification — verifies walletType === POLY_PROXY for a deterministic proxy wallet

Residual risks / follow-ups

  • Gas limit is hardcoded to 10_000_000 (reference client fallback). Gas estimation would require an RPC provider in the workflow — deferred.
  • gasPrice: '0' and relay: ZERO_ADDRESS are acceptable per backend validation but carry no real relay signal.

🤖 Generated with Claude Code


Note

Medium Risk
Touches transaction signing and relayer submission logic (hash construction, signature payloads, and environment addresses), where small mismatches can break execution. Changes are scoped to gasless workflows and covered by updated tests.

Overview
Adds gasless transaction support for WalletType.POLY_PROXY alongside the existing Safe flow by building a relayer-compatible proxy transaction hash ("rlx:" preimage) and submitting RelayerTransactionType.PROXY executions targeting the proxy factory.

Refactors the gasless signing step so signGaslessMessage now carries a raw 32-byte hex digest (Safe EIP-712 digests are precomputed; proxy uses the new hash builder), updates viem/ethers-v5/privy adapters accordingly, and extends environment/config + ABI helpers (relayHub address and encodeProxyCall). Tests are updated/added to cover proxy wallet classification and the new workflow shape.

Reviewed by Cursor Bugbot for commit a1bde68. Bugbot is set up for automated code reviews on this repo. Configure here.

@cesarenaldi cesarenaldi force-pushed the claude/dreamy-tharp-141b15 branch 2 times, most recently from 9a052f6 to 9c372e5 Compare April 23, 2026 08:02
Comment thread packages/client/src/actions/gasless.test.ts
@cesarenaldi cesarenaldi force-pushed the claude/dreamy-tharp-141b15 branch from 9c372e5 to 71c68e4 Compare April 23, 2026 08:33
Comment thread packages/client/src/actions/gasless.ts Outdated
@cesarenaldi cesarenaldi force-pushed the claude/dreamy-tharp-141b15 branch from 71c68e4 to 449dad2 Compare April 23, 2026 09:03
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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 449dad2. Configure here.

Comment thread packages/client/src/actions/gasless.test.ts
@cesarenaldi cesarenaldi force-pushed the claude/dreamy-tharp-141b15 branch 5 times, most recently from e7c11de to f1705f8 Compare April 23, 2026 10:28
Extends prepareGaslessTransaction to handle Magic Link proxy wallets
(WalletType.POLY_PROXY) alongside the existing Safe-backed flow.

The proxy signing contract differs from Safe's EIP-712 approach: it
uses the GSN relay hub protocol — keccak256("rlx:" ++ from ++ to ++
data ++ relayerFee ++ gasPrice ++ gasLimit ++ nonce ++ relayHub ++
relay) — signed with personal_sign semantics. The calldata targets
the proxy factory's proxy() function rather than the wallet directly.

Changes:
- environments.ts: add relayHub address to EnvironmentConfig (production: 0xD216153c06E857cD7f72665E0aF1d7D82172F494)
- abis.ts: add encodeProxyCall() for proxy((uint8,address,uint256,bytes)[]) ABI encoding
- workflow.ts: add SignGaslessHashRequest for raw 32-byte hash signing
- viem.ts / ethers-v5.ts / privy.ts: handle signGaslessHash in completeWith
- account.ts: export deriveProxyWalletAddress as @internal
- actions/gasless.ts: add proxy branch in prepareGaslessTransaction; add buildProxyTransactionHash and helpers
- testing.ts: add deriveProxyAddress helper
- gasless.test.ts / clients.test.ts: add proxy wallet classification and workflow tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@cesarenaldi cesarenaldi force-pushed the claude/dreamy-tharp-141b15 branch from f1705f8 to a1bde68 Compare April 23, 2026 11:01
@cesarenaldi cesarenaldi merged commit 13dd95a into main Apr 23, 2026
6 of 7 checks passed
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