Writing8 Common Mistakes in Web3 Wallet Signing and Approval Flows — LinkIT
5 min readweb3, wallet-signing, token-approvals, security, dapp-ux

8 Common Mistakes in Web3 Wallet Signing and Approval Flows

Review approval scope, message signing, replay protection, chain validation, and transaction states in Web3 wallet flows.

Wallet signing and approval flows should explain what a user is authorizing and distinguish cancellation, submission, and confirmed execution. Review approval scope, replay protection, chain selection, and pending states as separate parts of the flow.

Mistake 1: Requesting Unlimited Token Approvals

The approve function on ERC-20 tokens accepts an amount. Some dApp integrations request uint256.max — the largest possible integer — which grants the approved contract unlimited spending authority over that token balance, now and in the future.

From a UX standpoint, this is a single confirm. From a security standpoint, it means one compromised contract can drain every token in the user's wallet for which they have given unlimited approval.

Fix: Request the exact amount the current transaction requires, or use EIP-2612 permit signatures that expire and are scoped to a single transaction. If unlimited approval is genuinely needed for your product design, explain it explicitly to the user before they sign.

Mistake 2: Using eth_sign for Message Signing

eth_sign signs arbitrary bytes prefixed with \x19Ethereum Signed Message:\n. It is the oldest signing method and the most dangerous — a signed arbitrary-bytes message can potentially be repurposed as a valid transaction on certain networks. Most wallets now show a warning when eth_sign is requested, which causes user anxiety and drop-off.

Fix: Use eth_signTypedData_v4 (EIP-712) for all structured data signing. Typed data shows the user a human-readable breakdown of every field they are signing, including domain, contract, and purpose. It is also cryptographically safer because the domain separator prevents replay across contracts and chains.

Mistake 3: No Replay Protection on Off-Chain Signatures

If your product uses off-chain signatures to authorize on-chain actions — common in meta-transactions, permit flows, and SIWE auth — and those signatures do not include a nonce, chain ID, and verifying contract address, they can be replayed.

A replay attack reuses a valid signature from a past action to authorize a different action. In the worst case, a signature that authorized a small action can be submitted again to authorize the same action repeatedly.

Fix: Every signature payload must include at minimum: a nonce unique to that user + action combination, the chain ID, and the address of the contract that will verify the signature. EIP-712 domain separators enforce this when implemented correctly.

Mistake 4: Showing the Wallet Modal Without Context

Many dApps trigger the wallet's confirmation modal immediately when the user clicks an action button, with no intermediate explanation. The user sees a hex-encoded payload, a gas estimate in gwei, and a countdown timer — and has no idea what they are authorizing.

Without context, users may be unable to tell whether the request matches the action they intended.

Fix: Add an intent confirmation step before triggering any wallet modal. Show in plain language: what action is being taken, what is being authorized, what it costs, and what changes as a result. Users should understand the requested action before the wallet asks them to confirm it.

Mistake 5: Not Handling User Rejection

When a user rejects a signature or transaction in their wallet, the wallet SDK throws an error with a code like 4001 or ACTION_REJECTED. An integration that swallows this error silently (leaving the UI in a loading state) or displays a generic unhandled error message gives the user no useful next step.

Fix: Catch rejection errors specifically and treat them as expected user behavior, not exceptions. Show a calm, non-alarming message like "You cancelled the transaction — tap Confirm to try again." Reset the UI to the pre-signing state cleanly.

Mistake 6: Not Validating Chain Before Signing

Token approval on the wrong chain is meaningless but wastes gas. A signature intended for Ethereum mainnet but submitted on a forked testnet with the same contract address can have unintended effects. Many dApps check the chain at connection time but not at transaction time.

Fix: Validate chainId immediately before constructing any transaction or signature payload, not only at the start of the session. If the chain has changed, prompt the user to switch before proceeding.

Mistake 7: Treating Transaction Hash as Transaction Success

When sendTransaction resolves with a hash, many developers immediately show a success screen. A transaction hash means the transaction was received by the node — not that it was included in a block or that it succeeded.

Transactions can fail on-chain for many reasons: insufficient gas, reverted logic, slippage exceeded. Showing success before receipt confirmation creates a poor experience when the user later discovers the action did not complete.

Fix: Wait for the transaction receipt using waitForTransactionReceipt (or equivalent) and check that receipt.status === 1 before triggering any success state. Show a pending state in the interim.

Mistake 8: Exposing the Full Approval Flow to New Users Without Explanation

The ERC-20 approve-then-transact pattern requires two separate wallet confirmations for first-time interactions. Developers who are used to this find it obvious. Users who have never used your product have no mental model for why they are being asked to confirm twice.

Common responses from new users: thinking the first confirmation was the final one, closing the app, or assuming something went wrong after the first transaction succeeded.

Fix: Show a two-step progress indicator that explains both steps before the user begins: "Step 1 of 2: Approve USDC (one-time setup)" and "Step 2 of 2: Complete transaction." Consider migrating to EIP-2612 permit signatures where the token supports it, which collapses two transactions into one signed message plus one transaction.


Discuss wallet signing and approval flows with LinkIT.