ByAUJay
A Developer's Guide to Migrating to Wallet-Connect V2
**Summary:** WalletConnect v1 has officially been shut down, so it's time to make the leap to v2! This transition brings some important updates that can impact your connection reliability, mobile deep linking, session security, and procurement sign-off. In this practical guide, you'll find clear steps on what changes you need to make in your code, what you should be measuring, and more.
Wallet-Connect V2: Migration Guide for Developers
The specific technical headaches we keep seeing
- Ever run into that annoying “invalid namespaces” or “required accounts not satisfied” error during session negotiation? It usually happens right after scanning a QR code, blocking signatures. Chances are it's a CAIP-2/CAIP-10 or namespace mismatch issue in v2. Check out the details here.
- If you’ve noticed mobile flows bouncing users between apps or the browser, it’s likely due to some misconfigured deep links or universal links, especially on iOS. This can lead to users getting stuck and losing conversions. For more info, head over to this link.
- Heads up! The legacy Web3Modal and v1 connectors are officially deprecated. If your team hasn’t transitioned to WalletConnect v2 or Reown AppKit, expect some breaking changes and a whole lot of patchwork solutions. Find out more here.
- Long-running approvals, like custody and multi-sigs, often time out because dapps might not be setting the request expiry correctly, or wallets could be dropping the ball on handling it. Get the scoop here.
- Approvals for smart contract wallets (EIP‑1271) or counterfactual accounts can trip you up unless you specifically manage the verification paths. If you want to dive deeper, check out this EIP.
- There’s a bit of inconsistency in ProjectId and relay configurations across web, RN, Android, and iOS builds, which is causing connect rates to take a hit in production. You can find more about it here.
- Lastly, with the reorg of the ecosystem (WalletConnect → Reown; Web3Modal → AppKit), there are new package names, dashboards, and upgrade paths popping up. It’s crucial to make sure everything lines up across CI/CD and procurement. More details can be found here.
What this costs you:
- Missed quarterly feature deadlines due to QA loops struggling with flaky mobile deep links and namespace errors.
- Red flags in vendor risk during SOC2 audits (like unclear PII/logging and unbounded session TTLs).
- Increases in support tickets and drops in conversions during the “Connect wallet” steps.
Why delaying the migration risks your roadmap
- WalletConnect v1 is officially out of the picture! We're moving on to v2, which is the way forward. The network has shifted toward using permissioned-federated nodes, and there's a plan in place for permissionless participation down the line. Sticking with older connectors or unofficial forks is just asking for trouble; expect things to keep breaking. (walletconnect.com)
- With the v2 Sign API, pairing and sessions are now separate, and it comes with cool new features like Namespaces, explicit expiries, request history, and method-level permissions. Make sure to implement these correctly, or you might run into “connect but not sign” issues when you go live. (specs.walletconnect.com)
- Mobile linking and Link Mode are now key for how native apps can communicate without relying on WebSocket. If you skip this, especially on iOS, you risk bouncing users and hurting completion rates. (docs.walletconnect.network)
- Heads up: Ecosystem SDKs are on the move! Tools like wagmi, RainbowKit, and AppKit are now looking for a v2 ProjectId and updated providers/adapters. Just because it works locally doesn’t mean it’ll hold up after you upgrade the libraries. (2.x.wagmi.sh)
- There's a bit of a risk with GTM: WalletConnect/Reown is handling millions of connections each month, so any small regression--like 1-2% due to poor v2 implementation--can have a big impact on an enterprise level. (businesswire.com)
7Block’s migration methodology (technical, measured, SOC2-ready)
We kick things off with a 3-sprint implementation that brings together code, QA, and procurement seamlessly.
Sprint 0 (1 week): Architecture diff + SOC2 impact
- Let’s break down the current integration points for both web and native platforms to get ready for those v2 packages:
- For Web/EVM, you can use either @walletconnect/ethereum-provider or @walletconnect/universal-provider, or if you prefer, check out wagmi’s walletConnect() connector. You can find more info on it here.
- If you’re dealing with native wallets or dapps, consider using WalletKit/AppKit along with some platform polyfills like @walletconnect/react-native-compat. More details are available here.
- For those who used Web3Modal, it’s time to plan an upgrade to Reown AppKit for web, RN, iOS, and Android. Check out the upgrade details here.
- Now, onto some easy compliance wins:
- Start by defining log redaction - make sure there’s no PII in your event payloads. Also, set up retention windows and SIEM export for your relay and SDK logs.
- Make sure to document the session expiries and how you handle errors in your control narratives, which is crucial for SOC2 CC6.x/CC7.x.
- Finally, double-check your ProjectId/Dashboard access controls along with SSO/MDM for your operational staff.
Sprint 1 (2 weeks): Namespaces, session management, and mobile linking
- Embrace CAIP-2/10 across the board; let's ditch those hardcoded legacy chain IDs.
- Shift to the “optionalNamespaces-first” approach to boost wallet compatibility (progressive authorization) and cut down on rejections: (medium.com)
// Universal Provider (multichain) with optionalNamespaces
import UniversalProvider from "@walletconnect/universal-provider";
const provider = await UniversalProvider.init({
projectId: process.env.WC_PROJECT_ID!, // from WalletConnect/Reown dashboard
metadata: {
name: "Acme App",
description: "Enterprise-grade dapp",
url: "https://example.com",
icons: ["https://example.com/icon.png"],
},
});
await provider.connect({
// Keep requiredNamespaces unset; request all chains in optionalNamespaces
optionalNamespaces: {
eip155: {
methods: [
"eth_sendTransaction",
"eth_signTransaction",
"personal_sign",
"eth_signTypedData",
],
chains: ["eip155:1", "eip155:137", "eip155:10", "eip155:8453"],
events: ["accountsChanged", "chainChanged"],
},
},
});
- Make sure to set and manage session expiry along with request expiry:
- The default session time-to-live is around 7 days; you can renew it using
extendSession. Check it out here: (docs.walletconnect.network). - For request expiry, it should fall between 5 minutes to 7 days; wallets need to send back specific error codes when something expires. More details can be found here: (specs.walletconnect.com).
- The default session time-to-live is around 7 days; you can renew it using
// Extending session (WalletKit API example)
const { acknowledged } = await walletKit.extendSession({ topic });
await acknowledged(); // resolves when dapp acks; if offline, resolves on reconnect
- Here are some mobile deep linking best practices to keep in mind:
- Go for deep links instead of universal links when transitioning from a wallet to an app. Just make sure to limit the redirect metadata to sessions that started with a deep link. Check out the details here.
- When it comes to iOS and Android wallets, make sure to register your wc:// or app scheme. Also, handle any “incomplete” URIs during request redirects and avoid auto-opening during QR-only flows. For more info, visit this link.
- Consider using Link Mode for low-latency requests through universal or app links in native-to-native flows. You can find more about it here.
Sprint 2 (2 weeks): Provider adapters, EIP-1271, and production hardening
- Web DApps with Wagmi:
import { createConfig, http } from "@wagmi/core";
import { mainnet, sepolia } from "@wagmi/core/chains";
import { walletConnect } from "@wagmi/connectors";
export const config = createConfig({
chains: [mainnet, sepolia],
connectors: [
walletConnect({
projectId: process.env.WC_PROJECT_ID!,
// optional: metadata, qrModalOptions, relayUrl
}),
],
transports: {
[mainnet.id]: http(),
[sepolia.id]: http(),
},
});
This connector automatically uses WalletConnect v2. If a user decides to switch to a chain that hasn't been approved yet, they'll need to reconnect to approve it. Make sure to consider the user experience for this error scenario. (2.x.wagmi.sh)
- Swap out Web3Modal for the Reown AppKit, which works across web, React Native, iOS, and Android. Don’t forget to align those adapters (EVM/Solana/Bitcoin) with the fresh dashboard. Check out the details here: (docs.reown.com)
- Introduce EIP‑1271 verification for SIWE/messages and smart wallet orders. Plus, there’s an optional support for ERC‑6492 if you want to dive into counterfactual contracts: (eips.ethereum.org)
// EIP-1271 signature check (ethers v5-style)
import { ethers } from "ethers";
const ERC1271_ABI = ["function isValidSignature(bytes32,bytes) view returns (bytes4)"];
const MAGIC = "0x1626ba7e";
export async function isValid1271Signature(
provider: ethers.providers.Provider,
contractAddress: string,
hash: string,
sig: string
) {
const wallet = new ethers.Contract(contractAddress, ERC1271_ABI, provider);
try {
const res: string = await wallet.isValidSignature(hash, sig);
return res.toLowerCase() === MAGIC.toLowerCase();
} catch {
return false;
}
}
- Strengthen signing methods to minimize risk:
- Go for EIP‑712 typed data instead of eth_sign. This helps cut down on phishing threats and enhances wallet compatibility. (eips.ethereum.org)
1) SignClient with decoupled pairing/session and namespaces
import SignClient from "@walletconnect/sign-client";
const signClient = await SignClient.init({
projectId: process.env.WC_PROJECT_ID!, // WalletConnect/Reown dashboard
metadata: {
name: "Acme App",
description: "Enterprise-grade dapp",
url: "https://example.com",
icons: ["https://example.com/icon.png"],
},
});
// Subscribe to proposal and session events
signClient.on("session_proposal", async (proposal) => {
// Validate proposal; optionally filter methods/chains
});
signClient.on("session_update", ({ topic, params }) => {
// Handle dynamic permission changes
});
// Pair first, then propose session using pairing topic
const { uri, approval } = await signClient.connect({
// keep requiredNamespaces unset, use optionalNamespaces for flexibility
optionalNamespaces: {
eip155: {
chains: ["eip155:1", "eip155:137"],
methods: ["eth_sendTransaction", "personal_sign", "eth_signTypedData"],
events: ["accountsChanged", "chainChanged"],
},
},
});
// Render QR or deep link if needed
if (uri) {
// Show QR or trigger deep link
}
// Wait for wallet approval
const session = await approval();
- Tip: If you’re running into “invalid namespaces” or “required accounts not satisfied” messages, it’s usually due to CAIP-2/10 formatting problems, or you're trying to use method chains that don’t quite support what you need. Make sure to double-check against the spec test cases. (specs.walletconnect.com)
2) Custom QR flow without the built-in modal
import EthereumProvider from "@walletconnect/ethereum-provider";
const provider = await EthereumProvider.init({
projectId: process.env.WC_PROJECT_ID!,
// showQrModal: false, // bring your own modal
});
provider.on("display_uri", (uri: string) => {
// Render your enterprise-branded QR, stream analytics, apply AB tests
});
You can track funnel events with this, like “QR displayed → wallet opened → session settled.” Check it out on npmjs.com!
3) iOS/Android deep linking and Link Mode
- Set up the wc:// scheme or whatever native scheme you’re using; make sure to configure the redirect metadata and don't worry about those “incomplete” URIs that are just there to bring the app to the front for a pending request. (docs.walletconnect.network)
- Turn on Link Mode for smooth native↔native connections. This will help cut down on latency and keep things running even if those WebSocket links are a bit shaky. (docs.walletconnect.network)
// iOS WalletKit example (Link Mode)
let metadata = AppMetadata(
name: "Acme Wallet",
description: "Enterprise wallet",
url: "https://example.com",
icons: [...],
redirect: try! AppMetadata.Redirect(
native: "acmewallet://",
universal: "https://example.com/wc",
linkMode: true
)
)
WalletKit.configure(metadata: metadata)
4) Long-lived approvals (custody/multisig)
- Configure per-request expiry settings (ranging from 5 minutes to 7 days) along with a user experience for handling “expired” responses. Make sure that the relay publish TTL aligns with the expiry time. You can check out the details here.
await signClient.request({
topic: session.topic,
chainId: "eip155:1",
request: { method: "eth_signTypedData", params: [...] },
expiry: Math.floor(Date.now() / 1000) + 3600, // 1 hour
});
Best emerging practices (2026) we recommend adopting now
- Use Namespaces progressively:
- Try to keep
requiredNamespacesunset unless you really need it; instead, ask for broaderoptionalNamespacesand tweak based on what the wallet can handle. (medium.com)
- Try to keep
- Encode all chains/methods with CAIP-2 and events that require session approval; also, make sure to validate accounts in the CAIP-10 format. (specs.walletconnect.com)
- Prefer deep links on mobile; make sure to scope redirect metadata to only deep-link sessions. And hey, don’t just auto-redirect when you scan a QR code. (docs.walletconnect.network)
- Implement Link Mode for native apps, especially if you’re dealing with users who have custody or are in low-connectivity situations. (docs.walletconnect.network)
- Support EIP‑1271 and, if you want, add ERC‑6492 to let SIWE and order signing work smoothly with smart contract wallets and counterfactual accounts. (eips.ethereum.org)
- Raise the floor on signing safety by putting EIP‑712 (eth_signTypedData) at the top of your list instead of eth_sign. (eips.ethereum.org)
- Track session TTLs and create clear “extend” flows for those long-lived sessions; don’t just assume that sessions can last forever. (docs.walletconnect.network)
- For web stacks using wagmi/RainbowKit, make sure to upgrade to versions that default to v2 and pass a ProjectId. And don’t forget to plan your user experience for those unapproved chain switches! (rainbowkit.com)
Prove -- The GTM metrics that matter (and how we instrument them)
What We Measure in Pilots
Here’s a quick rundown of what we look at in our pilot programs:
- Connect Success Rate: We track how often a unique QR or deep link leads to a settled session, breaking it down by device, OS, and wallet. We’re measuring against a big baseline with over 20 million monthly connections, then working to close any gaps we find. Check out more on this BusinessWire article.
- Time to First Signature (TTFS): We’re looking at the P50/P95 metrics, both with and without Link Mode to see how quickly users are able to sign.
- Session Stability: We're looking at how often users are able to resume their sessions after the app goes into the background, plus how many session extension events occur each active week. For more detailed information, head over to the WalletConnect documentation.
- Request Completion vs. Expiry: We keep an eye on how requests perform within a 5 to 7 day window for custody. This includes the percentage of expired requests, average response times, and the distribution of error codes. You can find the specifications in this WalletConnect specs page.
- EIP‑1271 Success vs. Fallback: We focus on the success rates, especially through the ERC‑6492 path, with a particular eye on Account Abstraction (AA) wallets. More details are available on the EIP website.
- Support Ticket Rate: We monitor the number of support tickets per 1,000 sessions for issues like "wallet failed to open,” “invalid namespaces,” and “unapproved chain.”
What Good Looks Like After This Migration:
- Over 97% success rate for connects on top wallets now that we’ve rolled out optionalNamespaces and nailed down mobile linking best practices.
- A solid drop in P95 TTFS for native apps using Link Mode, thanks to less reliance on WebSockets. (docs.walletconnect.network)
- Less than 1% of requests are expiring, which means we’ve nailed the user experience with explicit expiries and wallet UI cues. (specs.walletconnect.com)
- A nice, clean SOC2 narrative: we’ve got bounded session TTLs, least-privilege namespaces, no PII in our logs, plus defined rotation and retention policies.
Procurement and security notes (Enterprise-ready)
- SOC2 alignment: Make sure to keep tabs on session and approval expiries, handle errors properly, and avoid logging any personally identifiable information (PII). Don’t forget to send your logs to the SIEM, set up SSO/MDM for dashboard access, and have those incident runbooks ready for any wallet outages.
- Decentralization roadmap: The WalletConnect Network is expanding with more node operators and is heading towards permissionless participation. This will play a key role in how you assess vendor risk and manage your BCP posture. Check it out here.
- Need private infrastructure? Just a heads up, self-hosted relay for v2 isn’t really supported in general. It’s better to stick with the network roadmap instead of trying to fork old code. For more info, visit GitHub.
Migration checklist (copy/paste for your Jira)
- Let's swap out the outdated Web3Modal packages for Reown AppKit across all platforms. Also, don’t forget to document the new ProjectId provisioning workflow in our runbooks. You can find the details here.
- It's time to switch things up and use wagmi's
walletConnect()or the@walletconnect/*providers along with the projectId. - We should refactor to CAIP-2/CAIP-10 and focus on optionalNamespaces-first sessions. Make sure to add validation tests as per the spec. Check out the specifics here.
- Implement deep links tailored for each platform, and restrict the redirect metadata just for these deep-link flows. Let’s also take a look at Link Mode for our native apps. More on that can be found here.
- We need to incorporate EIP‑1271/ERC‑6492 verification wherever it makes sense. Take a look here for more info.
- Let's enforce request expiries and build out the UX for expiry/extend notifications. We should also keep an eye on those rising expiry rates and set up alerts. You can read up on the requirements here.
- It’d be great to add instrumentation for “display_uri → session settled → first signature,” breaking it down by wallet and device.
- Lastly, we need to update our security documents for SOC2 compliance. Make sure to cover data flow (no PII), log retention, access controls, and incident response planning.
How 7Block Labs helps you ship on time (and prove ROI)
- We take care of all the tough stuff, from code all the way to SOC2 narratives. For implementation, just tap into our awesome web3 development services and blockchain integration.
- We strengthen your signing and contract layer with our top-notch security audit services and high-quality smart contract development.
- Got some DeFi features in your roadmap? No worries! We can work on those simultaneously with our DeFi development services and conduct performance reviews while we wrap up the WalletConnect v2 migration.
- We also create custom KPI dashboards to track connection success, TTFS, expiries, and error codes, keeping your product leadership and procurement teams in the loop.
Appendix: Reference snippets
EIP‑712 Signing (Prefer This Over eth_sign)
Check out EIP-712 for more info!
const typedData = {
domain: { name: "Acme", version: "1", chainId: 1, verifyingContract: "0x..." },
types: { Mail: [{ name: "from", type: "address" }, { name: "contents", type: "string" }] },
primaryType: "Mail",
message: { from: "0xabc...", contents: "hello" },
};
await provider.request({
method: "eth_signTypedData_v4",
params: [address, JSON.stringify(typedData)],
});
Wagmi + WalletConnect Connector (v2) with projectId and metadata
Check out the 2.x.wagmi.sh for all the details on how to set up the Wagmi and WalletConnect connector using project ID and metadata!
import { walletConnect } from "@wagmi/connectors";
const connector = walletConnect({
projectId: process.env.WC_PROJECT_ID!,
metadata: {
name: "Acme App",
description: "Enterprise-grade dapp",
url: "https://example.com",
},
});
RN Polyfills and WalletKit Initialization
Make sure to import your compatibility settings first. For more details, check out the WalletConnect documentation.
import "@walletconnect/react-native-compat";
// then import Reown/WalletConnect SDKs
If you’re looking for a way to get this done with low risk and measurable returns, we can handle the migration and set up the metrics in about 30 to 60 days, all while making sure we’re aligned with SOC2 and procurement requirements.
Schedule your 90-Day Pilot Strategy Call. (walletconnect.com)
Like what you're reading? Let's build together.
Get a free 30-minute consultation with our engineering team.
Related Posts
ByAUJay
Building a Donation-Based Crowdfunding Platform That Gives Tax Receipts
**Summary:** Donation-based crowdfunding that includes tax receipts has become quite the complex puzzle across different regions. You've got to navigate IRS Pub 1771/526 rules, UK Gift Aid declarations, Canada’s CRA receipting, and the new eIDAS/OpenID4VCI wallets--all while keeping everything running smoothly.
ByAUJay
Why 'Full-Lifecycle Advisory' Beats Just Coding
**Summary:** Engineering teams that focus solely on “writing Solidity” often find themselves caught off guard by shifts in protocols, the need for composable security, and the procurement hurdles that are now impacting real ROI. Our full-lifecycle advisory service bridges the gap by connecting EIP-7702 smart accounts, modular decentralized applications (DA), and ZK-based compliance solutions.
ByAUJay
Why Your Project Could Really Use a 'Protocol Economist
Summary: A lot of Web3 teams are missing a crucial player: the “protocol economist.” And you can really see the impact--value slips away through MEV routing, token incentives that are all out of whack, and those sneaky changes to wallets after Pectra that end up messing with the unit economics. In this playbook, we’ll explore what a protocol economist can do to tackle these issues head-on.

