The simple WalletConnect Pay flow signs an EIP-3009Documentation Index
Fetch the complete documentation index at: https://docs.walletconnect.com/llms.txt
Use this file to discover all available pages before exploring further.
transferWithAuthorization typed-data payload — the gasless transfer used by USDC and similar stablecoins. USDT does not implement EIP-3009, so WalletConnect Pay routes it through the Permit2 contract instead.
The first time a user pays a given token on a given chain, the wallet must approve Permit2 on-chain. Subsequent payments on the same token only require the typed-data signature.
The two-action flow
When an option needs a Permit2 approval,getRequiredPaymentActions returns two actions — in the order they must execute:
eth_sendTransaction— ERC-20approve(Permit2, amount)on the token contracteth_signTypedData_v4— Permit2 typed-data payload authorizing the transfer
Detecting an approval-required option
Inspect the action list for aneth_sendTransaction entry. In standalone SDK flows, this means option.actions; in WalletKit flows, this means the actions returned by getRequiredPaymentActions. If one is present, the option is a Permit2 flow and your wallet should prepare for an on-chain step.
- Kotlin
- Swift
- TypeScript
- Dart
Showing the approval gas estimate
The approve tx costs native gas (e.g. POL on Polygon, ETH on mainnet) — separate from the token amount the user is paying. Estimate it and show the user the expected fee before they confirm so they aren’t surprised by a wallet prompt for a one-time on-chain cost. This can live wherever your wallet collects user intent — a review screen, a confirmation sheet, or inline on the option row.- Kotlin
- Swift
- TypeScript
- Dart
Executing the actions in order
Because the Permit2 typed data signs against the token allowance the approve tx grants, the approve must be mined before you sign.- Submit
eth_sendTransaction(action 1) and wait for the receipt. - Parse the typed data from
eth_signTypedData_v4(action 2) and sign it. - Push both results into
signatures[]in the order the actions were returned. - Call
confirmPayment(signatures).
- Kotlin
- Swift
- TypeScript
- Dart
EIP-712 library quirks. EIP-712 signing libraries disagree on whether
types.EIP712Domain must be present in the payload. The Permit2 typed data returned by WalletConnect Pay omits it.- Libraries that require
EIP712Domain(e.g.eth_sig_util_pluson Flutter, some Android libraries): synthesize anEIP712Domainentry intypesfrom the fields actually present indomainbefore signing. - Libraries that reject
EIP712Domain(e.g. ethers v5_signTypedData): strip it fromtypesbefore signing. - Yttrium’s
signTypedDatais currently hardcoded to ERC-3009 (from/to/value/validAfter/validBefore/nonce) and rejects Permit2. Wallets using Yttrium need a generic EIP-712 hasher — seeEIP712TypedData.swiftfor a reference implementation.
Loader UX
The two-action flow has two distinct user-visible steps that can each take several seconds:- The approve tx is broadcast and you wait for the receipt.
- The user is prompted to sign the Permit2 typed data.
Sample wallets
The four reference wallets below all just shipped this two-action flow and are good starting points to copy from.React Native
wallets/rn_cli_wallet — see PaymentUtil.ts, PaymentTransactionUtil.ts, PaymentStore.ts.Kotlin
sample/wallet — see PaymentUtil.kt, PaymentTransactionUtil.kt, PaymentViewModel.kt.Swift
Example/WalletApp — see PaymentUtil.swift, PayTransactionService.swift, PayPresenter.swift, EIP712TypedData.swift.Flutter
packages/reown_walletkit/example — see evm_service.dart, wcp_payment_details.dart, wcp_confirming_payment.dart.