From c4ca11de079f79010b25c0ac950503f7fa6a5063 Mon Sep 17 00:00:00 2001 From: jakubuid Date: Wed, 23 Apr 2025 09:44:29 +0300 Subject: [PATCH 1/3] wallet kit web instalation page improvements --- walletkit/web/installation.mdx | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/walletkit/web/installation.mdx b/walletkit/web/installation.mdx index 41fe22d68..b27875b29 100644 --- a/walletkit/web/installation.mdx +++ b/walletkit/web/installation.mdx @@ -1,8 +1,18 @@ --- title: Installation +description: How to install and set up WalletKit SDK in your web application --- -Install WalletKit using npm or yarn. +# Installing WalletKit + +## Prerequisites + +- Node.js 14.0 or higher +- A JavaScript/TypeScript project (React, Vue, Angular, or vanilla JS) + +## Installation Steps + +1. Install WalletKit and its dependencies using your preferred package manager: ```bash npm @@ -18,6 +28,20 @@ bun add @reown/walletkit @walletconnect/utils @walletconnect/core pnpm add @reown/walletkit @walletconnect/utils @walletconnect/core ``` + +2. After installation, you'll need to configure WalletKit in your application. See the next section for setup instructions. + +## Verification + +To verify your installation was successful, you can check your `package.json` file to confirm the dependencies were added correctly. + ## Next Steps -Now that you've installed WalletKit, you're ready to start integrating it. The next section will walk you through the process of setting up your project to use the SDK. +Now that you've installed WalletKit, you're ready to start integrating it into your project. The following section will guide you through the configuration process and basic usage examples. + +## Troubleshooting + +If you encounter any installation issues: +- Ensure your Node.js version is up to date +- Try clearing your package manager's cache +- Check for any peer dependency requirements From 1663cc22d8e39704d6d7470f63bf0ae43d60bb22 Mon Sep 17 00:00:00 2001 From: jakubuid Date: Wed, 23 Apr 2025 10:31:08 +0300 Subject: [PATCH 2/3] Improve WalletKit usage documentation for better readability and AI-friendliness --- walletkit/web/usage.mdx | 514 +++++++++++++++------------------------- 1 file changed, 188 insertions(+), 326 deletions(-) diff --git a/walletkit/web/usage.mdx b/walletkit/web/usage.mdx index cf2acac05..b8ebc85bf 100644 --- a/walletkit/web/usage.mdx +++ b/walletkit/web/usage.mdx @@ -1,83 +1,94 @@ --- title: Usage +description: How to use WalletKit to connect wallets with decentralized applications --- import CloudBanner from "/snippets/cloud-banner.mdx"; -This section provides instructions on how to initialize the WalletKit client, approve sessions with supported namespaces, and respond to session requests, enabling easy integration of Web3 wallets with dapps through a simple and intuitive interface. +# WalletKit Usage Guide -## Cloud Configuration +This guide walks you through using WalletKit to integrate Web3 wallets with decentralized applications (dapps). -Create a new project on Reown Cloud at https://cloud.reown.com and obtain a new project ID. +## Prerequisites - +- Completed the [installation](/walletkit/web/installation) steps +- Basic knowledge of JavaScript/TypeScript +- Understanding of Web3 wallet concepts + +## Setup Process + +### 1. Cloud Configuration -## Initialization +First, create a project on Reown Cloud to get a project ID: -Create a new instance from Core and initialize it with a projectId created from installation. Next, create WalletKit instance by calling init on walletKit. Passing in the options object containing metadata about the app and an optional relay URL. +1. Go to [https://cloud.reown.com](https://cloud.reown.com) +2. Create a new project +3. Copy your project ID + + - -Make sure you initialize `walletKit` globally and use the same instance for all your sessions. For React-based apps, you can initialize it in the root component and export it to use in other components. - +### 2. Initialize WalletKit + +Create a WalletKit instance with your project ID and app metadata: ```javascript import { Core } from "@walletconnect/core"; import { WalletKit } from "@reown/walletkit"; +// Create a Core instance with your project ID const core = new Core({ - projectId: process.env.PROJECT_ID, + projectId: process.env.PROJECT_ID, // Your Reown Cloud project ID }); +// Initialize WalletKit with the core instance const walletKit = await WalletKit.init({ - core, // <- pass the shared `core` instance + core, metadata: { - name: "Demo app", - description: "Demo Client as Wallet/Peer", - url: "https://reown.com/walletkit", - icons: [], + name: "My Wallet App", + description: "Web3 Wallet Application", + url: "https://mywalletapp.com", + icons: ["https://mywalletapp.com/icon.png"], // Optional app icons }, }); ``` -## Session +> **Important**: Initialize `walletKit` once globally and reuse the same instance throughout your application. For React apps, initialize it in your root component. + +## Understanding Sessions -A session is a connection between a dapp and a wallet. It is established when a user approves a session proposal from a dapp. A session is active until the user disconnects from the dapp or the session expires. +### What is a Session? -### Namespace Builder +A session is a secure connection between a dapp and a wallet. Sessions are: +- Created when a user approves a connection request from a dapp +- Active until manually disconnected or until they expire (default: 7 days) +- Used to handle requests like transaction signing and message signing -With WalletKit (and @walletconnect/utils) we've published a helper utility that greatly reduces the complexity of parsing the `required` and `optional` namespaces. It accepts as parameters a `session proposal` along with your user's `chains/methods/events/accounts` and returns ready-to-use `namespaces` object. +### Managing Sessions + +#### Retrieving Active Sessions ```javascript -// util params -{ - proposal: ProposalTypes.Struct; // the proposal received by `.on("session_proposal")` - supportedNamespaces: Record< // your Wallet's supported namespaces - string, // the supported namespace key e.g. eip155 - { - chains: string[]; // your supported chains in CAIP-2 format e.g. ["eip155:1", "eip155:2", ...] - methods: string[]; // your supported methods e.g. ["personal_sign", "eth_sendTransaction"] - events: string[]; // your supported events e.g. ["chainChanged", "accountsChanged"] - accounts: string[] // your user's accounts in CAIP-10 format e.g. ["eip155:1:0x453d506b1543dcA64f57Ce6e7Bb048466e85e228"] - } - >; -}; +const activeSessions = walletKit.getActiveSessions(); ``` -Example usage +#### Creating Sessions with Namespace Builder -```javascript -// import the builder util -import { WalletKit, WalletKitTypes } from '@reown/walletkit' -import { buildApprovedNamespaces, getSdkError } from '@walletconnect/utils' +The namespace builder simplifies creating compatible session configurations: -async function onSessionProposal({ id, params }: WalletKitTypes.SessionProposal){ - try{ - // ------- namespaces builder util ------------ // +```javascript +// Import required utilities +import { WalletKit, WalletKitTypes } from '@reown/walletkit'; +import { buildApprovedNamespaces, getSdkError } from '@walletconnect/utils'; + +// Handle session proposals +async function onSessionProposal({ id, params }: WalletKitTypes.SessionProposal) { + try { + // Build namespaces with supported chains, methods, events, and accounts const approvedNamespaces = buildApprovedNamespaces({ proposal: params, supportedNamespaces: { eip155: { - chains: ['eip155:1', 'eip155:137'], + chains: ['eip155:1', 'eip155:137'], // Ethereum, Polygon methods: ['eth_sendTransaction', 'personal_sign'], events: ['accountsChanged', 'chainChanged'], accounts: [ @@ -86,137 +97,53 @@ async function onSessionProposal({ id, params }: WalletKitTypes.SessionProposal) ] } } - }) - // ------- end namespaces builder util ------------ // + }); + // Approve the session with the built namespaces const session = await walletKit.approveSession({ id, namespaces: approvedNamespaces - }) - }catch(error){ - // use the error.message to show toast/info-box letting the user know that the connection attempt was unsuccessful - .... + }); + + // Session is now established + } catch (error) { + // Handle errors (e.g., show user notification) await walletKit.rejectSession({ id: proposal.id, reason: getSdkError("USER_REJECTED") - }) + }); } } +// Listen for session proposals +walletKit.on('session_proposal', onSessionProposal); -walletKit.on('session_proposal', onSessionProposal) +// Connect to a dapp using its URI (typically from a QR code) +await walletKit.pair({ uri: "wc:..." }); ``` -If your wallet supports multiple namespaces e.g. `eip155`,`cosmos` & `near` -Your `supportedNamespaces` should look like the following example. +For wallets supporting multiple blockchain ecosystems: ```javascript -// ------- namespaces builder util ------------ // const approvedNamespaces = buildApprovedNamespaces({ - proposal: params, - supportedNamespaces: { - eip155: {...}, - cosmos: {...}, - near: {...} + proposal: params, + supportedNamespaces: { + eip155: { + // Ethereum configuration }, + cosmos: { + // Cosmos configuration + }, + near: { + // NEAR Protocol configuration + } + }, }); -// ------- end namespaces builder util ------------ // -``` - -### Get Active Sessions - -You can get the wallet active sessions using the `getActiveSessions` function. - -```js -const activeSessions = walletKit.getActiveSessions(); -``` - -### EVM methods & events - -In @walletconnect/ethereum-provider, (our abstracted EVM SDK for apps) we support by default the following Ethereum methods and events: - -```ts -{ - //... - methods: [ - "eth_accounts", - "eth_requestAccounts", - "eth_sendRawTransaction", - "eth_sign", - "eth_signTransaction", - "eth_signTypedData", - "eth_signTypedData_v3", - "eth_signTypedData_v4", - "eth_sendTransaction", - "personal_sign", - "wallet_switchEthereumChain", - "wallet_addEthereumChain", - "wallet_getPermissions", - "wallet_requestPermissions", - "wallet_registerOnboarding", - "wallet_watchAsset", - "wallet_scanQRCode", - "wallet_sendCalls", - "wallet_getCallsStatus", - "wallet_showCallsStatus", - "wallet_getCapabilities", - ], - events: [ - "chainChanged", - "accountsChanged", - "message", - "disconnect", - "connect", - ] -} -``` - -### Session Approval - -The `session_proposal` event is emitted when a dapp initiates a new session with a user's wallet. The event will include a `proposal` object with information about the dapp and requested permissions. The wallet should display a prompt for the user to approve or reject the session. If approved, call `approveSession` and pass in the `proposal.id` and requested `namespaces`. - -The `pair` method initiates a WalletConnect pairing process with a dapp using the given `uri` (QR code from the dapps). To learn more about pairing, checkout out the [docs](/advanced/api/core/pairing). - -```javascript -walletKit.on( - "session_proposal", - async (proposal: WalletKitTypes.SessionProposal) => { - const session = await walletKit.approveSession({ - id: proposal.id, - namespaces, - }); - } -); -await walletKit.pair({ uri }); ``` -### 🛠️ Usage examples - -- [in a demo wallet app](https://github.com/WalletConnect/web-examples/blob/a50c8eb5a10666f25911713c5358e78f1ca576d6/advanced/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx#L264) -- [in integration tests](https://github.com/reown-com/reown-walletkit-js/blob/main/packages/walletkit/test/sign.spec.ts#L55) - -### ⚠️ Expected Errors - -- `No matching key. proposal id doesn't exist: 1` - -This rejection means the SDK can't find a record with the given `proposal.id` - in this example `1`. -This can happen when the proposal has expired (by default 5 minutes) or if you attempt to respond to a proposal that has already been approved/rejected. -If you are seeing this error, please make sure that you are calling `approveSession` with the correct `proposal.id` that is available within the proposal payload. +#### Rejecting Sessions -- `Error: Missing or invalid. approve(), namespaces should be an object with data` - -This error means that the `namespaces` parameter passed to `approveSession` is either missing or invalid. Please check that you are passing a valid `namespaces` object that satisfies all required properties. - -- `Non conforming namespaces. approve() namespaces don't satisfy required namespaces.` - -This error indicates that some value(s) in your `namespaces` object do not satisfy the required namespaces requested by the dapp. -To provide additional guidance, the message might include info about the exact property that is missing or invalid e.g. `Required: eip155:1 Approved: eip155:137`. -Please check [CAIP-25](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-25.md) to familiarize yourself with the standard and it's nuances. -Additionally, we highly recommend you to use our `namespace` builder utility that would greatly simplify the process of parsing & building a valid `namespaces` object. - -### Session Rejection - -In the event you want to reject the session proposal, call the `rejectSession` method. The `getSDKError` function comes from the `@walletconnect/utils` [library](https://github.com/WalletConnect/walletconnect-monorepo/tree/v2.0/packages/utils). +To reject a session proposal: ```javascript walletKit.on( @@ -230,33 +157,11 @@ walletKit.on( ); ``` -### 🛠️ Usage examples - -- [in a demo wallet app](https://github.com/WalletConnect/web-examples/blob/a50c8eb5a10666f25911713c5358e78f1ca576d6/advanced/wallets/react-wallet-v2/src/views/SessionProposalModal.tsx#L287) -- [in integration tests](https://github.com/reown-com/reown-walletkit-js/blob/main/packages/walletkit/test/sign.spec.ts#L79) - -### ⚠️ Expected Errors - -- `No matching key. proposal id doesn't exist: 1` - -This rejection means the SDK can't find a record with the given `proposal.id` - in this example `1`. -This can happen when the proposal has expired (by default 5 minutes) or if you attempt to respond to a proposal that has already been approved/rejected. -If you are seeing this error, please make sure that you are calling `rejectSession` with the correct `proposal.id` that is available within the proposal payload. +## Handling Session Requests -- `Error: Missing or invalid. reject() reason:` +### Responding to Requests -This rejection means the `reason` parameter passed to `rejectSession` is either missing or invalid. -We recommend using the `getSDKError` function from the `@walletconnect/utils` library that will populate & format the parameter for you. - -### Responding to Session requests - -The `session_request` event is emitted when the SDK received a request from the peer and it needs the wallet to perform a specific action, such as signing a transaction. The event contains a `topic` and a `request` object, which will vary depending on the action requested. - -To respond to the request, you can access the `topic` and `request` object by destructuring them from the event payload. To see a list of possible `request` and `response` objects, refer to the relevant JSON-RPC Methods for [Ethereum](../../advanced/multichain/rpc-reference/ethereum-rpc.md), [Solana](../../advanced/multichain/rpc-reference/solana-rpc.md), [Cosmos](../../advanced/multichain/rpc-reference/cosmos-rpc.md), or [Stellar](../../advanced/multichain/rpc-reference/stellar-rpc.md). - -As an example, if the dapp requests a `personal_sign` method, you can extract the `params` array from the `request` object. The first item in the array is the hex version of the message to be signed, which can be converted to UTF-8 and assigned to a `message` variable. The second item in `params` is the user's wallet address. - -To sign the message, you can use your wallet's `signMessage` method and pass in the message. The signed message, along with the `id` from the event payload, can then be used to create a `response` object, which can be passed into `respondSessionRequest`. +When a dapp sends a request (like signing a transaction), handle it with: ```javascript walletKit.on( @@ -264,22 +169,34 @@ walletKit.on( async (event: WalletKitTypes.SessionRequest) => { const { topic, params, id } = event; const { request } = params; - const requestParamsMessage = request.params[0]; - - // convert `requestParamsMessage` by using a method like hexToUtf8 - const message = hexToUtf8(requestParamsMessage); - - // sign the message - const signedMessage = await wallet.signMessage(message); - - const response = { id, result: signedMessage, jsonrpc: "2.0" }; - - await walletKit.respondSessionRequest({ topic, response }); + + // Example: Processing a message signing request + if (request.method === "personal_sign") { + const messageHex = request.params[0]; + const address = request.params[1]; + + // Convert hex message to readable text + const message = hexToUtf8(messageHex); + + // Sign message with your wallet implementation + const signedMessage = await wallet.signMessage(message); + + // Send successful response + const response = { + id, + result: signedMessage, + jsonrpc: "2.0" + }; + + await walletKit.respondSessionRequest({ topic, response }); + } } ); ``` -To reject a session request, the response should be similar to this. +### Rejecting Requests + +To reject a request (e.g., when user cancels): ```javascript const response = { @@ -287,201 +204,146 @@ const response = { jsonrpc: "2.0", error: { code: 5000, - message: "User rejected.", + message: "User rejected the request", }, }; -``` - -### 🛠️ Usage examples - -- [in a demo wallet app](https://github.com/WalletConnect/web-examples/blob/a50c8eb5a10666f25911713c5358e78f1ca576d6/advanced/wallets/react-wallet-v2/src/views/SessionSignModal.tsx#L36) -- [in integration tests](https://github.com/reown-com/reown-walletkit-js/blob/main/packages/walletkit/test/sign.spec.ts#L165) - -### ⚠️ Expected Errors - -- `Error: No matching key. session topic doesn't exist: 'xyz...'` - -This rejection means the SDK can't find a session with the given `topic` - in this example `xyz...`. -This can happen when the session has been disconnected by either the wallet or the dapp while the session request was being processed or if a session with such topic doesn't exist. -If you are seeing this error, please make sure that you are using a correct topic that is available within the request payload. - -- `Error: Missing or invalid. respond() response:` -This rejection means the `response` parameter passed to `respondSessionRequest` is either missing or invalid. The response should be a valid [JSON-RPC 2.0](https://www.jsonrpc.org/specification) response object. -We recommend you to use our `formatJsonRpcResult` utility from `"@walletconnect/jsonrpc-utils"` that will format the response for you. - -Example usage: -`id` argument being the request id from the request payload. - -```javascript -import { formatJsonRpcResult } from "@walletconnect/jsonrpc-utils"; - -const signature = await cryptoWallet.signTransaction(signTransaction); -const response = await walletKit.respondSessionRequest({ - topic: session.topic, - response: formatJsonRpcResult(id, signature), -}); +await walletKit.respondSessionRequest({ topic, response }); ``` -### Updating a Session +## Managing Existing Sessions -If you wish to include new accounts or chains or methods in an existing session, `updateSession` allows you to do so. -You need pass in the `topic` and a new `Namespaces` object that contains all of the existing namespaces as well as the new data you wish to include. -After you update the session, the other peer will receive a `session_update` event. +### Updating Sessions -An example adding a new account to an existing session: +To add new accounts or chains to an existing session: ```javascript +// Adding a new account const namespaces = session.namespaces; const accounts = [ "eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb", - "eip155:1:0x1234567890123456789012345678901234567890", + "eip155:1:0x1234567890123456789012345678901234567890", // New account ]; -const updatedNamespaces = { - ...namespaces, - eip155: { - ...namespaces.eip155, - accounts, - }, -}; -const { acknowledged } = await walletKit.updateSession({ - topic: session.topic, - namespaces: updatedNamespaces, -}); -// If you wish to be notified when the dapp acknowledges the update. -// note that if the dapp is offline `acknowledged` will not resolve until it comes back online -await acknowledged(); -``` -An example adding a new chain to an existing session: - -```javascript -const namespaces = session.namespaces; -const chains = ["eip155:1", "eip155:137"]; -const accounts = [ - "eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb", - "eip155:137:0x1234567890123456789012345678901234567890", -]; const updatedNamespaces = { ...namespaces, eip155: { ...namespaces.eip155, accounts, - chains, }, }; + await walletKit.updateSession({ topic: session.topic, namespaces: updatedNamespaces, }); ``` -### 🛠️ Usage examples - -- [in a demo wallet app](https://github.com/WalletConnect/web-examples/blob/a50c8eb5a10666f25911713c5358e78f1ca576d6/advanced/wallets/react-wallet-v2/src/pages/session.tsx#L77) -- [in integration tests](https://github.com/reown-com/reown-walletkit-js/blob/main/packages/walletkit/test/sign.spec.ts#L98) - -### ⚠️ Expected Errors - -Note that all `namespaces` validation applies and you still have to satisfy the required namespaces requested by the dapp. - -- `Error: No matching key. session topic doesn't exist: 'xyz...'` - -This rejection means the SDK can't find a session with the given `topic` - in this example `xyz...`. -This can happen when the session you're trying to update has already been disconnected by either the wallet or the dapp or if a session with such topic doesn't exist. -If you are seeing this error, please make sure that you are using a correct topic of an active session. - -- `Error: Missing or invalid. update(), namespaces should be an object with data` - -This error means that the `namespaces` parameter passed to `updateSession` is either missing or invalid. Please check that you are passing a valid `namespaces` object that satisfies all required properties. - -- `Non conforming namespaces. update() namespaces don't satisfy required namespaces.` - -This error indicates that some value(s) in your `namespaces` object do not satisfy the required namespaces requested by the dapp. -To provide additional guidance, the message might include info about the exact property that is missing or invalid e.g. `Required: eip155:1 Approved: eip155:137`. -Please check [CAIP-25](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-25.md) to familiarize yourself with the standard and it's nuances. -Additionally, we highly recommend you to use our `namespace` builder utility that would greatly simplify the process of parsing & building a valid `namespaces` object. - -### Extending a Session +### Extending Session Duration -Sessions have a default expiry of 7 days. To extend a session by an additional 7 days, call `.extendSession` method and pass in the `topic` of the session you wish to extend. +Sessions expire after 7 days by default. Extend a session with: ```javascript -const { acknowledged } = await walletKit.extendSession({ topic }); -// if you wish to be notified when the dapp acks the extend -// note that if the dapp is offline `acknowledged` will not resolve until it comes back online +const { acknowledged } = await walletKit.extendSession({ + topic: session.topic +}); + +// Optional: Wait for dapp to acknowledge await acknowledged(); ``` -### 🛠️ Usage examples - -- [in integration tests](https://github.com/reown-com/reown-walletkit-js/blob/main/packages/walletkit/test/sign.spec.ts#L130) - -### ⚠️ Expected Errors - -- `Error: No matching key. session topic doesn't exist: 'xyz...'` - -This rejection means the SDK can't find a session with the given `topic` - in this example `xyz...`. -This can happen when the session you're trying to update has already been disconnected by either the wallet or the dapp or if a session with such topic doesn't exist. -If you are seeing this error, please make sure that you are using a correct topic of an active session. - -### Session Disconnect - -To initiate disconnect from a session(think session delete), call `.disconnectSession` by passing a `topic` & `reason` for the disconnect. -The other peer will receive a `session_delete` and be notified that the session has been disconnected. - - -**Note** +### Disconnecting Sessions -It's important that you're subscribed to the `session_delete` event as well, to be notified when the other peer initiates a disconnect. - - -We recommend using the `getSDKError` utility function, that will provide ready-to-use `reason` payloads and is available in the `@walletconnect/utils` [library](https://github.com/WalletConnect/walletconnect-monorepo/tree/v2.0/packages/utils). - +To terminate a session: ```javascript await walletKit.disconnectSession({ - topic, + topic: session.topic, reason: getSdkError("USER_DISCONNECTED"), }); ``` -### 🛠️ Usage examples - -- [in integration tests](https://github.com/reown-com/reown-walletkit-js/blob/main/packages/walletkit/test/sign.spec.ts#L222) - -### ⚠️ Expected Errors - -- `Error: No matching key. session topic doesn't exist: 'xyz...'` +> **Note**: Always subscribe to the `session_delete` event to handle when a dapp disconnects. -This rejection means the SDK can't find a session with the given `topic` - in this example `xyz...`. -This can happen when the session you're trying to update has already been disconnected by either the wallet or the dapp or if a session with such topic doesn't exist. -If you are seeing this error, please make sure that you are using a correct topic of an active session. +## Emitting Events -### Emitting Session Events - -To emit session events, call the `emitSessionEvent` and pass in the params. If you wish to switch to chain/account that is not approved (missing from `session.namespaces`) you will have to update the session first. In the following example, the wallet will emit `session_event` that will instruct the dapp to switch the active accounts. +Notify dapps about wallet state changes: ```javascript +// Example: Notifying when active account changes await walletKit.emitSessionEvent({ - topic, + topic: session.topic, event: { name: "accountsChanged", data: ["0xab16a96D359eC26a11e2C2b3d8f8B8942d5Bfcdb"], }, chainId: "eip155:1", }); -``` - -In the following example, the wallet will emit `session_event` when the wallet switches chains. -```javascript +// Example: Notifying when active chain changes await walletKit.emitSessionEvent({ - topic, + topic: session.topic, event: { name: "chainChanged", - data: 1, + data: 1, // Chain ID }, chainId: "eip155:1", }); ``` + +## Common Errors and Solutions + +### Session Proposal Errors + +- **"No matching key. proposal id doesn't exist"**: The proposal may have expired (default: 5 minutes) or been already processed. + - Solution: Use the correct `proposal.id` from the current proposal payload. + +- **"Missing or invalid. approve(), namespaces should be an object with data"**: The namespaces object is invalid. + - Solution: Ensure you're providing a properly formatted namespaces object. + +- **"Non conforming namespaces"**: Your namespaces don't match what the dapp requested. + - Solution: Use the namespace builder utility and ensure you're supporting all required chains/methods. + +### Session Request Errors + +- **"No matching key. session topic doesn't exist"**: The session may have been disconnected. + - Solution: Verify the session exists before responding. + +- **"Missing or invalid. respond() response"**: Invalid response format. + - Solution: Use `formatJsonRpcResult` from `@walletconnect/jsonrpc-utils`. + +## Supported Methods and Events + +WalletKit supports these Ethereum methods by default: + +```javascript +methods: [ + "eth_accounts", + "eth_requestAccounts", + "eth_sendRawTransaction", + "eth_sign", + "eth_signTransaction", + "eth_signTypedData", + "eth_signTypedData_v3", + "eth_signTypedData_v4", + "eth_sendTransaction", + "personal_sign", + "wallet_switchEthereumChain", + "wallet_addEthereumChain", + // And more... +] + +events: [ + "chainChanged", + "accountsChanged", + "message", + "disconnect", + "connect", +] +``` + +## Additional Resources + +- [GitHub Demo Wallet App](https://github.com/WalletConnect/web-examples/tree/main/advanced/wallets/react-wallet-v2) +- [Integration Tests](https://github.com/reown-com/reown-walletkit-js/blob/main/packages/walletkit/test/sign.spec.ts) +- [CAIP-25 Standard](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-25.md) From 7ace72c83a4f32bdbe2e0c5acb7b96847c81c970 Mon Sep 17 00:00:00 2001 From: jakubuid Date: Wed, 23 Apr 2025 11:01:41 +0300 Subject: [PATCH 3/3] Improve One-click Auth documentation for better readability and AI-friendliness --- walletkit/web/one-click-auth.mdx | 164 +++++++++++++++++++++---------- 1 file changed, 110 insertions(+), 54 deletions(-) diff --git a/walletkit/web/one-click-auth.mdx b/walletkit/web/one-click-auth.mdx index 184c1bf9d..24f27e544 100644 --- a/walletkit/web/one-click-auth.mdx +++ b/walletkit/web/one-click-auth.mdx @@ -1,135 +1,191 @@ --- title: One-click Auth +description: Implement streamlined authentication for your wallet --- -## Introduction +# One-click Authentication -This section outlines an innovative protocol method that facilitates the initiation of a Sign session and the authentication of a wallet through a [Sign-In with Ethereum](https://eips.ethereum.org/EIPS/eip-4361) (SIWE) message, enhanced by [ReCaps](https://eips.ethereum.org/EIPS/eip-5573) (ReCap Capabilities). +## What is One-click Auth? -This enhancement not only offers immediate authentication for dApps, paving the way for prompt user logins, but also integrates informed consent for authorization. Through this mechanism, dApps can request the delegation of specific capabilities to perform actions on behalf of the wallet user. These capabilities, encapsulated within SIWE messages as ReCap URIs, detail the scope of actions authorized by the user in an explicit and human-readable form. +One-click Auth is a streamlined authentication protocol that allows users to: +- Sign in to dApps quickly with their Ethereum wallet +- Authorize specific permissions in a single step +- Enjoy a smoother user experience with fewer confirmation prompts + +This protocol combines [Sign-In with Ethereum](https://eips.ethereum.org/EIPS/eip-4361) (SIWE) messages with [ReCaps](https://eips.ethereum.org/EIPS/eip-5573) (ReCap Capabilities) to create a secure, consent-based authentication flow. -By incorporating ReCaps, this method extends the utility of SIWE messages, allowing dApps to combine authentication with a nuanced authorization model. This model specifies the actions a dApp is authorized to execute on the user's behalf, enhancing security and user autonomy by providing clear consent for each delegated capability. As a result, dApps can utilize these consent-backed messages to perform predetermined actions, significantly enriching the interaction between dApps, wallets, and users within the Ethereum ecosystem. -![](/images/w3w/authenticatedSessions-light.png) +![One-click Authentication Flow](/images/w3w/authenticatedSessions-light.png) -## Handling Authentication Requests +## Key Benefits + +1. **Combined Authentication and Authorization**: Users can authenticate and grant specific permissions in one step +2. **Explicit Consent**: All authorized actions are clearly defined in human-readable format +3. **Enhanced Security**: Granular permissions prevent unauthorized access +4. **Improved UX**: Fewer confirmation steps for users + +## Implementation Guide + +### Step 1: Listen for Authentication Requests -To handle incoming authentication requests, subscribe to the `session_authenticate` event. This will notify you of any authentication requests that need to be processed, allowing you to either approve or reject them based on your application logic. +First, set up an event listener for incoming authentication requests: ```typescript walletKit.on("session_authenticate", async (payload) => { - // Process the authentication request here. - // Steps include: - // 1. Populate the authentication payload with the supported chains and methods - // 2. Format the authentication message using the payload and the user's account - // 3. Present the authentication message to the user - // 4. Sign the authentication message(s) to create a verifiable authentication object(s) - // 5. Approve the authentication request with the authentication object(s) + // We'll implement the authentication flow in the next steps + console.log("Received authentication request:", payload); }); ``` -## Authentication Objects/Payloads +### Step 2: Create the Authentication Payload + +When an authentication request is received, populate it with your wallet's supported chains and methods: ```typescript import { populateAuthPayload } from "@walletconnect/utils"; -// EVM chains that your wallet supports -const supportedChains = ["eip155:1", "eip155:2", 'eip155:137']; -// EVM methods that your wallet supports -const supportedMethods = ["personal_sign", "eth_sendTransaction", "eth_signTypedData"]; -// Populate the authentication payload with the supported chains and methods +// Define chains and methods your wallet supports +const supportedChains = [ + "eip155:1", // Ethereum Mainnet + "eip155:137" // Polygon +]; + +const supportedMethods = [ + "personal_sign", + "eth_sendTransaction", + "eth_signTypedData" +]; + +// Populate the authentication payload const authPayload = populateAuthPayload({ authPayload: payload.params.authPayload, chains: supportedChains, methods: supportedMethods, }); -// Prepare the user's address in CAIP10(https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-10.md) format -const iss = `eip155:1:0x0Df6d2a56F90e8592B4FfEd587dB3D5F5ED9d6ef`; -// Now you can use the authPayload to format the authentication message +``` + +### Step 3: Format the Authentication Message + +Create a SIWE message that the user will sign: + +```typescript +// Format user's address according to CAIP-10 standard +// Format: namespace:chainId:address +const userAddress = "0x0Df6d2a56F90e8592B4FfEd587dB3D5F5ED9d6ef"; +const iss = `eip155:1:${userAddress}`; + +// Generate the authentication message const message = walletKit.formatAuthMessage({ request: authPayload, iss }); -// Present the authentication message to the user -... +// Display this message to the user for review before signing +showMessageToUser(message); ``` -## Approving Authentication Requests +### Step 4: Approve Authentication (Two Approaches) - -**Note** +#### Approach 1: Single Authentication Object -1. The recommended approach for secure authentication across multiple chains involves signing a SIWE (Sign-In with Ethereum) message for each chain and account. However, at a minimum, one SIWE message must be signed to establish a session. It is possible to create a session for multiple chains with just one issued authentication object. -2. Sometimes a dapp may want to only authenticate the user without creating a session, not every approval will result with a new session. - +For simple cases, you can create a single authentication object: ```typescript -// Approach 1 -// Sign the authentication message(s) to create a verifiable authentication object(s) -const signature = await cryptoWallet.signMessage(message, privateKey); -// Build the authentication object(s) +// After user approves the message +const signature = await wallet.signMessage(message); + +// Build the authentication object const auth = buildAuthObject( authPayload, { - t: "eip191", - s: signature, + t: "eip191", // Signature type (EIP-191) + s: signature, // The signature }, iss ); -// Approve +// Approve the authentication request await walletKit.approveSessionAuthenticate({ id: payload.id, auths: [auth], }); +``` + +#### Approach 2: Multiple Authentication Objects (Recommended for Multi-chain) -// Approach 2 -// Note that you can also sign multiple messages for every requested chain/address pair +For better security with multiple chains, sign a separate message for each chain: + +```typescript const auths = []; -authPayload.chains.forEach(async (chain) => { - const message = walletKit.formatAuthMessage({ + +// Create authentication objects for each chain +for (const chain of authPayload.chains) { + // Create message specific to this chain + const chainMessage = walletKit.formatAuthMessage({ request: authPayload, - iss: `${chain}:${cryptoWallet.address}`, + iss: `${chain}:${wallet.address}`, }); - const signature = await cryptoWallet.signMessage(message); + + // Sign the message + const signature = await wallet.signMessage(chainMessage); + + // Build authentication object for this chain const auth = buildAuthObject( authPayload, { - t: "eip191", // signature type + t: "eip191", s: signature, }, - `${chain}:${cryptoWallet.address}` + `${chain}:${wallet.address}` ); + auths.push(auth); -}); +} -// Approve +// Approve with multiple authentication objects await walletKit.approveSessionAuthenticate({ id: payload.id, auths, }); ``` -## Rejecting Authentication Requests +> **Note**: While you can authenticate multiple chains with a single signature, creating separate signatures for each chain provides better security. + +### Step 5: Rejecting Authentication Requests -If the authentication request cannot be approved or if the user chooses to reject it, use the rejectSession method. +If the user decides not to approve the authentication request: ```typescript import { getSdkError } from "@walletconnect/utils"; await walletKit.rejectSessionAuthenticate({ id: payload.id, - reason: getSdkError("USER_REJECTED"), // or choose a different reason if applicable + reason: getSdkError("USER_REJECTED"), }); ``` -## Testing One-click Auth +## Important Considerations -You can use [AppKit Lab](https://appkit-lab.reown.com/library/ethers-siwe/) to test and verify that your wallet supports One-click Auth properly. +1. **Session Creation**: Not all authentication approvals result in a new session. Some dApps may want to authenticate users without creating a persistent session. + +2. **Message Display**: Always show the authentication message to users before signing so they can review the permissions they're granting. + +3. **Signature Types**: The examples use EIP-191 signatures, which are standard for Ethereum wallets. + +## Testing Your Implementation + +You can test your One-click Auth implementation using the AppKit Lab: + +## Common Issues and Solutions + +- **Invalid Signature**: Ensure you're using the correct private key and message format +- **Chain Mismatch**: Verify that the chains in your authentication payload match what the dApp is requesting +- **Missing Methods**: Confirm that your supported methods include what the dApp needs