# Pairing API Source: https://docs.reown.com/advanced/api/core/pairing The Pairing API is a lightweight API for establishing an encrypted, protocol-agnostic communication layer between peers. Its purpose is to provide a secure channel for proposing protocols or sending requests between dapp and wallet. **Don't have a project ID?** Head over to Reown Cloud and create a new project now! ## Installation WalletConnect currently offers Sign and Auth SDKs. To allow a reusable communication channel between peers, the Pairing API exposes a standard interface and allows for sending and receiving multi-protocol requests over a single pairing. Each SDK uses the same implementation of `core/pairing` (via `@walletconnect/core`) to manage pairings. To run multiple SDKs side-by-side (e.g. Sign and Auth), please refer to the \[Sharing a Core instance] guide. #### Add SDK for your project. You can add a WalletConnect Core SDKs to your project with Swift Package Manager. In order to do that: 1. Open XCode 2. Go to File -> Add Packages 3. Paste the repo GitHub URL: [https://github.com/reown-com/reown-swift](https://github.com/reown-com/reown-swift) 4. Tap Add Package 5. Select WalletConnectPairing check mark Kotlin implementation of Android CoreClient for all WalletConnect SDKs. This SDK is developed in Kotlin and usable in both Java and Kotlin files. ![Maven Central](https://img.shields.io/maven-central/v/com.walletconnect/android-core) #### Requirements * Android min SDK 23 * Java 11 #### Installation root/build.gradle.kts: ```gradle allprojects { repositories { mavenCentral() maven { url "https://jitpack.io" } } } ``` app/build.gradle ```gradle implementation("com.walletconnect:android-core:release_version") ``` #### Project set up To use initialize RelayClient properly you will need a projectId. Go to [https://cloud.reown.com/app](https://cloud.reown.com/app), register your project and get projectId. #### CoreClient initialization Before using any of the WalletConnect Kotlin SDKs, it is necessary to initialize the CoreClient. The initialization of CoreClient must always happen in the Android Application class. Provide the projectId generated in the Reown Cloud, the WebSocket URL, choose the connection type, and pass the application class. You can also pass your own Relay instance using the `RelayConnectionInterface`. ```kotlin val projectId = "" //Get Project ID at https://cloud.reown.com/ val connectionType = ConnectionType.AUTOMATIC or ConnectionType.MANUAL val application = //Android Application level class [Optional] val optionalRelay: RelayConnectionInterface? = /*implement interface*/ CoreClient.initialize(projectId = projectId, connectionType = connectionType, application = application, relay = optionalRelay) ``` #### Using your own Relay instance The CoreClient offers the ability to use a custom Relay client. Just creating an instance of `RelayConnectionInterface` and passing it to `CoreClient.initialize`. ```kotlin ... val optionalRelay: RelayConnectionInterface = /*implement interface*/ CoreClient.initialize(projectId = projectId, connectionType = connectionType, application = application, relay = optionalRelay) ``` WalletConnect currently offers Sign and Auth SDKs. To allow a reusable communication channel between peers, the Pairing API exposes a standard interface and allows for sending and receiving multi-protocol requests over a single pairing. Each SDK uses the same implementation of `core/pairing` (via `@walletconnect/core`) to manage pairings. To run multiple SDKs side-by-side (e.g. Sign and Auth), please refer to the \[Sharing a Core instance] guide. Install the `WalletConnect.Core` nuget package, which implements the Pairing API ```shell dotnet add package WalletConnect.Core ``` Once the `WalletConnect.Core` library is installed, create a Metadata object. It will describe your application and define its appearance in a web browser. Then configure the Pair instance with a metadata object you have instantiated. ```csharp var metadata = new Metadata() { Name = "my-app", Description = "My app description", Icons = new[] { "https://walletconnect.com/meta/favicon.ico" }, Url = "https://walletconnect.com", } var options = new CoreOptions() { ProjectId = "...", Name = "my-app", } var core = new WalletConnectCore(options); core.Pairing.Configure(metadata); ``` Since `WalletConnectUnity` is a wrapper around `WalletConnectSharp`, usage of the pairing API is identical to `.NET`. Please refer to .NET documentation on how to use Pairing inside `WalletConnectUnity`. #### Package Installation To install packages via OpenUPM, you need to have [Node.js](https://nodejs.org/en/) and [openupm-cli](https://openupm.com/docs/getting-started.html#installing-openupm-cli) installed. Once you have them installed, you can run the following commands: ```bash openupm add com.walletconnect.core ``` 1. Open `Advanced Project Settings` from the gear ⚙ menu located at the top right of the Package Manager’s toolbar 2. Add a new scoped registry with the following details: * Name: `OpenUPM` * URL: `https://package.openupm.com` * Scope(s): `com.walletconnect` 3. Press plus ➕ and then `Save` buttons 4. In the Package Manager windows open the add ➕ menu from the toolbar 5. Select `Add package by name...` 6. Enter the package name: * `com.walletconnect.core` 7. Press `Add` button 1. Open the add ➕ menu in the Package Manager’s toolbar 2. Select `Add package from git URL...` 3. Enter the package URL: **WalletConnectUnity Core** ``` https://github.com/WalletConnect/WalletConnectUnity.git?path=Packages/com.walletconnect.core ``` 4. Press `Add` button It's possible to lock the version of the package by adding `#{version}` at the end of the git URL, where `#{version}` is the git tag of the version you want to use. For example, to install version `1.0.1` of WalletConnectUnity Modal, use the following URL: ``` https://github.com/WalletConnect/WalletConnectUnity.git?path=Packages/com.walletconnect.core#core/1.0.1 ``` #### WebGL Due to WebGL's single-threaded nature, certain asynchronous operations like `Task.Run`, `Task.ContinueWith`, `Task.Delay`, and `ConfigureAwait(false)` are not natively supported. To enable these operations in WebGL builds, an additional third-party package, [WebGLThreadingPatcher](https://github.com/VolodymyrBS/WebGLThreadingPatcher), is required. This package modifies the Unity WebGL build to delegate work to the `SynchronizationContext`, allowing these operations to be executed on the same thread without blocking the main application. Please note that all tasks are still executed on a single thread, and any blocking calls will freeze the entire application. The [WebGLThreadingPatcher](https://github.com/VolodymyrBS/WebGLThreadingPatcher) package can be added via git URL: ``` https://github.com/VolodymyrBS/WebGLThreadingPatcher.git ``` #### Initialization 1. Fill in the Project ID and Metadata fields in the `Assets/WalletConnectUnity/Resources/WalletConnectProjectConfig` asset. * If you don’t have a Project ID, you can create one at [Reown Cloud](https://cloud.reown.com). * The `Redirect` fields are optional. They are used to redirect the user back to your app after they approve or reject the session. 2. Initialize `WalletConnect` and get reference to the instance of `Core`: ```csharp // Initialize singleton await WalletConnect.Instance.InitializeAsync(); // Or handle instancing manually var walletConnectUnity = new WalletConnect(); await walletConnectUnity.InitializeAsync(); var core = WalletConnect.Instance.SignClient.Core; ``` ## Usage The methods listed below are limited to only the public methods of the Pairing API that we recommend you interact with directly. For an exhaustive list, please refer to the spec and/or implementation linked under [Useful Links](https://specs.walletconnect.com/2.0/specs/clients/core/pairing/pairing-methods) above. The keyword `sdkClient` is used here as a placeholder for any WalletConnect SDK that implements the Pairing API (e.g. `signClient`, `authClient`, etc). ```ts // Creates a new (inactive) pairing. Returns the URI for a peer to consume via `pair`, as well as the pairing topic. const {topic, uri} = await sdkClient.core.pairing.create() // Pair with a peer's proposed pairing, extracted from the provided `uri` parameter. await sdkClient.core.pairing.pair({ uri: "wc:1b3eda3f4..." }) // Activate a previously created pairing (e.g. after the peer has paired), by providing the pairing topic. await sdkClient.core.pairing.activate({ topic: "1b3eda3f4..." }) // Updates the expiry of an existing pairing, by providing the pairing topic and an `expiry` in seconds (e.g. `60` for one minute from now) await sdkClient.core.pairing.updateExpiry({ topic: "1b3eda3f4...", expiry: 60 }) // Updates a pairing's metadata, by providing the pairing topic and the desired metadata. await sdkClient.core.pairing.updateMetadata({ topic: "1b3eda3f4...", metadata: { name: "MyDapp", ... } }) // Returns an array of all existing pairings. const pairings = sdkClient.core.pairing.getPairings() // Pings a pairing's peer, by providing the pairing topic. await sdkClient.core.pairing.ping({ topic: "1b3eda3f4..." }) // Disconnects/Removes a pairing, by providing the pairing topic. await sdkClient.core.pairing.disconnect({ topic: "1b3eda3f4..." }) ``` #### Listeners for pairing-related events The Pairing API currently emits the following events: * `pairing_ping` * `pairing_delete` * `pairing_expire` Any of these events can be listened for via the standard Node [`EventEmitter` interface](https://nodejs.org/api/events.html#class-eventemitter): ```ts sdkClient.core.pairing.events.on("pairing_delete", ({ id, topic }) => { // clean up after the pairing for `topic` was deleted. }); ``` Create an AppMetadata object. It will describe your application and define its appearance in a web browser. Starting from WalletConnect SDK version 1.9.5, the `redirect` field in the `AppMetadata` object is mandatory. Ensure that the provided value matches your app's URL scheme to prevent redirection-related issues. Then configure the Pair instance with a metadata object you have instantiated. ```swift let metadata = AppMetadata(name: , description: , url: , icons: <[String]>, redirect: AppMetadata.Redirect(native: "example://", universal: nil)) Pair.configure(metadata: metadata) ``` #### Pairing Wallet Usage In pair wallet with dapp, the user needs to scan a QR code or open a deep link generated by dapp, then instantiate `WalletConnectURI` from the scanned QR code string and call the `pair()` function as follows. ```swift let uri WalletConnectURI(string: ) try! await Pair.instance.pair(uri: uri) ``` Now wallet and a dapp have a secure communication channel that will be used by top level APIs. #### Pairing Dapp Usage In order to pair dapp and a wallet, dapp needs to generate and share a uri with wallet. To generate a uri call `create()` function on Pair instance as follows. ```swift let uri = try await Pair.instance.create() ``` Now you can share the uri with the wallet. #### **Create Pairing** ```kotlin val pairing: Pairing? = CoreClient.Pairing.create() { error -> } ``` When first establishing a pairing with a Peer, call `CoreClient.Pairing.create`. This will try and generate a new pairing with a URI parameter that can be used to establish a connection with the other Peer as well as other meta data related to the pairing. # #### **Pair Clients** ```kotlin val pairingParams = Core.Params.Pair(pairingUri) CoreClient.Pairing.pair(pairingParams) { error -> } ``` To pair the wallet with the Dapp, call the CoreClient.Pairing's pair function which needs a `Core.Params.Pair` parameter. `Core.Params.Pair` is where the WC Uri will be passed. # #### **Get List of Active Pairings** ```kotlin val listOfActivePairings: List = CoreClient.Pairing.getPairings() ``` To get a list of the most current active pairings, call `CoreClient.Pairing.getPairings()` which will return a list of type `Core.Model.Pairing`. # #### **Disconnect a Pairing** ```kotlin CoreClient.Pairing.disconnect(topic = /*Pairing topic*/") { error -> } ``` To disconnect from a pairing, just pass the topic of the pairing to disconnect from (use `getPairings()` to get a list of all active pairings and their topics). The methods listed below are limited to only the public methods of the Pairing API that we recommend you interact with directly. For an exhaustive list, please refer to the spec and/or implementation linked under [Useful Links](https://specs.walletconnect.com/2.0/specs/clients/core/pairing/pairing-methods) above. The keyword `sdkClient` is used here as a placeholder for any WalletConnect SDK that implements the Pairing API (e.g. `signClient`, `authClient`, etc). ```ts // Creates a new (inactive) pairing. Returns the URI for a peer to consume via `pair`, as well as the pairing topic. const {topic, uri} = await sdkClient.core.pairing.create() // Pair with a peer's proposed pairing, extracted from the provided `uri` parameter. await sdkClient.core.pairing.pair({ uri: "wc:1b3eda3f4..." }) // Activate a previously created pairing (e.g. after the peer has paired), by providing the pairing topic. await sdkClient.core.pairing.activate({ topic: "1b3eda3f4..." }) // Updates the expiry of an existing pairing, by providing the pairing topic and an `expiry` in seconds (e.g. `60` for one minute from now) await sdkClient.core.pairing.updateExpiry({ topic: "1b3eda3f4...", expiry: 60 }) // Updates a pairing's metadata, by providing the pairing topic and the desired metadata. await sdkClient.core.pairing.updateMetadata({ topic: "1b3eda3f4...", metadata: { name: "MyDapp", ... } }) // Returns an array of all existing pairings. const pairings = sdkClient.core.pairing.getPairings() // Pings a pairing's peer, by providing the pairing topic. await sdkClient.core.pairing.ping({ topic: "1b3eda3f4..." }) // Disconnects/Removes a pairing, by providing the pairing topic. await sdkClient.core.pairing.disconnect({ topic: "1b3eda3f4..." }) ``` #### Listeners for pairing-related events The Pairing API currently emits the following events: * `pairing_ping` * `pairing_delete` * `pairing_expire` Any of these events can be listened for via the standard Node [`EventEmitter` interface](https://nodejs.org/api/events.html#class-eventemitter): ```ts sdkClient.core.pairing.events.on("pairing_delete", ({ id, topic }) => { // clean up after the pairing for `topic` was deleted. }); ``` #### Pairing Wallet Usage When paring a wallet with a dapp, the user needs to scan a QR code or open a deep link generated by the dapp. Grab the string from the scanned QR code string or from the deep link and call the `Pair()` function as follows. ```csharp var uri = "..."; PairingStruct pairingData = await core.Pairing.Pair(uri); ``` Now the wallet and a dapp have a secure communication channel that will be used by top level APIs. #### Pairing Dapp Usage In order to pair dapp and a wallet, dapp needs to generate and share a uri with wallet. To generate a uri call `create()` function on Pair instance as follows. ```csharp var pairData = await core.Pairing.Create(); string topic = pairData.Topic; string uri = pairData.Uri; ``` Now you can share the uri with the wallet either through a QR Code or by using a deep link. #### Message Sending / Handling Once a wallet and dapp has been paired, they can send messages securely to the pairing topic. Requests can be received from the dapp by handling the message callback in the `MessageHandler` module. ```csharp core.MessageHandler.MessageEventHandler() .FilterRequests(r => r.Topic == pairingData.Topic) .OnRequest += async delegate(RequestEventArgs eventArgs) { Console.WriteLine(eventArgs.Request); eventArgs.Response = new MyResponse() { // ... }; }; ``` A response can be sent for any request by setting the `Response` field in the `eventArgs` parameter. Receiving responses is handled the same way, but instead of the `OnRequest` event you would use the `OnResponse` event. Request, Responses and Errors can be sent using the `SendRequest` , `SendResult` and `SendError` functions in the `MessageHandler` module. ```csharp long id = await core.MessageHandler.SendRequest(pairingTopic, data); ``` # Relay Client Source: https://docs.reown.com/advanced/api/core/relay Relay client provides transport layer for Sign, Auth and Chat SDKs. You can configure it once and every SDK will transport protocol messages via same instance of a relay client with only one opened websocket connection. The Relay API can be accessed through the Core Client Before using Sign or Auth SDK, it is necessary to configure a shared Networking Client instance. Set a project ID generated when starting a project on Reown Cloud and SocketFactory instance. WalletConnect Swift SDK does not depend on any websocket library. SocketFactory parameter allows you to pass your own implementation of websocket connection. Here's an example of WebSocketFactory implementation using Starscream v3 ```swift import Starscream extension WebSocket: WebSocketConnecting { } struct SocketFactory: WebSocketFactory { func create(with url: URL) -> WebSocketConnecting { return WebSocket(url: url) } } ``` Please note that if you have made changes to the list of **Allowed Domains** in the **Reown Cloud Dashboard**, then you may encounter an error with the connection if you use **Starscream** or any other socket client. For example, the native implementation of **Starscream** will use the `relay.walletconnect.com` as an `Origin` parameter if not provided, which will be missing from the list of **Allowed Domains**. The solution to this could be the inclusion of the `relay.walletconnect.com` in the **Allowed Domains**, corresponding changes in the socket client implementation, or following changes in the `WebSocketFactory`. Create and register App Group Identifier in [Apple Developer Center](https://developer.apple.com/account/resources/identifiers/list/applicationGroup) if needed and provide it during Networking client configuration. ```swift import Starscream extension WebSocket: WebSocketConnecting { } struct DefaultSocketFactory: WebSocketFactory { func create(with url: URL) -> WebSocketConnecting { var urlRequest = URLRequest(url: url) urlRequest.addValue("allowed.domain.com", forHTTPHeaderField: "Origin") return WebSocket(request: urlRequest) } } ``` #### Networking client configuration ```swift Networking.configure(groupIdentifier: , projectId: , socketFactory: SocketFactory()) ``` `groupIdentifier` - App group identifier, created on [Apple Developer Center](https://developer.apple.com/account/resources/identifiers/list/applicationGrou). Enables to share keychain items between the Notify SDK and a UNNotificationServiceExtension to receive and decrypt push notifications. #### Web Socket Connection By default web socket connection is handled internally by the SDK. That means that Web socket will be safely disconnected when apps go to background and it will connect back when app reaches foreground. But if it is not expected for your app and you want to handle socket connection manually you can do it as follows: 1. set socketConnectionType for manual ```swift Networking.configure(projectId: , socketFactory: SocketFactory(), socketConnectionType: .manual) ``` 2. control socket connection: ```swift try Networking.instance.connect() ``` ```swift try Networking.instance.disconnect() ``` #### Web Socket connection control There are two connection types, Automatic and Manual. Automatic connection type enables SDK to control web socket connection internally. Meaning, web socket connection is closed when app goes to the background and is opened when app goes to the foreground. Manual connection type enables developers to control web socket connection. ```kotlin CoreClient.initialize(projectId = projectId, connectionType = ConnectionType.MANUAL, application = application) CoreClient.Relay.connect() { error -> /*Error when wrong connection type is in use*/} CoreClient.Relay.disconnect() { error -> /*Error when wrong connection type is in use*/} ``` # Shared Core Instance Source: https://docs.reown.com/advanced/api/core/shared-core The following content are only available for JavaScript. WalletConnect's SDKs are designed to share common logic and resources via the `@walletconnect/core` package. **If you intend to leverage multiple SDKs together (e.g. Sign + Auth), it is highly recommended to instantiate a single `Core` instance and pass it to the relevant SDKs.** This avoids each SDK creating its own `Core` instance, and thus duplicating computation, memory allocation, event listeners etc. In the following example, we first instantiate a `Core` instance, and then proceed to instantiate both the Sign and Auth SDK with this shared `Core`: ```ts import { Core } from "@walletconnect/core"; import SignClient from "@walletconnect/sign-client"; import { AuthClient } from "@walletconnect/auth-client"; // First instantiate a separate `Core` instance. const core = new Core({ projectId: "", }); const metadata = { name: "Example Dapp", description: "Example Dapp", url: "#", icons: ["https://walletconnect.com/walletconnect-logo.png"], }; // Pass `core` to the SignClient on init. const signClient = await SignClient.init({ core, metadata }); // Pass `core` to the AuthClient on init. const authClient = await AuthClient.init({ core, metadata }); ``` # Introduction Source: https://docs.reown.com/advanced/api/notify/about WalletConnect Notify is a push notification protocol that enables apps to notify users of both off-chain and on-chain events. The Notify API allows wallet users to register subscriptions for different on-chain or off-chain events that are relevant to the user. The notifications are sent to the respective wallets. To integrate on the Dapp Side, check [here.](/appkit/features/notifications) To integrate on the Wallet Side, check [here.](/walletkit/features/notifications) # Dapp Usage Source: https://docs.reown.com/advanced/api/sign/dapp-usage ## Implementation This library is compatible with Node.js, browsers and React Native applications (Node.js modules require polyfills for React Native). Dapps will also need to install WalletConnectModal for the UI. `bash npm npm install @walletconnect/modal ` `bash Yarn yarn add @walletconnect/modal ` `bash Bun bun add @walletconnect/modal ` `bash pnpm pnpm add @walletconnect/modal ` For an example implementation, please refer to our `react-dapp-v2` [example](https://github.com/WalletConnect/web-examples/tree/main/advanced/dapps/react-dapp-v2). #### Install Packages Dapps will also need to install `WalletConnectModal` for the UI. `bash npm npm install @walletconnect/modal ` `bash Yarn yarn add @walletconnect/modal ` `bash Bun bun add @walletconnect/modal ` `bash pnpm pnpm add @walletconnect/modal ` #### Create a Session **1. Initiate your WalletConnect client with the relay server, using [your Project ID](../../cloud/relay).** ```javascript import SignClient from "@walletconnect/sign-client"; const signClient = await SignClient.init({ projectId: "", // optional parameters relayUrl: "", metadata: { name: "Example Dapp", description: "Example Dapp", url: "#", icons: ["https://walletconnect.com/walletconnect-logo.png"], }, }); ``` **2. Add listeners for desired `SignClient` events.** To listen to pairing-related events, please follow the guidance for [Pairing API event listeners](https://specs.walletconnect.com/2.0/specs/clients/core/pairing/pairing-api). ```javascript signClient.on("session_event", ({ event }) => { // Handle session events, such as "chainChanged", "accountsChanged", etc. }); signClient.on("session_update", ({ topic, params }) => { const { namespaces } = params; const _session = signClient.session.get(topic); // Overwrite the `namespaces` of the existing session with the incoming one. const updatedSession = { ..._session, namespaces }; // Integrate the updated session state into your dapp state. onSessionUpdate(updatedSession); }); signClient.on("session_delete", () => { // Session was deleted -> reset the dapp state, clean up from user session, etc. }); ``` **3. Create a new WalletConnectModal instance.** ```javascript import { WalletConnectModal } from "@walletconnect/modal"; const walletConnectModal = new WalletConnectModal({ projectId: "", // `standaloneChains` can also be specified when calling `walletConnectModal.openModal(...)` later on. standaloneChains: ["eip155:1"], }); ``` **4. Connect the application and specify session permissions.** ```javascript try { const { uri, approval } = await signClient.connect({ // Optionally: pass a known prior pairing (e.g. from `signClient.core.pairing.getPairings()`) to skip the `uri` step. pairingTopic: pairing?.topic, // Provide the namespaces and chains (e.g. `eip155` for EVM-based chains) we want to use in this session. requiredNamespaces: { eip155: { methods: [ "eth_sendTransaction", "eth_signTransaction", "eth_sign", "personal_sign", "eth_signTypedData", ], chains: ["eip155:1"], events: ["chainChanged", "accountsChanged"], }, }, }); // Open QRCode modal if a URI was returned (i.e. we're not connecting an existing pairing). if (uri) { walletConnectModal.openModal({ uri }); // Await session approval from the wallet. const session = await approval(); // Handle the returned session (e.g. update UI to "connected" state). // * You will need to create this function * onSessionConnect(session); // Close the QRCode modal in case it was open. walletConnectModal.closeModal(); } } catch (e) { console.error(e); } ``` #### Session Authenticate with ReCaps The authenticate() method enhances the WalletConnect protocol, offering EVM dApps a sophisticated mechanism to request wallet authentication and simultaneously establish a session. This innovative approach not only authenticates the user but also facilitates a seamless session creation, integrating the capabilities defined by ERC-5573, also known as ReCaps. ReCaps extend the SIWE protocol, enabling users to give informed consent for dApps to exercise scoped capabilities on their behalf. This consent mechanism is crucial for authorizing a dApp to perform actions or access resources, thus ensuring security and trust in dApp interactions. These scoped capabilities are specified through ReCap URIs in the resources field of the AuthRequestParams, which translate to human-readable consent in the SIWE message, detailing the actions a dApp is authorized to undertake. To initiate an authentication and authorization request, a dApp invokes the authenticate() method, passing in parameters that include desired capabilities as outlined in EIP-5573. The method generates a pairing URI for user interaction, facilitating a streamlined authentication and consent process. Example of initiating an authentication request with ReCaps: ```typescript const { uri, response } = await signClient.authenticate({ chains: ['eip155:1', 'eip155:2'], // chains your dapp requests authentication for domain: 'localhost', // your domain uri: 'http://localhost/login', // uri nonce: '1239812982', // random nonce methods: ['personal_sign', 'eth_chainId', 'eth_signTypedData_v4'], // the methods you wish to use resources: ['https://example.com'] // any resources relevant to the connection }) // Present the URI to users as QR code to be able to connect with a wallet ... // wait for response const result = await response() // after a Wallet establishes a connection response will resolve with auths ( authentication objects ) & the established session const { auths, session } = result; // now you can send requests to that session ``` #### Making Requests Once the session has been established successfully, you can start making JSON-RPC requests to be approved and signed by the wallet: ```javascript const result = await signClient.request({ topic: session.topic, chainId: "eip155:1", request: { method: "personal_sign", params: [ "0x7468697320697320612074657374206d65737361676520746f206265207369676e6564", "0x1d85568eEAbad713fBB5293B45ea066e552A90De", ], }, }); ``` > For more information on available JSON-RPC requests, see the [JSON-RPC reference](../../advanced/multichain/rpc-reference/ethereum-rpc.md). ### Restoring a Session Sessions are saved to localstorage, meaning that even if the web page is reloaded, the session can still be retrieved, as demonstrated in the following code: ```ts const lastKeyIndex = signClient.session.getAll().length - 1; const lastSession = signClient.session.getAll()[lastKeyIndex]; ``` #### Finding a Specific Session If you need to find a specific session, you can do so by passing in a known `requiredNamespace` and calling `find`. ```ts const specificSession = _client.find({ requiredNamespaces: { eip155: { methods: [ "eth_sendTransaction", "eth_signTransaction", "eth_sign", "personal_sign", "eth_signTypedData", ], chains: ["eip155:5"], events: ["chainChanged", "accountsChanged"], }, }, }); ``` #### Configure Networking and Pair clients Make sure that you properly configure Networking and Pair Clients first. * [Networking](/advanced/api/core/relay) * [Pairing](/advanced/api/core/pairing) #### Configure Sign Client In order to initialize a client, call a `configure` method on the Sign instance ```swift Sign.configure(crypto: CryptoProvider) ``` #### Subscribe for Sign publishers When your `Sign` instance receives requests from a peer it will publish related event. So you should set subscription to handle them. To track sessions subscribe to `sessionsPublisher` publisher ```swift Sign.instance.sessionsPublisher .receive(on: DispatchQueue.main) .sink { [unowned self] (sessions: [Session]) in // reload UI }.store(in: &publishers) ``` Following publishers are available to subscribe: ```swift public var sessionsPublisher: AnyPublisher<[Session], Never> public var sessionProposalPublisher: AnyPublisher public var sessionRequestPublisher: AnyPublisher public var socketConnectionStatusPublisher: AnyPublisher public var sessionSettlePublisher: AnyPublisher public var sessionDeletePublisher: AnyPublisher<(String, Reason), Never> public var sessionResponsePublisher: AnyPublisher public var sessionRejectionPublisher: AnyPublisher<(Session.Proposal, Reason), Never> public var sessionUpdatePublisher: AnyPublisher<(sessionTopic: String, namespaces: [String : SessionNamespace]), Never> public var sessionEventPublisher: AnyPublisher<(event: Session.Event, sessionTopic: String, chainId: Blockchain?), Never> public var sessionUpdateExpiryPublisher: AnyPublisher<(sessionTopic: String, expiry: Date), Never> ``` #### Connect Clients 1. Prepare namespaces that constraints minimal requirements for your dApp: ```Swift let methods: Set = ["eth_sendTransaction", "personal_sign", "eth_signTypedData"] let blockchains: Set = [Blockchain("eip155:1")!, Blockchain("eip155:137")!] let namespaces: [String: ProposalNamespace] = ["eip155": ProposalNamespace(chains: blockchains, methods: methods, events: []] ``` To learn more on namespaces, check out our [specs](https://specs.walletconnect.com/2.0/specs/clients/sign/namespaces). 2. Your App should generate a pairing URI and share it with a wallet. Uri can be presented as a QR code or sent via a universal link. Wallet begins subscribing for session proposals after receiving URI. In order to create a pairing and send a session proposal, you need to call the following: ```Swift let uri = try await Sign.instance.connect(requiredNamespaces: namespaces, topic: uri.topic) ``` #### Session Authenticate with ReCaps The authenticate() method enhances the WalletConnect protocol, offering EVM dApps a sophisticated mechanism to request wallet authentication and simultaneously establish a session. This innovative approach not only authenticates the user but also facilitates a seamless session creation, integrating the capabilities defined by ERC-5573, also known as ReCaps. ReCaps extend the SIWE protocol, enabling users to give informed consent for dApps to exercise scoped capabilities on their behalf. This consent mechanism is crucial for authorizing a dApp to perform actions or access resources, thus ensuring security and trust in dApp interactions. These scoped capabilities are specified through ReCap URIs in the resources field of the AuthRequestParams, which translate to human-readable consent in the SIWE message, detailing the actions a dApp is authorized to undertake. To initiate an authentication and authorization request, a dApp invokes the authenticate() method, passing in parameters that include desired capabilities as outlined in EIP-5573. The method generates a pairing URI for user interaction, facilitating a streamlined authentication and consent process. Example of initiating an authentication request with ReCaps: ```swift func initiateAuthentication() { Task { do { let authParams = AuthRequestParams.stub() // Customize your AuthRequestParams as needed let uri = try await Sign.instance.authenticate(authParams) // Present the URI to the user, e.g., show a QR code or send a deep link presentAuthenticationURI(uri) } catch { print("Failed to initiate authentication request: \(error)") } } } ``` ##### Subscribe to Authentication Responses Once you have initiated an authentication request, you need to listen for responses from wallets. Responses will indicate whether the authentication request was approved or rejected. Use the authResponsePublisher to subscribe to these events. Example subscription to authentication responses: ```swift Sign.instance.authResponsePublisher .receive(on: DispatchQueue.main) .sink { response in switch response.result { case .success(let (session, _)): if let session = session { // Authentication successful, session established handleSuccessfulAuthentication(session) } else { // Authentication successful, but no session created (SIWE-only flow) handleSuccessfulAuthenticationWithoutSession() } case .failure(let error): // Authentication request was rejected or failed handleAuthenticationFailure(error) } } .store(in: &subscriptions) ``` In this setup, the authResponsePublisher notifies your dApp of the outcome of the authentication request. Your dApp can then proceed based on whether the authentication was successful, rejected, or failed due to an error. Example of AuthRequestParams: ```swift extension AuthRequestParams { static func stub( domain: String = "yourDappDomain.com", chains: [String] = ["eip155:1", "eip155:137"], nonce: String = "uniqueNonce", uri: String = "https://yourDappDomain.com/login", statement: String? = "I accept the Terms of Service: https://yourDappDomain.com/tos", resources: [String]? = nil, // here your dapp may request authorization with recaps methods: [String]? = ["personal_sign", "eth_sendTransaction"] ) -> AuthRequestParams { return try! AuthRequestParams( domain: domain, chains: chains, nonce: nonce, uri: uri, statement: statement, resources: resources, methods: methods ) } } ``` #### Send Request to the Wallet Once the session has been established `sessionSettlePublisher` will publish an event. Your dApp can start requesting wallet now. ```Swift let method = "personal_sign" let walletAddress = "0x9b2055d370f73ec7d8a03e965129118dc8f5bf83" // This should match the connected address let requestParams = AnyCodable(["0x4d7920656d61696c206973206a6f686e40646f652e636f6d202d2031363533333933373535313531", walletAddress]) let request = Request(topic: session.topic, method: method, params: requestParams, chainId: Blockchain(chainId)!) try await Sign.instance.request(params: request) ``` When wallet respond `sessionResponsePublisher` will publish an event so you can verify the response. #### Extending a Session By default, session lifetime is set for 7 days and after that time user's session will expire. But if you consider that a session should be extended you can call: ```Swift try await Sign.instance.extend(topic: session.topic) ``` Above method will extend a user's session to a week. #### Where to go from here * Try our [Example dApp](https://github.com/reown-com/reown-swift/tree/main/Example) that is part of [WalletConnectSwiftV2 repository](https://github.com/reown-com/reown-swift). * Build API documentation in XCode: go to Product -> Build Documentation #### **Initialization** ```kotlin val projectId = "" // Get Project ID at https://cloud.reown.com/ val connectionType = ConnectionType.AUTOMATIC or ConnectionType.MANUAL val appMetaData = Core.Model.AppMetaData( name = "Dapp Name", description = "Dapp Description", url = "Dapp URL", icons = /*list of icon url strings*/, redirect = "kotlin-dapp-wc:/request" // Custom Redirect URI ) CoreClient.initialize(projectId = projectId, connectionType = connectionType, application = this, metaData = appMetaData) val init = Sign.Params.Init(core = CoreClient) SignClient.initialize(init) { error -> // Error will be thrown if there's an issue during initialization } ``` The Dapp client is responsible for initiating the connection with wallets and defining the required namespaces (CAIP-2) from the Wallet and is also in charge of sending requests. To initialize the Sign client, create a `Sign.Params.Init` object in the Android Application class with the Core Client. The `Sign.Params.Init` object will then be passed to the `SignClient` initialize function. # # **Dapp** #### **SignClient.DappDelegate** ```kotlin val dappDelegate = object : SignClient.DappDelegate { override fun onSessionApproved(approvedSession: Sign.Model.ApprovedSession) { // Triggered when Dapp receives the session approval from wallet } override fun onSessionRejected(rejectedSession: Sign.Model.RejectedSession) { // Triggered when Dapp receives the session rejection from wallet } fun onSessionAuthenticateResponse(sessionAuthenticateResponse: Sign.Model.SessionAuthenticateResponse) { // Triggered when Dapp receives the session authenticate response from wallet } override fun onSessionUpdate(updatedSession: Sign.Model.UpdatedSession) { // Triggered when Dapp receives the session update from wallet } override fun onSessionExtend(session: Sign.Model.Session) { // Triggered when Dapp receives the session extend from wallet } override fun onSessionEvent(sessionEvent: Sign.Model.SessionEvent) { // Triggered when the peer emits events that match the list of events agreed upon session settlement } override fun onSessionDelete(deletedSession: Sign.Model.DeletedSession) { // Triggered when Dapp receives the session delete from wallet } override fun onSessionRequestResponse(response: Sign.Model.SessionRequestResponse) { // Triggered when Dapp receives the session request response from wallet } override fun onProposalExpired(proposal: Modal.Model.ExpiredProposal) { // Triggered when a proposal becomes expired } override fun onRequestExpired(request: Modal.Model.ExpiredRequest) { // Triggered when a request becomes expired } override fun onConnectionStateChange(state: Sign.Model.ConnectionState) { //Triggered whenever the connection state is changed } override fun onError(error: Sign.Model.Error) { // Triggered whenever there is an issue inside the SDK } } SignClient.setDappDelegate(dappDelegate) ``` The SignClient needs a `SignClient.DappDelegate` passed to it for it to be able to expose asynchronously updates sent from the Wallet. # #### **Connect** ```kotlin val namespace: String = /*Namespace identifier, see for reference: https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md#syntax*/ val chains: List = /*List of chains that wallet will be requested for*/ val methods: List = /*List of methods that wallet will be requested for*/ val events: List = /*List of events that wallet will be requested for*/ val requiredNamespaces: Map = mapOf(namespace, Sign.Model.Namespaces.Proposal(accounts, methods, events)) /*Required namespaces to setup a session*/ val optionalNamespaces: Map = mapOf(namespace, Sign.Model.Namespaces.Proposal(accounts, methods, events)) /*Optional namespaces to setup a session*/ val pairing: Core.Model.Pairing = /*Either an active or inactive pairing*/ val connectParams = Sign.Params.Connect(requiredNamespaces, optionalNamespaces, pairing) fun SignClient.connect(connectParams, { onSuccess -> /*callback that returns letting you know that you have successfully initiated connecting*/ }, { error -> /*callback for error while trying to initiate a connection with a peer*/ } ) ``` More about optional and required namespaces can be found [here](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-25.md) # #### **Authenticate** The authenticate() method enhances the WalletConnect protocol, offering EVM dApps a sophisticated mechanism to request wallet authentication and simultaneously establish a session. This innovative approach not only authenticates the user but also facilitates a seamless session creation, integrating the capabilities defined by ERC-5573, also known as ReCaps. Capabilities are specified through ReCap URIs in the resources field of the Sign.Params.Authenticate, which translate to human-readable consent in the SIWE message, detailing the actions a dApp is authorized to undertake. To initiate an authentication and authorization request, a dApp invokes the authenticate() method, passing in parameters that include desired capabilities as outlined in EIP-5573. The method generates a pairing URI for user interaction, facilitating a streamlined authentication and consent process. Example of initiating an authentication request with ReCaps: ```kotlin val authenticateParams = Sign.Params.Authenticate( domain = "your.domain", chains = listof("eip155:1", "eip155:137"), methods = listOf("personal_sign", "eth_signTypedData"), uri = "https://yourDappDomain.com/login", nonce = randomNonce, statement = "Sign in with wallet.", resources = null, // here your dapp may request authorization with recaps ) SignClient.authenticate(authenticateParams, onSuccess = { url -> //Handle authentication URI. Show as a QR code a send via deeplink }, onError = { error -> //Handle error } ) ``` Once you have sent an authentication request, await for responses from wallets. Responses will indicate whether the authentication request was approved or rejected. Use the onSessionAuthenticateResponse callback to receive a response: ```kotlin fun onSessionAuthenticateResponse(sessionAuthenticateResponse: Sign.Model.SessionAuthenticateResponse) { // Triggered when Dapp receives the session authenticate response from wallet if (sessionAuthenticateResponse is Sign.Model.SessionAuthenticateResponse.Result) { if (sessionAuthenticateResponse.session != null) { // Authentication successful, session established } else { // Authentication successful, but no session created (SIWE-only flow) } } else { // Authentication request was rejected or failed } } ``` # #### **Get List of Settled Sessions** ```kotlin SignClient.getListOfSettledSessions() ``` To get a list of the most current settled sessions, call `SignClient.getListOfSettledSessions()` which will return a list of type `Session`. # #### **Get list of pending session requests for a topic** ```kotlin SignClient.getPendingRequests(topic: String) ``` To get a list of pending session requests for a topic, call `SignClient.getPendingRequests()` and pass a topic which will return a `PendingRequest` object containing requestId, method, chainIs and params for pending request. #### Initialization To create an instance of `SignClient`, you need to pass in the core and metadata parameters. ```dart SignClient signClient = await SignClient.createInstance( relayUrl: 'wss://relay.walletconnect.com', // The relay websocket URL, leave blank to use the default projectId: '123', metadata: PairingMetadata( name: 'dapp (Requester)', description: 'A dapp that can request that transactions be signed', url: 'https://walletconnect.com', icons: ['https://avatars.githubusercontent.com/u/37784886'], ), ); ``` #### Connection To connect with specific parameters and display the returned URI, use `connect` with the required namespaces. ```dart ConnectResponse response = await signClient.connect( requiredNamespaces: { 'eip155': RequiredNamespace( chains: ['eip155:1'], // Ethereum chain methods: ['eth_signTransaction'], // Requestable Methods ), 'kadena': RequiredNamespace( chains: ['kadena:mainnet01'], // Kadena chain methods: ['kadena_quicksign_v1'], // Requestable Methods ), } ); Uri? uri = response.uri; ``` You will use that URI to display a QR code or handle a deep link. We recommend not handling deep linking yourself. If you want to deep link, then use the [walletconnect\_modal\_flutter](https://pub.dev/packages/walletconnect_modal_flutter) package. #### Session Data Once you've displayed the URI you can wait for the future and hide the QR code once you've received session data. ```dart final SessionData session = await response.session.future; ``` #### Request Signatures Once the session had been created, you can request signatures. ```dart final signature = await signClient.request( topic: session.topic, chainId: 'eip155:1', request: SessionRequestParams( method: 'eth_signTransaction', params: 'json serializable parameters', ), ); ``` #### Respond to Events You can also respond to events from the wallet, like chain changed, using `onSessionEvent` and `registerEventHandler`. ```dart signClient.onSessionEvent.subscribe((SessionEvent? session) { // Do something with the event }); signClient.registerEventHandler( namespace: 'kadena', event: 'kadena_transaction_updated', ); ``` # To Test Run tests using `flutter test`. Expected flutter version is: >`3.3.10` # Useful Commands * `flutter pub run build_runner build --delete-conflicting-outputs` - Regenerates JSON Generators * `flutter doctor -v` - get paths of everything installed. * `flutter pub get` * `flutter upgrade` * `flutter clean` * `flutter pub cache clean` * `flutter pub deps` * `flutter pub run dependency_validator` - show unused dependencies and more * `dart format lib/* -l 120` * `flutter analyze` #### Setup First you must setup `SignClientOptions` which stores both the `ProjectId` and `Metadata`. You may also optionally specify the storage module to use. By default, the `FileSystemStorage` module is used if none is specified. ```csharp var dappOptions = new SignClientOptions() { ProjectId = "39f3dc0a2c604ec9885799f9fc5feb7c", Metadata = new Metadata() { Description = "An example dapp to showcase WalletConnectSharpv2", Icons = new[] { "https://walletconnect.com/meta/favicon.ico" }, Name = "WalletConnectSharpv2 Dapp Example", Url = "https://walletconnect.com" }, // Uncomment to disable persistent storage // Storage = new InMemoryStorage() }; ``` Then, you must setup the `ConnectOptions` which define what blockchain, RPC methods and events your dapp will use. *C# Constructor* ```csharp var dappConnectOptions = new ConnectOptions() { RequiredNamespaces = new RequiredNamespaces() { { "eip155", new RequiredNamespace() { Methods = new[] { "eth_sendTransaction", "eth_signTransaction", "eth_sign", "personal_sign", "eth_signTypedData", }, Chains = new[] { "eip155:1" }, Events = new[] { "chainChanged", "accountsChanged", } } } } }; ``` *Builder Functions Style* ```csharp var dappConnectOptions1 = new ConnectOptions() .RequireNamespace("eip155", new RequiredNamespace() .WithMethod("eth_sendTransaction") .WithMethod("eth_signTransaction") .WithMethod("eth_sign") .WithMethod("personal_sign") .WithMethod("eth_signTypedData") .WithChain("eip155:1") .WithEvent("chainChanged") .WithEvent("accountsChanged") ); ``` With both options defined, you can initialize and connect the SDK. ```csharp var dappClient = await WalletConnectSignClient.Init(dappOptions); var connectData = await dappClient.Connect(dappConnectOptions); ``` You can grab the `Uri` for the connection request from `connectData`. ```csharp ExampleShowQRCode(connectData.Uri); ``` Then await connection approval using the `Approval` Task object. ```csharp Task sessionConnectTask = connectData.Approval; SessionStruct sessionData = await sessionConnectTask; // or // SessionStruct sessionData = await connectData.Approval; ``` This `Task` will return the `SessionStruct` when the session was approved, or throw an exception when the session request has either * Timed out * Been Rejected #### Connected Address To get the currently connected address, use the following function ```csharp public class Caip25Address { public string Address; public string ChainId; } public Caip25Address GetCurrentAddress(string chain) { if (string.IsNullOrWhiteSpace(chain)) return null; var defaultNamespace = currentSession.Namespaces[chain]; if (defaultNamespace.Accounts.Length == 0) return null; var fullAddress = defaultNamespace.Accounts[0]; var addressParts = fullAddress.Split(":"); var address = addressParts[2]; var chainId = string.Join(':', addressParts.Take(2)); return new Caip25Address() { Address = address, ChainId = chainId, }; } public Caip25Address GetCurrentAddress() { var currentSession = dappClient.Session.Get(dappClient.Session.Keys[0]); var defaultChain = currentSession.Namespaces.Keys.FirstOrDefault(); if (string.IsNullOrWhiteSpace(defaultChain)) return null; return GetCurrentAddress(defaultChain); } ``` #### WalletConnect Methods All sign methods require the `topic` of the session to be given. This can be found in the `SessionStruct` object given when a session has been given approval by the user. ```csharp var sessionTopic = sessionData.Topic; ``` ##### Update Session Update a session, adding/removing additional namespaces in the given topic. ```csharp var newNamespaces = new Namespaces(...); var request = await dappClient.UpdateSession(sessionTopic, newNamespaces); await request.Acknowledged(); ``` ##### Extend Session Extend a session's expiry time so the session remains open ```csharp var request = await dappClient.Extend(sessionTopic); await request.Acknowledged(); ``` ##### Ping Send a ping to the session ```csharp var request = await dappClient.Ping(sessionTopic); await request.Acknowledged(); ``` #### Session Requests Sending session requests as a dapp requires to build the request **and** response classes that the session request `params` will be structured. C# is a statically typed language, so these types must be given whenever you do a session request (or do any querying for session requests). Currently, **WalletConnectSharp does not automatically assume the object type for `params` is an array**. This is very important, since most EVM RPC requests have `params` as an array type. **Use `List` to workaround this**. For example, for `eth_sendTransaction`, use `List` instead of `Transaction`. Newtonsoft.Json is used for JSON serialization/deserialization, therefore you can use Newtonsoft.Json attributes when defining fields in your request/response classes. ##### Building a Request type Create a class for the request and populate it with the JSON properties the request object has. For this example, we will use `eth_sendTransaction` The `params` field for `eth_sendTransaction` has the object type ```csharp using Newtonsoft.Json; public class Transaction { public string from; // Newtonsoft.Json attributes can be used [JsonProperty("to")] public string To; [JsonProperty("gas", NullValueHandling = NullValueHandling.Ignore)] public string Gas; // Properties have limited support [JsonProperty("gasPrice", NullValueHandling = NullValueHandling.Ignore)] public string GasPrice { get; set; } [JsonProperty("value")] public string Value { get; set; } [JsonProperty("data", NullValueHandling = NullValueHandling.Ignore)] public string Data { get; set; } = "0x"; } ``` [the `params` field is an array of this object](https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_sendtransaction) ```json params: [ { from: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", to: "0xd46e8dd67c5d32be8058bb8eb970870f07244567", gas: "0x76c0", // 30400 gasPrice: "0x9184e72a000", // 10000000000000 value: "0x9184e72a", // 2441406250 data: "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675", }, ] ``` Now, let's define the actual request class we'll use in `dappClient.Request` ```csharp [RpcMethod("eth_sendTransaction"), RpcRequestOptions(Clock.ONE_MINUTE, 99997)] public class EthSendTransaction : List { public EthSendTransaction(params Transaction[] transactions) : base(transactions) { } } ``` The `RpcMethod` class attributes defines the rpc method this request uses. The `RpcRequestOptions` class attributes define the expiry time and tag attached to the request. **Both of these attributes are required** We use `List` since the `params` field for `eth_sendTransaction` is actually sent as an object array. If the `params` field was a normal object, then we could use `Transaction` or define the fields directly into this class. ##### Sending a request The response type for `eth_sendTransaction` is a `string`, so no response type is required to be made. You only need to create a response type if the response type is a custom object. ```csharp var wallet = GetCurrentAddress(); var result = new EthSendTransaction(new Transaction() { From = wallet.Address, To = wallet.Address, Value = "0" }); // Returns the transaction hash or throws an error string result = await dappClient.Request(sessionTopic, request, wallet.ChainId); ``` #### Disconnecting To disconnect a session, use the `Disconnect` function. You may optional provide a reason for the disconnect ```csharp await dappClient.Disconnect(sessionTopic); // or await dappClient.Disconnect(sessionTopic, Error.FromErrorType(ErrorType.USER_DISCONNECTED)); ``` #### Subscribe to session events ```csharp dappClient.SubscribeToSessionEvent("chainChanged", OnChainChanged); ``` WalletConnectUnity is a wrapper for WalletConnectSharp. It simplifies managing a single active session, addressing a common challenge with the original library. #### Features of WalletConnectUnity 1. **Simplified Session Management**: WalletConnectSharp is designed to support multiple sessions, requiring developers to manually track and restore the active session. WalletConnectUnity simplifies this process by focusing on a single session, making it easier to manage session restoration. 2. **Session Restoration**: WalletConnectUnity includes methods to easily access and restore the active session from storage. 3. **Deep Linking Support**: WalletConnectUnity automatically handles deep linking for mobile and desktop wallets. 4. **QR Code Generation**: WalletConnectUnity provides a utility for generating QR codes. #### Usage To use WalletConnectUnity in your project: 1. Fill in the Project ID and Metadata fields in the `Assets/WalletConnectUnity/Resources/WalletConnectProjectConfig` asset. * If you don’t have a Project ID, you can create one at [Reown Cloud](https://cloud.reown.com). * The `Redirect` fields are optional. They are used to redirect the user back to your app after they approve or reject the session. 2. Initialize `WalletConnect` and connect the wallet: ```csharp // Initialize singleton await WalletConnect.Instance.InitializeAsync(); // Or handle instancing manually var walletConnectUnity = new WalletConnect(); await walletConnectUnity.InitializeAsync(); // Try to resume the last session var sessionResumed = await WalletConnect.Instance.TryResumeSessionAsync(); if (!sessionResumed) { var connectedData = await WalletConnect.Instance.ConnectAsync(connectOptions); // Create QR code texture var texture = WalletConnectUnity.Core.Utils.QRCode.EncodeTexture(connectedData.Uri); // ... Display QR code texture // Wait for wallet approval await connectedData.Approval; } ``` All features of WalletConnectSharp are accessible in WalletConnectUnity. For complex scenarios, the `SignClient` can be accessed directly through `WalletConnect.SignClient`. Refer to the `.NET` documentation for details on using the Sign API within WalletConnectUnity. The usage of the WalletConnectSharp.Sign API remains consistent with `.NET`. # Introduction Source: https://docs.reown.com/advanced/api/sign/overview WalletConnect Sign is a remote signer protocol to communicate securely between web3 wallets and dapps. The protocol establishes a remote pairing between two apps and/or devices using a Relay server to relay payloads. These payloads are symmetrically encrypted through a shared key between the two peers. The pairing is initiated by one peer displaying a QR Code or deep link with a standard WalletConnect URI and is established when the counter-party approves this pairing request. **Don't have a project ID?** Head over to Reown Cloud and create a new project now! ## Installation `bash npm npm install @walletconnect/sign-client ` `bash Yarn yarn add @walletconnect/sign-client ` `bash Bun bun add @walletconnect/sign-client ` `bash pnpm pnpm add @walletconnect/sign-client ` For Node.js, the WalletConnect SignClient additionally requires `lokijs` to manage storage internally. `bash npm npm install --save @walletconnect/sign-client lokijs@1.x ` `bash Yarn yarn add @walletconnect/sign-client lokijs@1.x ` `bash Bun bun add --save @walletconnect/sign-client lokijs@1.x ` `bash pnpm pnpm add @walletconnect/sign-client lokijs@1.x ` You can add a WalletConnect SDK to your project with Swift Package Manager. In order to do that: 1. Open XCode 2. Go to File -> Add Packages 3. Paste the repo GitHub URL: [https://github.com/reown-com/reown-swift](https://github.com/reown-com/reown-swift) 4. Tap Add Package 5. Select WalletConnect check mark 1. Update Cocoapods spec repos. Type in terminal `pod repo update` 2. Initialize Podfile if needed with `pod init` 3. Add pod to your Podfile: ```ruby pod 'WalletConnectSwiftV2' ``` 4. Install pods with `pod install` If you encounter any problems during package installation, you can specify the exact path to the repository ```ruby pod 'WalletConnectSwiftV2', :git => 'https://github.com/reown-com/reown-swift.git', :tag => '1.0.5' ``` Kotlin implementation of WalletConnect v2 Sign protocol for Android applications. This SDK is developed in Kotlin and usable in both Java and Kotlin files. * Android Core ![Maven Central](https://img.shields.io/maven-central/v/com.walletconnect/android-core) * Sign ![Maven Central](https://img.shields.io/maven-central/v/com.walletconnect/sign) #### Requirements * Android min SDK 23 * Java 11 #### Installation root/build.gradle.kts: ```gradle allprojects { repositories { mavenCentral() maven { url "https://jitpack.io" } } } ``` app/build.gradle.kts ```gradle implementation("com.walletconnect:android-core:release_version") implementation("com.walletconnect:sign:release_version") ``` Install the WalletConnect client package. ```dart flutter pub add walletconnect_flutter_v2 ``` #### Platform Specific Setup Depending on your platform, you will have to add different permissions to get the package to work. #### MacOS Add the following to your `DebugProfile.entitlements` and `Release.entitlements` files so that it can connect to the WebSocket server. ```xml com.apple.security.network.client ``` #### Install via Packages Install the WalletConnect Sign Client package via Nuget. ```shell dotnet add package WalletConnect.Sign ``` WalletConnectUnity.Core is a Unity package that provides a client implementation of the WalletConnect v2 protocol. It is built on top of the [WalletConnectSharp.Sign](https://github.com/WalletConnect/WalletConnectSharp) library, which provides the core functionality for the WalletConnect protocol. #### Prerequisites * Unity 2021.3 or above * IL2CPP code stripping level: Minimal (or lower) #### Package Installation To install packages via OpenUPM, you need to have [Node.js](https://nodejs.org/en/) and [openupm-cli](https://openupm.com/docs/getting-started.html#installing-openupm-cli) installed. Once you have them installed, you can run the following commands: ```bash openupm add com.walletconnect.core ``` 1. Open `Advanced Project Settings` from the gear ⚙ menu located at the top right of the Package Manager’s toolbar 2. Add a new scoped registry with the following details: * Name: `OpenUPM` * URL: `https://package.openupm.com` * Scope(s): `com.walletconnect` 3. Press plus ➕ and then `Save` buttons 4. In the Package Manager windows open the add ➕ menu from the toolbar 5. Select `Add package by name...` 6. Enter the package name: * `com.walletconnect.core` 7. Press `Add` button 1. Open the add ➕ menu in the Package Manager’s toolbar 2. Select `Add package from git URL...` 3. Enter the package URL: **WalletConnectUnity Core** ``` https://github.com/WalletConnect/WalletConnectUnity.git?path=Packages/com.walletconnect.core ``` 4. Press `Add` button It's possible to lock the version of the package by adding `#{version}` at the end of the git URL, where `#{version}` is the git tag of the version you want to use. For example, to install version `1.0.1` of WalletConnectUnity Modal, use the following URL: ``` https://github.com/WalletConnect/WalletConnectUnity.git?path=Packages/com.walletconnect.core#core/1.0.1 ``` #### WebGL Due to WebGL's single-threaded nature, certain asynchronous operations like `Task.Run`, `Task.ContinueWith`, `Task.Delay`, and `ConfigureAwait(false)` are not natively supported. To enable these operations in WebGL builds, an additional third-party package, [WebGLThreadingPatcher](https://github.com/VolodymyrBS/WebGLThreadingPatcher), is required. This package modifies the Unity WebGL build to delegate work to the `SynchronizationContext`, allowing these operations to be executed on the same thread without blocking the main application. Please note that all tasks are still executed on a single thread, and any blocking calls will freeze the entire application. The [WebGLThreadingPatcher](https://github.com/VolodymyrBS/WebGLThreadingPatcher) package can be added via git URL: ``` https://github.com/VolodymyrBS/WebGLThreadingPatcher.git ``` # Smart Contract Wallet Usage Source: https://docs.reown.com/advanced/api/sign/smart-contract-wallet-usage This section is limited to just for Web/JavaScript at the present moment Smart Contract wallets like [Argent](https://argent.gitbook.io/argent/wallet-connect-and-argent) are fully supported by the WalletConnect protocol. However, there are some considerations to be taken when integrating WalletConnect in your dapp for Smart Contract wallets, regarding how the accounts are exposed in the session, message signatures are returned, and transactions are broadcasted. ### Accounts When you connect your dapp to a smart contract wallet, you will receive the **smart account address** for the wallet. This is not to be confused with the **delegate keys** that are used to sign messages and transactions. You can detect smart contract wallets by verifying on-chain if the exposed account address has any associated code deployed. ```javascript import { providers, utils } from "ethers"; const provider = new providers.JsonRpcProvider(rpcUrl); const bytecode = await provider.getCode(address); const isSmartContract = bytecode && utils.hexStripZeros(bytecode) !== "0x"; ``` ```javascript import Web3 from "web3"; const web3 = new Web3(rpcUrl); const bytecode = await web3.eth.getCode(address); const isSmartContract = bytecode && utils.hexStripZeros(bytecode) !== "0x"; ``` Smart contract wallets are essentially multi-signature wallets that use multiple keys to authorize operations on behalf of these smart contract accounts, so you will have to take into consideration how messages and transactions are handled by your dapp. ## Messages Normally, when verifying signatures from "normal" accounts, which are Externally Owned Accounts (EOAs), you would use an ECDSA method called `ecrecover()` to retrieve the corresponding public key, which will then map to an address. In the case of Smart Contract Wallets, you are not able to sign a message with the smart contract account. Therefore, the standard [EIP-1271](https://eips.ethereum.org/EIPS/eip-1271) was defined to outline a validation method which can be called on-chain, labeled `isValidSignature()`. ```text contract ERC1271 { bytes4 constant internal MAGICVALUE = 0x1626ba7e; function isValidSignature( bytes32 _hash, bytes memory _signature ) public view returns (bytes4 magicValue); } ``` This method has a single parameter `_hash` which should be [EIP-191](https://eips.ethereum.org/EIPS/eip-191) compliant and can be computed using: ```javascript import { utils } from "ethers"; const hash = utils.hashMessage(message); ``` ```javascript import Web3 from "web3"; const web3 = new Web3(rpcUrl); const hash = web3.eth.accounts.hashMessage(message); ``` ## Transactions Smart Contract wallets, like [Argent](https://argent.gitbook.io/argent/wallet-connect-and-argent), commonly use the concept of meta transactions. These are a specific type of transaction that is signed by one or more key pairs but is submitted to the Ethereum network by a relayer. The relayer pays the gas fee (in ETH), and the wallet will refund the relayer (in ETH or ERC20 tokens) up to an amount signed by the wallet's owner. From your dapp's perspective, this is managed by the mobile wallet application. Your dapp will submit a regular `{ to, value, data }` transaction to the web3 provider. This transaction will be transmitted to the mobile wallet application through WalletConnect. The mobile wallet will transform the data into a meta transaction: * `to` will be the `RelayerManager` contract address * `data` will be the encoded data of the call to the `execute()` method with the relevant parameters Your dapp will receive the transaction hash in order to monitor the status of the transaction, and events will be emitted as usual. The relayer has the ability to replay a transaction with a higher gas price due to fluctuating network conditions. The transaction hash is modified, and the dapp will not be aware of the new transaction hash. One solution could be for your dapp to observe a specific event being emitted instead of the transaction status. There is currently work on standardizing events for transactions replies that has been recently proposed via [EIP-2831](https://eips.ethereum.org/EIPS/eip-2831). We hope to improve our SDKs in the future to take this standard into account. # Wallet Usage Source: https://docs.reown.com/advanced/api/sign/wallet-usage Sign API establishes a session between a wallet and a dapp in order to expose a set of blockchain accounts that can sign transactions or messages using a secure remote JSON-RPC transport with methods and events. **Don't have a project ID?** Head over to Reown Cloud and create a new project now! This library is compatible with Node.js, browsers and React Native applications (Node.js modules require polyfills for React Native). #### Migrating from v1.x **We recommend you install v1 and v2 together for maximum compatibility.** If your wallet already uses `@walletconnect/client@1.x.x`, you should be able to add `@walletconnect/sign-client@2.x.x` without any issues. If you experience dependency clashes or you require both `@walletconnect/types@1.x.x` and `@walletconnect/types@2.x.x` in parallel in your wallet's top-level dependencies, please refer to the [`legacy` packages](https://github.com/WalletConnect/walletconnect-legacy/tree/main/packages) which were published explicitly for this purpose. In the above scenario, you would replace `@walletconnect/types@1.x.x` with `@walletconnect/legacy-types` and then install `@walletconnect/types@2.x.x`. #### Initializing the client Initialize client as a controller using [your Project ID](../../cloud/relay). ```js const signClient = await SignClient.init({ projectId: "", // optional parameters relayUrl: "", metadata: { name: "Wallet name", description: "A short description for your wallet", url: "", icons: [""], }, }); ``` #### Setting up event listeners WalletConnect v2.0 emits events related to the current session. The listeners listed in the following code snippet represent typical events in a session's lifecycle that you can listen for to synchronise your application accordingly. Example: when a `session_delete` event is emitted, it makes sense to change the UI from an active session state to an inactive/disconnected state. **1. Add listeners for desired `SignClient` events.** To listen to pairing-related events, please follow the guidance for [Pairing API event listeners.](../core/pairing) ```ts signClient.on("session_proposal", (event) => { // Show session proposal data to the user i.e. in a modal with options to approve / reject it interface Event { id: number; params: { id: number; expiry: number; relays: Array<{ protocol: string; data?: string; }>; proposer: { publicKey: string; metadata: { name: string; description: string; url: string; icons: string[]; }; }; requiredNamespaces: Record< string, { chains: string[]; methods: string[]; events: string[]; } >; pairingTopic?: string; }; } }); signClient.on("session_event", (event) => { // Handle session events, such as "chainChanged", "accountsChanged", etc. interface Event { id: number; topic: string; params: { event: { name: string; data: any; }; chainId: string; }; } }); signClient.on("session_request", (event) => { // Handle session method requests, such as "eth_sign", "eth_sendTransaction", etc. interface Event { id: number; topic: string; params: { request: { method: string; params: any; }; chainId: string; }; } }); signClient.on("session_ping", (event) => { // React to session ping event interface Event { id: number; topic: string; } }); signClient.on("session_delete", (event) => { // React to session delete event interface Event { id: number; topic: string; } }); ``` # Pairing and session permissions #### URI The pairing proposal between a wallet and a dapp is made using an [URI](https://specs.walletconnect.com/2.0/specs/clients/core/pairing/). In WalletConnect v2.0 the session and pairing are decoupled from each other. This means that a URI is shared to construct a pairing proposal, and only after settling the pairing the dapp can propose a session using that pairing. In simpler words, the dapp generates an URI that can be used by the wallet for pairing. #### Namespaces The `namespaces` parameter is used to specify the namespaces and chains that are intended to be used in the session. The following is an example: ```js namespaces: { eip155: { accounts: ["eip155:1:0x0000000000..., eip155:2:0x0000000000..."], methods: ["personal_sign", "eth_sendTransaction"], events: ["accountsChanged"] }, }; ``` #### Pairing with `uri` To create a pairing proposal, simply pass the `uri` received from the dapp into the `signClient.core.pairing.pair()` function. As of 2.0.0 (stable), calling pairing-specific methods (such as `signClient.pair()`) directly on `signClient` will continue to work, but is considered deprecated and will be removed in a future major version. It is recommended to instead call these methods directly via the [Pairing API.](../core//pairing), e.g.: `signClient.core.pairing.pair()`. ```js // This will trigger the `session_proposal` event await signClient.core.pairing.pair({ uri }); // Approve session proposal, use id from session proposal event and respond with namespace(s) that satisfy dapps request and contain approved accounts const { topic, acknowledged } = await signClient.approve({ id: 123, namespaces: { eip155: { accounts: ["eip155:1:0x0000000000..."], methods: ["personal_sign", "eth_sendTransaction"], events: ["accountsChanged"], }, }, }); // Optionally await acknowledgement from dapp const session = await acknowledged(); // Or reject session proposal await signClient.reject({ id: 123, reason: { code: 1, message: "rejected", }, }); ``` #### Pairing with QR Codes To facilitate better user experience, it is possible to pair wallets with dapps by scanning QR codes. This can be implemented by using any QR code scanning library (example, [react-qr-reader](https://www.npmjs.com/package/react-qr-reader)). After scanning the QR code, pass the obtained `uri` into the `signClient.pair()` function. A useful reference for implementing QR codes for pairing is the [react wallet example](https://github.com/WalletConnect/web-examples/blob/main/advanced/wallets/react-wallet-v2/). ## Authenticated Session 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 (SIWE) message, enhanced by ReCaps (ReCap Capabilities). 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. 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. #### Handling 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. ```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) }); ``` #### Populate Authentication Payload ```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 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 const message = walletKit.formatAuthMessage({ request: authPayload, iss }); // Present the authentication message to the user ... ``` #### Approving Authentication Requests **Note** 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. ```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) const auth = buildAuthObject( authPayload, { t: "eip191", s: signature, }, iss ); // Approve await walletKit.approveSessionAuthenticate({ id: payload.id, auths: [auth], }); // Approach 2 // Note that you can also sign multiple messages for every requested chain/address pair const auths = []; authPayload.chains.forEach(async (chain) => { const message = walletKit.formatAuthMessage({ request: authPayload, iss: `${chain}:${cryptoWallet.address}`, }); const signature = await cryptoWallet.signMessage(message); const auth = buildAuthObject( authPayload, { t: "eip191", // signature type s: signature, }, `${chain}:${cryptoWallet.address}` ); auths.push(auth); }); // Approve await walletKit.approveSessionAuthenticate({ id: payload.id, auths, }); ``` #### Rejecting Authentication Requests If the authentication request cannot be approved or if the user chooses to reject it, use the rejectSession method. ```typescript import { getSdkError } from "@walletconnect/utils"; await walletKit.rejectSessionAuthenticate({ id: payload.id, reason: getSdkError("USER_REJECTED"), // or choose a different reason if applicable }); ``` #### Configure Networking and Pair Clients Confirm you have configured the Network and Pair Client first * [Networking](/advanced/api/core/relay) * [Pairing](/advanced/api/core/pairing) #### Configure Sign Client In order to initialize a client, call a `configure` method on the Sign instance ```swift Sign.configure(crypto: CryptoProvider) ``` #### Subscribe for Sign Publishers The following publishers are available to subscribe: ```swift public var sessionsPublisher: AnyPublisher<[Session], Never> public var sessionProposalPublisher: AnyPublisher<(proposal: Session.Proposal, context: VerifyContext?), Never> public var sessionRequestPublisher: AnyPublisher<(request: Request, context: VerifyContext?), Never> public var socketConnectionStatusPublisher: AnyPublisher public var sessionSettlePublisher: AnyPublisher public var sessionDeletePublisher: AnyPublisher<(String, Reason), Never> public var sessionResponsePublisher: AnyPublisher public var sessionRejectionPublisher: AnyPublisher<(Session.Proposal, Reason), Never> public var sessionUpdatePublisher: AnyPublisher<(sessionTopic: String, namespaces: [String : SessionNamespace]), Never> public var sessionEventPublisher: AnyPublisher<(event: Session.Event, sessionTopic: String, chainId: Blockchain?), Never> public var sessionUpdateExpiryPublisher: AnyPublisher<(sessionTopic: String, expiry: Date), Never> ``` #### Connect Clients Your Wallet should allow users to scan a QR code generated by dapps. You are responsible for implementing it on your own. For testing, you can use our test dapp at: [https://react-app.walletconnect.com/](https://react-app.walletconnect.com/), which is v2 protocol compliant. Once you derive a URI from the QR code call `pair` method: ```swift try await Pair.instance.pair(uri: uri) ``` if everything goes well, you should handle following event: ```swift Sign.instance.sessionProposalPublisher .receive(on: DispatchQueue.main) .sink { [weak self] session in self?.verifyDapp(session.context) self?.showSessionProposal(session.proposal) }.store(in: &publishers) ``` Session proposal is a handshake sent by a dapp and it's purpose is to define a session rules. Handshake procedure is defined by [CAIP-25](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-25.md). `Session.Proposal` object conveys set of required `ProposalNamespaces` that contains required blockchains methods and events. Dapp requests with methods and wallet will emit events defined in namespaces. `VerifyContext` provides a domain verification information about `Session.Proposal` and `Request`. It consists of origin of a Dapp from where the request has been sent, validation enum that says whether origin is **unknown**, **valid** or **invalid** and verify URL server. To enable or disable verification find the **Verify SDK** toggle in your project [cloud](https://cloud.reown.com). ```swift public struct VerifyContext: Equatable, Hashable { public enum ValidationStatus { case unknown case valid case invalid } public let origin: String? public let validation: ValidationStatus public let verifyUrl: String } ``` The user will either approve the session proposal (with session namespaces) or reject it. Session namespaces must at least contain requested methods, events and accounts associated with proposed blockchains. Accounts must be provided according to [CAIP10](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-10.md) specification and be prefixed with a chain identifier. chain\_id + : + account\_address. You can find more on blockchain identifiers in [CAIP2](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md). Our `Account` type meets the criteria. ``` let account = Account("eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb")! ``` Accounts sent in session approval must at least match all requested blockchains. Example proposal namespaces request: ```json { "eip155": { "chains": ["eip155:137", "eip155:1"], "methods": ["eth_sign"], "events": ["accountsChanged"] }, "cosmos": { "chains": ["cosmos:cosmoshub-4"], "methods": ["cosmos_signDirect"], "events": ["someCosmosEvent"] } } ``` Example session namespaces response: ```json { "eip155": { "accounts": [ "eip155:137:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb", "eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb" ], "methods": ["eth_sign"], "events": ["accountsChanged"] }, "cosmos": { "accounts": [ "cosmos:cosmoshub-4:cosmos1t2uflqwqe0fsj0shcfkrvpukewcw40yjj6hdc0" ], "methods": ["cosmos_signDirect", "personal_sign"], "events": ["someCosmosEvent", "proofFinalized"] } } ``` #### 💡 AutoNamespaces Builder Utility `AutoNamespaces` is 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 `SessionNamespace` object. ```swift public static func build( sessionProposal: Session.Proposal, chains: [Blockchain], methods: [String], events: [String], accounts: [Account] ) throws -> [String: SessionNamespace] ``` Example usage ```swift do { let sessionNamespaces = try AutoNamespaces.build( sessionProposal: proposal, chains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!], methods: ["eth_sendTransaction", "personal_sign"], events: ["accountsChanged", "chainChanged"], accounts: [ Account(blockchain: Blockchain("eip155:1")!, address: "0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb")!, Account(blockchain: Blockchain("eip155:137")!, address: "0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb")! ] ) try await Sign.instance.approve(proposalId: proposal.id, namespaces: sessionNamespaces) } catch { print(error) } ``` #### Approve Session ```swift Sign.instance.approve( proposalId: "proposal_id", namespaces: sessionNamespaces ) ``` #### Reject Session ```swift Sign.instance.reject( proposalId: "proposal_id", reason: .userRejected ) ``` When session is successfully approved `sessionSettlePublisher` will publish a `Session` ```swift Sign.instance.sessionSettlePublisher .receive(on: DispatchQueue.main) .sink { [weak self] _ in self?.reloadSessions() }.store(in: &publishers) ``` `Session` object represents an active session connection with a dapp. It contains dapp’s metadata (that you may want to use for displaying an active session to the user), namespaces, and expiry date. There is also a topic property that you will use for linking requests with related sessions. You can always query settled sessions from the client later with: ```swift Sign.instance.getSessions() ``` #### Track Sessions When your `Sign` instance receives requests from a peer it will publish a related event. Set a subscription to handle them. To track sessions subscribe to `sessionsPublisher` publisher ```swift Sign.instance.sessionsPublisher .receive(on: DispatchQueue.main) .sink { [self self] (sessions: [Session]) in // Reload UI }.store(in: &publishers) ``` #### Handle Requests from Dapp After the session is established, a dapp will request your wallet's users to sign a transaction or a message. Requests will be delivered by the following publisher. ```swift Sign.instance.sessionRequestPublisher .receive(on: DispatchQueue.main) .sink { [weak self] session in self?.verifyDapp(session.context) self?.showSessionRequest(session.request) }.store(in: &publishers) ``` When a wallet receives a session request, you probably want to show it to the user. It’s method will be in scope of session namespaces. And it’s params are represented by `AnyCodable` type. An expected object can be derived as follows: ```swift if sessionRequest.method == "personal_sign" { let params = try! sessionRequest.params.get([String].self) } else if method == "eth_signTypedData" { let params = try! sessionRequest.params.get([String].self) } else if method == "eth_sendTransaction" { let params = try! sessionRequest.params.get([EthereumTransaction].self) } ``` Now, your wallet (as it owns your user’s private keys) is responsible for signing the transaction. After doing it, you can send a response to a dapp. ```swift let response: AnyCodable = sign(request: sessionRequest) // Implement your signing method try await Sign.instance.respond(topic: request.topic, requestId: request.id, response: .response(response)) ``` #### Update Session If you want to update user session's chains, accounts, methods or events you can use session update method. ```swift try await Sign.instance.update(topic: session.topic, namespaces: newNamespaces) ``` #### Extend Session By default, session lifetime is set for 7 days and after that time user's session will expire. But if you consider that a session should be extended you can call: ```swift try await Sign.instance.extend(topic: session.topic) ``` above method will extend a user's session to a week. #### Disconnect Session For good user experience your wallet should allow users to disconnect unwanted sessions. In order to terminate a session use `disconnect` method. ```swift try await Sign.instance.disconnect(topic: session.topic) ``` ### Authenticated Session An authenticated session represents a secure connection established between a wallet and a dApp after successful authentication. #### Handling Authentication Requests To handle incoming authentication requests, subscribe to the authenticateRequestPublisher. 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. ```swift Sign.instance.authenticateRequestPublisher .receive(on: DispatchQueue.main) .sink { result in // Process the authentication request here. // This involves displaying UI to the user. } .store(in: &subscriptions) // Assuming `subscriptions` is where you store your Combine subscriptions. ``` #### Building Authentication Objects To interact with authentication requests, first build authentication objects (AuthObject). These objects are crucial for approving authentication requests. This involves: **Creating an Authentication Payload** - Generate an authentication payload that matches your application's supported chains and methods. **Formatting Authentication Messages** - Format the authentication message using the payload and the user's account. **Signing the Authentication Message** - Sign the formatted message to create a verifiable authentication object. Example Implementation: ```swift func buildAuthObjects(request: AuthenticationRequest, account: Account, privateKey: String) throws -> [AuthObject] { let requestedChains = Set(request.payload.chains.compactMap { Blockchain($0) }) let supportedChains: Set = [Blockchain("eip155:1")!, Blockchain("eip155:137")!, Blockchain("eip155:69")!] let commonChains = requestedChains.intersection(supportedChains) let supportedMethods = ["personal_sign", "eth_sendTransaction"] var authObjects = [AuthObject]() for chain in commonChains { let accountForChain = Account(blockchain: chain, address: account.address)! let supportedAuthPayload = try Sign.instance.buildAuthPayload( payload: request.payload, supportedEVMChains: Array(commonChains), supportedMethods: supportedMethods ) let formattedMessage = try Sign.instance.formatAuthMessage(payload: supportedAuthPayload, account: accountForChain) let signature = // Assume `signMessage` is a function you've implemented to sign messages. signMessage(message: formattedMessage, privateKey: privateKey) let authObject = try Sign.instance.buildSignedAuthObject( authPayload: supportedAuthPayload, signature: signature, account: accountForChain ) authObjects.append(authObject) } return authObjects } ``` #### Approving Authentication Requests To approve an authentication request, construct AuthObject instances for each supported blockchain, sign the authentication messages, build AuthObjects and call approveSessionAuthenticate with the request ID and the authentication objects. ```swift let session = try await Sign.instance.approveSessionAuthenticate(requestId: requestId, auths: authObjects) ``` **Note** 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. #### Rejecting Authentication Requests If the authentication request cannot be approved or if the user chooses to reject it, use the rejectSession method. ```swift try await Sign.instance.rejectSession(requestId: requestId) ``` #### Where to go from here * Try our example wallet implementation [here](https://github.com/reown-com/reown-swift/tree/main/Example/WalletApp). {/* */} * Build API documentation in XCode: go to Product -> Build Documentation #### **Initialization** ```kotlin val projectId = "" // Get Project ID at https://cloud.reown.com/ val connectionType = ConnectionType.AUTOMATIC or ConnectionType.MANUAL val appMetaData = Core.Model.AppMetaData( name = "Wallet Name", description = "Wallet Description", url = "Wallet URL", icons = /*list of icon url strings*/, redirect = "kotlin-wallet-wc:/request" // Custom Redirect URI ) CoreClient.initialize(projectId = projectId, connectionType = connectionType, application = this, metaData = appMetaData) val init = Sign.Params.Init(core = CoreClient) SignClient.initialize(init) { error -> // Error will be thrown if there's an issue during initialization } ``` The wallet client will always be responsible for exposing accounts (CAPI10 compatible) to a Dapp and therefore is also in charge of signing. To initialize the Sign client, create a `Sign.Params.Init` object in the Android Application class with the Core Client. The `Sign.Params.Init` object will then be passed to the `SignClient`initialize function. # **Wallet** #### **SignClient.WalletDelegate** ```kotlin val walletDelegate = object : SignClient.WalletDelegate { override fun onSessionProposal(sessionProposal: Sign.Model.SessionProposal, verifyContext: Sign.Model.VerifyContext) { // Triggered when wallet receives the session proposal sent by a Dapp } val onSessionAuthenticate: ((Sign.Model.SessionAuthenticate, Sign.Model.VerifyContext) -> Unit)? get() = null // Triggered when wallet receives the session authenticate sent by a Dapp override fun onSessionRequest(sessionRequest: Sign.Model.SessionRequest, verifyContext: Sign.Model.VerifyContext) { // Triggered when a Dapp sends SessionRequest to sign a transaction or a message } override fun onSessionDelete(deletedSession: Sign.Model.DeletedSession) { // Triggered when the session is deleted by the peer } override fun onSessionSettleResponse(settleSessionResponse: Sign.Model.SettledSessionResponse) { // Triggered when wallet receives the session settlement response from Dapp } override fun onSessionUpdateResponse(sessionUpdateResponse: Sign.Model.SessionUpdateResponse) { // Triggered when wallet receives the session update response from Dapp } override fun onConnectionStateChange(state: Sign.Model.ConnectionState) { //Triggered whenever the connection state is changed } override fun onError(error: Sign.Model.Error) { // Triggered whenever there is an issue inside the SDK } } SignClient.setWalletDelegate(walletDelegate) ``` `Sign.Model.VerifyContext` provides a domain verification information about SessionProposal and SessionRequest. It consists of origin of a Dapp from where the request has been sent, validation Enum that says whether origin is VALID, INVALID or UNKNOWN and verify url server. ```kotlin data class VerifyContext( val id: Long, val origin: String, val validation: Model.Validation, val verifyUrl: String ) enum class Validation { VALID, INVALID, UNKNOWN } ``` The SignClient needs a `SignClient.WalletDelegate` passed to it for it to be able to expose asynchronous updates sent from the Dapp. # #### **Session Approval** NOTE: addresses provided in `accounts` array should follow [CAPI10](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-10.md) semantics. ```kotlin val proposerPublicKey: String = /*Proposer publicKey from SessionProposal object*/ val namespace: String = /*Namespace identifier, see for reference: https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md#syntax*/ val accounts: List = /*List of accounts on chains*/ val methods: List = /*List of methods that wallet approves*/ val events: List = /*List of events that wallet approves*/ val namespaces: Map = mapOf(namespace, Sign.Model.Namespaces.Session(accounts, methods, events)) val approveParams: Sign.Params.Approve = Sign.Params.Approve(proposerPublicKey, namespaces) SignClient.approveSession(approveParams) { error -> /*callback for error while approving a session*/ } ``` To send an approval, pass a Proposer's Public Key along with the map of namespaces to the `SignClient.approveSession` function. # #### **Session Rejection** ```kotlin val proposerPublicKey: String = /*Proposer publicKey from SessionProposal object*/ val rejectionReason: String = /*The reason for rejecting the Session Proposal*/ val rejectionCode: String = /*The code for rejecting the Session Proposal*/ For reference use CAIP-25: https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-25.md val rejectParams: Sign.Params.Reject = Reject(proposerPublicKey, rejectionReason, rejectionCode) SignClient.rejectSession(rejectParams) { error -> /*callback for error while rejecting a session*/ } ``` To send a rejection for the Session Proposal, pass a proposerPublicKey, rejection reason and rejection code to the `SignClient.rejectSession` function. # #### **Session Disconnect** ```kotlin val disconnectionReason: String = /*The reason for disconnecting the Session*/ val disconnectionCode: String = /*The code for disconnecting the Session*/ val sessionTopic: String = /*Topic from the Session*/ For reference use CAIP-25: https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-25.md val disconnectParams = Sign.Params.Disconnect(sessionTopic, disconnectionReason, disconnectionCode) SignClient.disconnect(disconnectParams) { error -> /*callback for error while disconnecting a session*/ } ``` To disconnect from a settled session, pass a disconnection reason with code and the Session topic to the `SignClient.disconnect` function. # #### **Respond Request** ```kotlin val sessionTopic: String = /*Topic of Session*/ val jsonRpcResponse: Sign.Model.JsonRpcResponse.JsonRpcResult = /*Settled Session Request ID along with request data*/ val result = Sign.Params.Response(sessionTopic = sessionTopic, jsonRpcResponse = jsonRpcResponse) SignClient.respond(result) { error -> /*callback for error while responding session request*/ } ``` To respond to JSON-RPC method that were sent from Dapps for a session, submit a `Sign.Params.Response` with the session's topic and request ID along with the respond data to the `SignClient.respond` function. #### **Reject Request** ```kotlin val sessionTopic: String = /*Topic of Session*/ val jsonRpcResponseError: Sign.Model.JsonRpcResponse.JsonRpcError = /*Session Request ID along with error code and message*/ val result = Sign.Params.Response(sessionTopic = sessionTopic, jsonRpcResponse = jsonRpcResponseError) SignClient.respond(result) { error -> /*callback for error while responding session request*/ } ``` To reject a JSON-RPC method that was sent from a Dapps for a session, submit a `Sign.Params.Response` with the settled session's topic and request ID along with the rejection data to the `SignClient.respond` function. # #### **Session Update** NOTE: addresses provided in `accounts` array should follow [CAIP10](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-10.md) semantics and syntax. ```kotlin val sessionTopic: String = /*Topic of Session*/ val namespace: String = /*Namespace identifier, see for reference: https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md#syntax*/ val accounts: List = /*List of accounts on authorized chains*/ val methods: List = /*List of methods that wallet approves*/ val events: List = /*List of events that wallet approves*/ val namespaces: Map = mapOf(namespace, Sign.Model.Namespaces.Session(accounts, methods, events)) val updateParams = Sign.Params.Update(sessionTopic, namespaces) SignClient.update(updateParams) { error -> /*callback for error while sending session update*/ } ``` To update a session with namespaces, use `SignClient.Update` to submit a `Sign.Params.Update` object with the session's topic and updated namespace objects (i.e. adding requesting new methods or events, new accounts on authorized chains, or authorizing new chainIds within a multi-chain namespace). # #### **Session Extend** ```kotlin val sessionTopic: String = /*Topic of Session*/ val extendParams = Sign.Params.Extend(sessionTopic = sessionTopic) SignClient.extend(extendParams) { error -> /*callback for error while extending a session*/ } ``` To extend a session, create a `Sign.Params.Extend` object with the session's topic to update the session with to `Sign.Extend`. Session is extended by 7 days. #### **Session Ping** ```kotlin val sessionTopic: String = /*Topic of Session*/ val pingParams = Sign.Params.Ping(sessionTopic) val listener = object : Sign.Listeners.SessionPing { override fun onSuccess(pingSuccess: Model.Ping.Success) { // Topic being pinged } override fun onError(pingError: Model.Ping.Error) { // Error } } SignClient.ping(pingParams, listener) ``` To ping a peer with a session, call `SignClient.ping` with the `Sign.Params.Ping` with a session's topic. If ping is successful, topic is echo'd in listener. # #### **Authenticated Session** An authenticated session represents a secure connection established between a wallet and a dApp after successful authentication. ### Authentication Requests To handle incoming authentication requests, set up SignClient.WalletDelegate. The onSessionAuthenticate callback 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. ```kotlin override val onSessionAuthenticate: ((Wallet.Model.SessionAuthenticate, Wallet.Model.VerifyContext) -> Unit) get() = { sessionAuthenticate, verifyContext -> // Triggered when wallet receives the session authenticate sent by a Dapp // Process the authentication request here // This involves displaying UI to the user } ``` ### Responding Authentication Request To interact with authentication requests, build authentication objects (Sign.Model.Cacao). It involves the following steps: **Creating an Authentication Payload Params** - Generate an authentication payload params that matches your application's supported chains and methods. **Formatting Authentication Messages** - Format the authentication message using the payload and the user's account. **Signing the Authentication Message** - Sign the formatted message to create a verifiable authentication object. Example: ```kotlin override val onSessionAuthenticate: ((Wallet.Model.SessionAuthenticate, Wallet.Model.VerifyContext) -> Unit) get() = { sessionAuthenticate, verifyContext -> val auths = mutableListOf() val authPayloadParams = generateAuthPayloadParams( sessionAuthenticate.payloadParams, supportedChains = listOf("eip155:1", "eip155:137", "eip155:56"), // Note: Only EVM chains are supported supportedMethods = listOf("personal_sign", "eth_signTypedData", "eth_sign") ) authPayloadParams.chains.forEach { chain -> val issuer = "did:pkh:$chain:$address" val formattedMessage = formatAuthMessage(Sign.Params.FormatMessage(authPayloadParams, issuer)) val signature = signMessage(message: formattedMessage, privateKey: privateKey) //Note: Assume `signMessage` is a function you've implemented to sign messages. val auth = generateAuthObject(authPayloadParams, issuer, signature) auths.add(auth) } } ``` ### Approving Authentication Requests To approve an authentication request, construct Sign.Model.Cacao instances for each supported chain, sign the authentication messages, build AuthObjects and call approveAuthenticate with the request ID and the authentication objects. ```kotlin val approveAuthenticate = Sign.Params.ApproveAuthenticate(id = sessionAuthenticate.id, auths = auths) SignClient.approveAuthenticate(approveProposal, onSuccess = { //Redirect back to the dapp if redirect is set: sessionAuthenticate.participant.metadata?.redirect }, onError = { error -> //Handle error } ) ``` **Note** 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. ### Rejecting Authentication Requests If the authentication request cannot be approved or if the user chooses to reject it, use the rejectAuthenticate method. ```kotlin val rejectParams = Sign.Params.RejectAuthenticate( id = sessionAuthenticate.id, reason = "Reason" ) SignClient.rejectAuthenticate(rejectParams, onSuccess = { //Success }, onError = { error -> //Handle error } ) ``` #### Setup First you must setup `SignClientOptions` which stores both the `ProjectId` and `Metadata`. You may also optionally specify the storage module to use. By default, the `FileSystemStorage` module is used if none is specified. ```csharp var walletOptions = new SignClientOptions() { ProjectId = "39f3dc0a2c604ec9885799f9fc5feb7c", Metadata = new Metadata() { Description = "An example wallet to showcase WalletConnectSharpv2", Icons = new[] { "https://walletconnect.com/meta/favicon.ico" }, Name = "WalletConnectSharpv2 Wallet Example", Url = "https://walletconnect.com" }, // Uncomment to disable persistent storage // Storage = new InMemoryStorage() }; ``` Once you have the options defined, you can initialize the SDK. ```csharp var walletClient = await WalletConnectSignClient.Init(walletOptions); ``` Wallets can pair an incoming session using the session's Uri. Pairing a session lets the Wallet obtain the connection proposal which can then be approved or denied. ```csharp ProposalStruct proposal = await walletClient.Pair(connectData.Uri); ``` The wallet can then approve or reject the proposal using either of the following: ```csharp string addressToConnect = ...; var approveData = await walletClient.Approve(proposal, addressToConnect); await approveData.Acknowledged(); ``` ```csharp string[] addressesToConnect = ...; var approveData = await walletClient.Approve(proposal, addressesToConnect); await approveData.Acknowledged(); ``` ```csharp await walletClient.Reject(proposal, "User rejected"); ``` #### WalletConnect Methods All sign methods require the `topic` of the session to be given. This can be found in the `SessionStruct` object given when a session has been given approval by the user. ```csharp var sessionTopic = sessionData.Topic; ``` ##### Update Session Update a session, adding/removing additional namespaces in the given topic. ```csharp var newNamespaces = new Namespaces(...); var request = await walletClient.UpdateSession(sessionTopic, newNamespaces); await request.Acknowledged(); ``` ##### Extend Session Extend a session's expiry time so the session remains open ```csharp var request = await walletClient.Extend(sessionTopic); await request.Acknowledged(); ``` ##### Ping Send a ping to the session ```csharp var request = await walletClient.Ping(sessionTopic); await request.Acknowledged(); ``` #### Responding to Session Requests Responding to session requests is very similar to sending session requests. See dApp usage on how sending session requests works. All custom session requests requires a request class **and** response class to be created that matches the `params` field type in the custom session request. C# is a statically typed language, so these types must be given whenever you do a session request (or do any querying for session requests). Currently, **WalletConnectSharp does not automatically assume the object type for `params` is an array**. This is very important, since most EVM RPC requests have `params` as an array type. **Use `List` to workaround this**. For example, for `eth_sendTransaction`, use `List` instead of `Transaction`. Newtonsoft.Json is used for JSON serialization/deserialization, therefore you can use Newtonsoft.Json attributes when defining fields in your request/response classes. ##### Building a Response type Create a class for the response and populate it with the JSON properties the response object has. For this example, we will use `eth_getTransactionReceipt` The `params` field for `eth_getTransactionReceipt` has the object type ```csharp using Newtonsoft.Json; using System.Numerics; [RpcMethod("eth_getTransactionReceipt"), RpcRequestOptions(Clock.ONE_MINUTE, 99995)] public class TransactionReceipt { [JsonProperty("transactionHash")] public string TransactionHash; [JsonProperty("transactionIndex")] public BigInteger TransactionIndex; [JsonProperty("blockHash")] public string BlockHash; [JsonProperty("blockNumber")] public BigInteger BlockNumber; [JsonProperty("from")] public string From; [JsonProperty("to")] public string To; [JsonProperty("cumulativeGasUsed")] public BigInteger CumulativeGasUsed; [JsonProperty("effectiveGasPrice ")] public BigInteger EffectiveGasPrice ; [JsonProperty("gasUsed")] public BigInteger GasUsed; [JsonProperty("contractAddress")] public string ContractAddress; [JsonProperty("logs")] public object[] Logs; [JsonProperty("logsBloom")] public string LogBloom; [JsonProperty("type")] public BigInteger Type; [JsonProperty("status")] public BigInteger Status; } ``` The `RpcMethod` class attributes defines the rpc method this response uses, this is optional. The `RpcResponseOptions` class attributes define the expiry time and tag attached to the response, **this is required**. ##### Sending a response To respond to requests from a dApp, you must define the class representing the request object type. The request type for `eth_getTransactionReceipt` is the following: ```csharp [RpcMethod("eth_getTransactionReceipt"), RpcRequestOptions(Clock.ONE_MINUTE, 99994)] public class EthGetTransactionReceipt : List { public EthGetTransactionReceipt(params string[] hashes) : base(hashes) { } } ``` We can handle the `eth_getTransactionReceipt` session request by doing the following: ```csharp walletClient.Engine.SessionRequestEvents().OnRequest += OnEthTransactionReceiptRequest; private Task OnEthTransactionReceiptRequest(RequestEventArgs e) { // logic for request goes here // set e.Response to return a response } ``` The callback function gets invoked whenever the wallet receives the `eth_getTransactionReceipt` request from a connected dApp. You may optionally filter further which requests are handled using the `FilterRequests` function ```csharp walletClient.Engine.SessionRequestEvents() .FilterRequests(r => r.Topic == sessionTopic) .OnRequest += OnEthTransactionReceiptRequest; ``` The callback returns a `Task`, so the callback can be made async. To return a response, **you must** set the `Response` field in `RequestEventArgs` with the desired response. ```csharp private async Task OnEthTransactionReceiptRequest(RequestEventArgs e) { var txHash = e.Request.Params[0]; var receipt = await EthGetTransactionReceipt(txHash); e.Response = receipt; } ``` #### Disconnecting To disconnect a session, use the `Disconnect` function. You may optional provide a reason for the disconnect ```csharp await walletClient.Disconnect(sessionTopic); // or await walletClient.Disconnect(sessionTopic, Error.FromErrorType(ErrorType.USER_DISCONNECTED)); ``` # FAQs Source: https://docs.reown.com/advanced/faq ## What chains does WalletConnect support? WalletConnect operates as a chain-agnostic protocol, adhering to the [CAIP-25](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-25.md) standard. While the WalletConnect protocol supports various chains, you can refer to the [list](../cloud/chains/chain-list) for the known compatible blockchains. However, please note that our SDKs have certain limitations on the chains they support. If you intend to extend support for non-EVM chains in your wallet or dapp, it is recommended to review the cross-chain primitives supported by the WalletConnect protocol through the Chain Agnostic Standards Alliance's [Namespaces](https://namespaces.chainagnostic.org/) project. Additionally, feel free to reach out to our community team for further guidance. In the event that the desired chain lacks documentation in the Namespaces project, you can collaborate with an expert in the respective chain's tooling and submit a [namespaces PR](https://github.com/ChainAgnostic/namespaces/?tab=readme-ov-file#namespaces). ## Will the relay server `bridge.walletconnect.org` still work in v2? No, the bridge servers are v1 only. ## How can I reconnect to the same pairing if my browser was restarted? The `signClient` will restore & reconnect its pairings automatically after the page is reloaded. All pairings are stored on the page's `localStorage`. For more context, feel free to check our [web examples](https://github.com/WalletConnect/web-examples). ## The default relay endpoint is blocked. How can I get around this? When initializing `signClient`, you can set `relayUrl` to `wss://relay.walletconnect.org`. ```js const signClient = await SignClient.init({ projectId: "", relayUrl: "wss://relay.walletconnect.org", metadata: {}, }); ``` ## How can we use a custom relay for our bridge without a WC URI parameter as the host? You are more than welcome to utilize a custom URI parameter during testing. However, it is currently not recommended for use in a production environment. ## Why is self-hosting not an option at this time? Are there plans to make this possible in the future? We understand the desire for developers to self-host their own relay. We share this vision, and have embarked on a decentralization roadmap in order to achieve this. By the end of this summer, we will launch a permissioned network and invite a select group of partners to participate in this crucial first phase. Our objective is to make self-hosting relay a reality with the creation of the decentralized WalletConnect Network, and we appreciate your patience as we progress in this enormous mission. ## How do I report a security issue? Please consult our [security.txt](https://reown.com/.well-known/security.txt) # Dapp Integration Guide Source: https://docs.reown.com/advanced/multichain/polkadot/dapp-integration-guide ## Dapp Guide Section Topics * WalletConnect Code/Component Setup * Constructing unsigned transactions * Sending unsigned transactions for signing using WalletConnect * Adding the signature to the ExtrinsicPayload * Signing and sending the transaction to the node *** # WalletConnect Code/Component Setup 1. **One time step**: Generate a unique `projectId` by visiting and creating your project’s profile on WalletConnect’s project dashboard at: [https://cloud.reown.com/](https://cloud.reown.com/). 2. Import `UniversalProvider` and `{ WalletConnectModal }` from `@walletconnect/universal-provider` and `@walletconnect/modal` respectively. ```js import UniversalProvider from "@walletconnect/universal-provider"; import { WalletConnectModal } from "@walletconnect/modal"; ``` 3. Instantiate a universal provider using the `projectId` created for your app. ```js const provider = await UniversalProvider.init({ projectId: "2ea3f3ghubh32b8ie2f2", relayUrl: "wss://relay.walletconnect.com", }); ``` 4. On user action (e.g. user clicks connect for WalletConnect), call the connect method on the providers sign client passing in preferred params. WalletConnect uses chain ids based on the CAIP standard (CAIP-13 for Polkadot Namespace): [Polkadot WalletConnect CAIP-13](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-13.md) * polkadot CAIP id = `91b171bb158e2d3848fa23a9f1c25182` * kusama CAIP id = `b0a8d493285c2df73290dfb7e61f870f` * westend CAIP id = `e143f23803ac50e8f6f8e62695d1ce9e` * statemint CAIP id = `68d56f15f85d3136970ec16946040bc1` * hydradx CAIP id = `afdc188f45c71dacbaa0b62e16a91f72` * phala network CAIP id = `1bb969d85965e4bb5a651abbedf21a54` * astar network CAIP id = `9eb76c5184c4ab8679d2d5d819fdf90b` * crust shadow CAIP id = `d4c0c08ca49dc7c680c3dac71a7c0703` * mangata kusama mainnet CAIP id = `d611f22d291c5b7b69f1e105cca03352` * turing network CAIP id = `0f62b701fb12d02237a33b84818c11f6` * Chain ids correspond to the genesis hash for each respective chain ### Example Namespace and Sign Client connect call: **Note**: this serves as an example where a dapp requires 3 different chain namespaces (polkadot, hydradx and turing network). The supported methods, chains, and events can all be defined by the dapp team based on the requirements of the dapp. ```js const params = { requiredNamespaces: { polkadot: { methods: ["polkadot_signTransaction", "polkadot_signMessage"], chains: [ "polkadot:91b171bb158e2d3848fa23a9f1c25182", // polkadot "polkadot:afdc188f45c71dacbaa0b62e16a91f72", // hydradx "polkadot:0f62b701fb12d02237a33b84818c11f6", // turing network ], events: ['chainChanged", "accountsChanged'], }, }, }; const { uri, approval } = await provider.client.connect(params); ``` 5. Create a standalone modal using your dapps WalletConnect projectId. ```js const walletConnectModal = new WalletConnectModal({ projectId: "2ea3f3ghubh32b8ie2f2", }); ``` 6. Open the modal prompting the user to scan the QR code with their wallet app or copy the URI from the modal and paste into their wallet app to begin the session creation process. ```js // if there is a URI from the client connect step open the modal if (uri) { walletConnectModal.openModal({ uri }); } // await session approval from the wallet app const walletConnectSession = await approval(); ``` 7. Get the accounts from the session for use in constructing transactions. ```js const walletConnectAccount = Object.values(walletConnectSession.namespaces) .map((namespace) => namespace.accounts) .flat(); // grab account addresses from CAIP account formatted accounts const accounts = wcAccounts.map((wcAccount) => { const address = wcAccount.split(":")[2]; return address; }); ``` # Constructing Unsigned Transactions One thing the dapp must do is properly construct the unsigned transaction. This consists of constructing an object with the intended chain’s metadata including the `specVersion`, `transactionVersion`, etc. In addition to these, you must provide the transaction data (`method`, `address` etc). Below is an example of what this general structure looks like using polkadotjs but this can be done in any valid way: ```js const unsignedTransaction = { specVersion: api.runtimeVersion.specVersion.toHex(), transactionVersion: api.runtimeVersion.transactionVersion.toHex(), address: selectedWalletConnectAccountAddress, blockHash: lastHeader.hash.toHex(), blockNumber: blockNumber.toHex(), era: era.toHex(), genesisHash: api.genesisHash.toHex(), method: method.toHex(), nonce: nonce.toHex(), signedExtensions: [ "CheckNonZeroSender", "CheckSpecVersion", "CheckTxVersion", "CheckGenesis", "CheckMortality", "CheckNonce", "CheckWeight", "ChargeTransactionPayment", ], tip: api.registry.createType("Compact", 0).toHex(), version: tx.version, }; ``` 8. A specific example of constructing an unsigned transaction using polkadotjs api to retrieve the chains metadata. ```js // import api and wsprovider import { ApiPromise, WsProvider } from "@polkadot/api"; //instantiate wsProvider and api const wsProvider = new WsProvider("wss://rpc.polkadot.io"); const api = await ApiPromise.create({ provider: wsProvider }); const lastHeader = await api.rpc.chain.getHeader(); const blockNumber = api.registry.createType( "BlockNumber", lastHeader.number.toNumber() ); const tx = api.tx.balances.transfer(keyring.bob.publicKey, 100); const method = api.createType("Call", tx); const era = api.registry.createType("ExtrinsicEra", { current: lastHeader.number.toNumber(), period: 64, }); const accountNonce = getBalanceAccount(submitAddress)?.nonce || 0; const nonce = api.registry.createType("Compact", accountNonce); const unsignedTransaction = { specVersion: api.runtimeVersion.specVersion.toHex(), transactionVersion: api.runtimeVersion.transactionVersion.toHex(), address: selectedWalletConnectAccountAddress, blockHash: lastHeader.hash.toHex(), blockNumber: blockNumber.toHex(), era: era.toHex(), genesisHash: api.genesisHash.toHex(), method: method.toHex(), nonce: nonce.toHex(), signedExtensions: [ "CheckNonZeroSender", "CheckSpecVersion", "CheckTxVersion", "CheckGenesis", "CheckMortality", "CheckNonce", "CheckWeight", "ChargeTransactionPayment", ], tip: api.registry.createType("Compact", 0).toHex(), version: tx.version, }; ``` # Sending unsigned transactions to the wallet for signing using WalletConnect 9. Send the unsigned transaction to the paired wallet for signing using the providers sign client. This triggers a `session_request` event which must be handled by the paired wallet. ### Polkadot Example ```js const result = await client.request({ chainId: "polkadot:91b171bb158e2d3848fa23a9f1c25182", topic: walletConnectSession.topic, request: { method: "polkadot_signTransaction", params: { address: selectedWalletConnectAddress, transactionPayload: unsignedTransaction, }, }, }); ``` ### Parachain Example (HydraDX) ```js const result = await client.request({ chainId: "polkadot:afdc188f45c71dacbaa0b62e16a91f72", topic: walletConnectSession.topic, request: { method: "polkadot_signTransaction", params: { address: selectedWalletConnectAddress, transactionPayload: unsignedTransaction, }, }, }); ``` Once the request is resolved, the expected response should be a result object which contains a signature ```js { signature: "0x09u03f0h3nf34f0m3mn0fn34fn3f"; // an example result } ``` ## Adding the signature to the ExtrinsicPayload Using this signature, we can now create an `ExtrinsicPayload` and add the signature. Below is an example of this general step: ```js // create the extrinsic payload using the unsigned transaction const rawUnsignedTransaction = api.registry.createType( "ExtrinsicPayload", unsignedTransaction, { version: unsignedTransaction.version, } ); // add the signature to the extrinsic payload tx.addSignature( selectedWalletConnectAddress, result.signature, rawUnsignedTransaction ); ``` # Signing and sending the transaction to the node Now, it is just about attaching the returned signature to the transaction and submitting it as specified by the dApp. Below is a specific example showing this process: ```js const rawUnsignedTransaction = api.registry.createType( "ExtrinsicPayload", unsignedTransaction, { version: unsignedTransaction.version, } ); tx.addSignature( selectedWalletConnectAddress, result.signature, rawUnsignedTransaction ); // send the signed transaction to the node const unsub = await tx.send(({ status, events }) => { // optionally handle ready status, notify user of submission if (status.isReady) { // ... } // optionally handle in block status, notify user of in block if (status.isInBlock) { // ... } // let user know outcome of transaction if (status.isFinalized) { events.forEach(({ event: { method } }) => { // if success optionally notify/update state if (method === "ExtrinsicSuccess") { // ... unsub(); // unsubscribe from extrinsic } else if (method === "ExtrinsicFailed") { // on failure optionally notify/update state // ... unsub(); // unsubscribe from extrinsic } }); } }); ``` # Namespaces Guide Source: https://docs.reown.com/advanced/multichain/polkadot/namespaces-guide ## Guide Section Topics * [Understanding Namespaces](#understanding-namespaces) * [Proposal Namespaces](#proposal-namespaces) * [Proposal Namespace Example](#proposal-namespace-example) * [Session Namespaces](#session-namespaces) * [Session Namespace Example](#session-namespace-example) * [Chains](#chains), [Methods](#methods) and [Events](#events) * [Using Namespaces with the Universal Provider](#dapps-universal-provider-and-namespaces) * [Using Namespaces with the WalletKit](#wallets-walletkit-and-namespaces) ### Understanding Namespaces * Pairing sessions use specific methods, events and chains during their lifetimes. These arguments constitute what is known as a `namespace`. * Namespaces are used to specify the chains, methods and events that are intended to be used in a particular session. * They establish the minimal requirement for a wallet and a dapp to get paired. There are two types of namespaces, `proposal namespaces` and `session namespaces`. ### Proposal Namespaces * A dapp sends a proposal namespace to the wallet for pairing. The proposal namespace contains the list of `chains`, `methods` and `events` that the dapp intends to make use of. * The wallet validates if the received proposal namespaces are valid and returns a session with its approved namespaces as a response if it is valid along with the approved accounts for each chain in the namespace. * If the requested proposal namespaces are not valid based on the wallets rules, the session cannot be established and the wallet rejects it with an error code that tells the dapp if the proposal namespaces have invalid chains, methods, events or if it was simply rejected by the user. ### Proposal Namespace Example An example Proposal Namespace for a dapp which supports connecting to Polkadot, Ethereum, Polygon and Cosmos: ```js { "polkadot": { "chains": [ "polkadot:91b171bb158e2d3848fa23a9f1c25182", // Polkadot "polkadot:b0a8d493285c2df73290dfb7e61f870f", // Kusama ], "methods": ["polkadot_signMessage"], "events": ["accountsChanged"] }, "eip155": { "chains": [ "eip155:1", // Ethereum "eip155:137" // Polygon ], "methods": ["eth_sign"], "events": ["accountsChanged"] }, "cosmos": { "chains": ["cosmos:cosmoshub-4"], // Cosmos "methods": ["cosmos_signDirect"], "events": ["someCosmosEvent"] } } ``` ### Session Namespaces * The wallet validates if the received proposal namespaces match with the session namespaces it supports. If they match, a session is established successfully and pairing is completed. If not, the session is not established. * The wallet session can also choose to provide access to more chains, methods or events that were not a part of the proposal namespaces. This means a dapp could send a proposal namespace with only Polkadot `['polkadot:91b171bb158e2d3848fa23a9f1c25182']` in its requiredNamespaces `chains` field but a wallet could return a session namespace with both Polkadot and Kusama `['polkadot:91b171bb158e2d3848fa23a9f1c25182','polkadot:b0a8d493285c2df73290dfb7e61f870f']` as part of the sessions namespaces. ### Session Namespace Example ```js { "polkadot": { "accounts": [ "polkadot:91b171bb158e2d3848fa23a9f1c25182:AZBEwbZhYeiofodZnM2iAoshP3pXRPNSJEKFqEPDmvv1mY7" ] "methods": ["polkadot_signMessage", "polkadot_signTransaction"], "events": ["accountsChanged"] }, "eip155": { "accounts": [ "eip155:137:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb", "eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb" ], "methods": ["eth_sign"], "events": ["accountsChanged"] }, "cosmos": { "accounts": [ "cosmos:cosmoshub-4:cosmos1t2uflqwqe0fsj0shcfkrvpukewcw40yjj6hdc0" ], "methods": ["cosmos_signDirect", "personal_sign"], "events": ["someCosmosEvent", "proofFinalized"] } } ``` ### Chains * `chains` is an array of chain ids which represent the chains the session will be using during its lifetime. For Polkadot, the format for each chain id is the chain agnostic namespace (e.g. `eip155`, `polkadot`, `cosmos` etc) followed by a colon and the genesis hash for the chain (e.g. `91b171bb158e2d3848fa23a9f1c25182` for Polkadot). * A dapp or wallet can make as many or as few chain ids a part of its namespace as desired. ### Methods * `methods` is represented as an array of wallet defined methods that a session supports. * These are not pre-defined or centrally implemented and can be modified/extended as needed by a wallet. * In the above Polkadot session namespace example there are two given methods `polkadot_signMessage` and `polkadot_signTransaction`. The idea for the functionality of these methods is to sign the relevant data (either a message or unsigned transaction) and return the signature. [An example for each method](https://github.com/WalletConnect/web-examples/blob/main/advanced/wallets/react-wallet-v2/src/lib/PolkadotLib.ts). * If a dapp required additional method support such as receiving the signed hex for a transaction in order to submit it rather than the signature, a wallet only needs to define and add support for the method so that any dapp that requires that functionality can use it when making requests. * An example would be adding a method named `polkadot_getSignedHex` and creating an implementation that signs, and returns the hash of the signed transaction. ```js // Example Session Namespace { "polkadot": { "accounts": [ "polkadot:91b171bb158e2d3848fa23a9f1c25182:AZBEwbZhYeiofodZnM2iAoshP3pXRPNSJEKFqEPDmvv1mY7" ], "methods": [ "polkadot_signMessage", "polkadot_signTransaction" "polkadot_getSignedHex", ], "events": ["accountsChanged"], } } // In the wallets codebase, you'd add functionality to be called when this new method is called from a WalletConnect session // Specific Example Implementation: public async getSignedHex(payload: SignerPayloadJSON) { this.registry.setSignedExtensions(payload.signedExtensions) const txPayload = this.registry.createType('ExtrinsicPayload', payload, { version: payload.version }); const { signature } = txPayload.sign(this.keypair) const extrinsic = registry.createType( 'Extrinsic', { method: payload.method }, { version: payload.version } ); extrinsic.addSignature(unsigned.address, signature, unsigned); const hex = extrinsic.toHex(); return { hex }; } ``` * Wallets and dapps can define an agreed upon interface based on a particular chain or ecosystems needs. ### Events * `events` represent specific changes in a sessions state that a dapp or wallet may want to take some action on. * For example, a dapp or a wallet might want to perform some action if the user changes the selected session accounts. An example of emitting this event can be found below: ```js await signClient.emit({ topic, event: { name: "accountsChanged", data: ["AZBEwbZhYeiofodZnM2iAoshP3pXRPNSJEKFqEPDmvv1mY7"], }, chainId: "polkadot:91b171bb158e2d3848fa23a9f1c25182", }); ``` This can be useful in a wallet if a user is adding additional accounts to a session so that the wallet or dapp can respond and update their respective states using events such as `session_update` to update the accounts, chains, methods or events for the session or `session_delete` to end a session. [(More on events)](https://docs.walletconnect.com/specs/clients/sign/session-events#session_request). ### Using Namespaces In order to create a session proposal, call the connect method on the universal provider's sign client. The sign clients `connect` method accepts an object based on the following interface: ```js interface ConnectParams { requiredNamespaces?: ProposalTypes.RequiredNamespaces; optionalNamespaces?: ProposalTypes.OptionalNamespaces; sessionProperties?: ProposalTypes.SessionProperties; pairingTopic?: string; relays?: RelayerTypes.ProtocolOptions[]; } ``` ### Dapps: Universal Provider and Namespaces: The connect method on the universal provider expects an object that matches the above `ConnectParams` interface. All fields are optional and in the below example we use only the `requiredNamespaces` field in our proposal namespace: ```js const proposalNamespace = { requiredNamespaces: { polkadot: { methods: ["polkadot_signTransaction", "polkadot_signMessage"], chains: ["polkadot:91b171bb158e2d3848fa23a9f1c25182"], events: ["chainChanged", "accountsChanged"], }, }, }; // call connect on the universal provider passing the proposal namespace const { uri, approval } = await provider.client.connect(proposalNamespace); ``` ### Wallets: WalletKit and Namespaces: When the WalletKit approves and creates a session, it must provide the session proposal `id` as well as the session `namespaces` which are approved for use in the session. An example of what this looks like is below. ```js const session = await walletKit.approveSession({ id: proposal.id, namespaces: { polkadot: { accounts: [ "polkadot:91b171bb158e2d3848fa23a9f1c25182:AZBEwbZhYeiofodZnM2iAoshP3pXRPNSJEKFqEPDmvv1mY7", ], methods: ["polkadot_signTransaction", "polkadot_signMessage"], chains: ["polkadot:91b171bb158e2d3848fa23a9f1c25182"], events: ["chainChanged", "accountsChanged"], }, }, }); ``` More information on namespaces can be found [here](https://docs.walletconnect.com/specs/clients/sign/namespaces#controller-side-validation-of-incoming-proposal-namespaces-wallet). # Wallet Integration Guide Source: https://docs.reown.com/advanced/multichain/polkadot/wallet-integration-guide ## Wallet Guide Section Topics * WalletConnect Code/Component Setup * Approving a Session Proposal * Rejecting a Session Proposal * Handling Session Request Events * Session Persistence/Management *** 1. **Getting Started:** Generate a unique `projectId` by visiting and creating your project's profile on WalletConnect's project dashboard at: * `https://cloud.reown.com/` # WalletConnect Code/Component Setup 2. Import Core and WalletKit from WalletConnect. ```js import { Core } from "@walletconnect/core"; import { WalletKit } from "@walletconnect/wallekit"; ``` 3. Instantiate and add Core and WalletKit to the state of the wallet. ```js const core = new Core({ projectId: "fgu234234njbhvhv23525bj" }); const walletKit = await WalletKit.init({ core: core, metadata: { name: "Example WalletConnect Wallet", description: "Example WalletConnect Integration", url: "myexamplewallet.com", icons: [], }, }); ``` 4. Create a function to accept a session `uri` which will be passed from a dapp when a user either scans the dapp's WalletConnect qrcode modal or manually copies and pastes the uri from the modal into the wallet's UI. ```js const onConnect = async (uri: string) => { // call walletKit.core.pairing.pair( { uri: uri }) // with the uri received from the dapp in order to emit the // `session_proposal` event const result = await walletKit.core.pairing.pair({ uri }); }; ``` 5. Handle the `session_proposal` event on the `walletKit`. This event is triggered when the `pair` method is called on `walletKit.core.pairing` to create a pairing session. # Approving a Session Proposal (Example) When approving a session proposal, the wallet can perform any necessary checks such as ensuring that the proposal includes all required namespaces and any optional namespaces. The approval response also contains the approved accounts as part of the namespace. Below is an example showing the format for wallet accounts and how to include them in a session proposal approval. ```js // example account addresses in wallet state const substrateAccounts = [ "5CK8D1sKNwF473wbuBP6NuhQfPaWUetNsWUNAAzVwTfxqjfr", "5F3sa2TJAWMqDhXG6jhV4N8ko9SxwGy8TpaNS1repo5EYjQX", ]; // format the accounts to match the chain:chain_id:address format const walletConnectAccounts = accounts.map( (account) => `polkadot:91b171bb158e2d3848fa23a9f1c25182:${account.address}` ); walletKit.on("session_proposal", async (proposal) => { // optionally show user a modal or way to reject or approve session showWalletConnectModal(); // handle user approval case // create the approved session with selected accounts, supported methods, chains and events for your wallet const session = await walletKit.approveSession({ id: proposal.id, namespaces: { polkadot: { accounts: walletConnectAccounts, methods: ["polkadot_signTransaction", "polkadot_signMessage"], chains: ["polkadot:91b171bb158e2d3848fa23a9f1c25182"], events: ['chainChanged", "accountsChanged'], }, }, }); // create response object const response = { id: proposal.id, result: "session approved", jsonrpc: "2.0", }; // respond to the dapp request with the approved session's topic and response await walletKit.respondSessionRequest({ topic: session.topic, response }); }); ``` # Rejecting a Session Proposal (Example) If the user does not approve the requested chains, methods, or accounts, or if the wallet does not support the requested chains or methods, the response should not be considered a success. Below is an example of rejecting a session proposal. ```js // Note: session_request is emitted when the client on the dapp end calls the request method // import getSdkError to create predefined ErrorResponse types import { getSdkError } from "@walletconnect/utils"; walletKit.on("session_proposal", async (proposal) => { // optionally show user a modal or way to reject or approve session showWalletConnectModal(); // handle user reject action await walletKit.rejectSession({ id: proposal.id, reason: getSdkError("USER_REJECTED"), }); }); ``` # Handling Session Request Event A dapp triggers an event when it requires the wallet to carry out a specific action, such as signing a transaction. The event includes a topic and a request object, which will differ based on the requested action. As seen in the [WalletConnect Web Examples](https://github.com/WalletConnect/web-examples/blob/main/advanced/wallets/react-wallet-v2/src/lib/PolkadotLib.ts), two common use cases in polkadot are signing messages and signing transactions. These methods are represented here as `polkadot_signMessage` and `polkadot_signTransaction` respectively and each simply signs the respective payload and returns the signature to the dapp. An example of a `session_request` event handler containing both can be found below. ```js walletKit.on("session_request", async (requestEvent) => { const { params, id } = requestEvent; const { request } = params; const address = request.params?.address; // check that the request address is in your users list of wallets // Example: const wallet = getPolkadotWallet(address); // if (!wallet) { throw new Error("Polkadot wallet does not exist"); } // handle supported methods (polkadot_signMessage, polkadot_signTransaction) switch (request.method) { case "polkadot_signMessage": // call function used by wallet to sign message and return the signature const signature = await yourwallet.signMessage(request.params.message); // create the response containing the signature in the result const response = { id, result: { signature: signature }, jsonrpc: "2.0" }; // respond to the dapp request with the response and topic await walletKit.respondSessionRequest({ topic, response }); case "polkadot_signTransaction": // call function used by wallet to sign transactions and return the signature const signature = await yourwallet.signTransaction( request.params.transactionPayload ); // create the response containing the signature in the result const response = { id, result: { signature: signature }, jsonrpc: "2.0" }; // respond to the dapp request with the response and topic await walletKit.respondSessionRequest({ topic, response }); // throw error for methods your wallet doesn't support default: throw new Error(getSdkError("INVALID_METHOD").message); } }); ``` # Sessions Persistence/Management * sessions can be saved/stored so users don't have to pair repeatedly * sessions can be disconnected from using `await walletKit.disconnectSession({ topic: topic });` passing the session topic. * sessions can be extended using `await walletKit.extendSession({ topic: topic });` passing the session topic. * Default session lifetime is 7 days for WalletConnect v2.0. # Further Documentation for WalletConnect 2.0 * [https://docs.walletconnect.com/](https://docs.walletconnect.com/) # Bitcoin Source: https://docs.reown.com/advanced/multichain/rpc-reference/bitcoin-rpc Bitcoin JSON-RPC Methods We define an account as the group of addresses derived using the same account value in their [derivation paths](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#user-content-Path_levels). We use the first address of the [external chain](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#examples) ("first external address"), as the identifier for an account. An account's total balance is defined as the sum of all unspent transaction outputs (UTXOs) belonging to its entire group of addresses. 1. Dapps **must** only display the first external address as a connected account. 2. Wallets **must** only offer to connect the first external address(es). #### Account Definition The derivation path levels in the [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#path-levels), [BIP49](https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki#user-content-Public_key_derivation), [BIP84](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki#public-key-derivation), [BIP86](https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki#user-content-Public_key_derivation) standards are: ``` m / purpose' / coin_type' / account' / change / address_index ``` Addresses with different `purpose`, `change` and `address_index` values are considered to belong to the same account. Valid `purpose` values are 44, 49, 84 and 86. We use the first external Native SegWit (purpose = 84) address as the default account identifier. For a specific seed phrase and path `m/84'/0'/0'/0/0` we get account 0 with identifier `bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu`. Its total balance is the sum of all UTXO balances on all addresses with derivation paths: * `m/44'/0'/0'/change/address_index` * `m/49'/0'/0'/change/address_index` * `m/84'/0'/0'/change/address_index` * `m/86'/0'/0'/change/address_index` If the wallet user changes to account 1 we get path `m/84'/0'/1'/0/0` with identifier `bc1qku0qh0mc00y8tk0n65x2tqw4trlspak0fnjmfz`. Its total balance is the sum of all UTXO balances on all addresses with derivation paths: * `m/44'/0'/1'/change/address_index` * `m/49'/0'/1'/change/address_index` * `m/84'/0'/1'/change/address_index` * `m/86'/0'/1'/change/address_index` ## sendTransfer This method is used to sign and submit a transfer of any `amount` of Bitcoin to a single `recipientAddress`, optionally including a `changeAddress` for the change amount and `memo` set as an OP\_RETURN output by supporting wallets. The transaction will be signed and broadcast upon user approval. ### Parameters * `Object` * `account` : `String` - *(Required)* The connected account's first external address. * `recipientAddress` : `String` - *(Required)* The recipient's public address. * `amount` : `String` - *(Required)* The amount of Bitcoin to send, denominated in satoshis (Bitcoin base unit). * `changeAddress` : `String` - *(Optional)* The sender's public address to receive change. * `memo` : `String` - *(Optional)* The OP\_RETURN value as a hex string without 0x prefix, maximum 80 bytes. ### Returns * `Object` * `txid` : `String` - *(Required)* The transaction id as a hex string without 0x prefix. ### Example The example below specifies a simple transfer of 1.23 BTC (123000000 Satoshi). ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "sendTransfer", "params": { "account": "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu", "recipientAddress": "bc1pmzfrwwndsqmk5yh69yjr5lfgfg4ev8c0tsc06e", "amount": "123000000", "memo": "636861726c6579206c6f766573206865" } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "txid": "f007551f169722ce74104d6673bd46ce193c624b8550889526d1b93820d725f7" } } ``` ## getAccountAddresses This method returns all current addresses needed for a dapp to fetch all UTXOs, calculate the total balance and prepare transactions. Dapps will typically use an indexing service to query for balances and UTXOs for all addresses returned by this method, such as: * [Blockbook API](https://github.com/trezor/blockbook/blob/master/docs/api.md#get-address) * [Bitcore API](https://github.com/bitpay/bitcore/blob/master/packages/bitcore-node/docs/api-documentation.md#address) We recognize that there are two broad classes of wallets in use today: 1. Wallets that generate a new change or receive address for every transaction ("dynamic wallet"). 2. Wallets that reuse the first external address for every transaction ("static wallet"). #### Implementation Details * All wallets **should** include the first external address and all addresses with one or more UTXOs, unless they're filtered by `intentions`. * Dynamic wallets **should** include minimum 2 unused change and receive addresses. Otherwise dapps may have to request [getAccountAddresses](#getAccountAddresses) after every transaction to discover the new addresses and keep track of the user's total balance. * All wallets **must** return fewer than 20 unused change and receive addresses to avoid breaking the [gap limit](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#address-gap-limit). ### Parameters * `Object` * `account` : `String` - *(Required)* The connected account's first external address. * `intentions` : `String[]` - *(Optional)* Filter what addresses to return, e.g. "payment" or "ordinal". ### Returns * `Array` * `Object` * `address` : `String` - *(Required)* Public address belonging to the account. * `publicKey` : `String` - *(Optional)* Public key for the derivation path in hex, without 0x prefix. * `path` : `String` - *(Optional)* Derivation path of the address e.g. "m/84'/0'/0'/0/0". * `intention` : `String` - *(Optional)* Intention of the address, e.g. "payment" or "ordinal". ### Example: Dynamic Wallet The example below specifies a result from a dynamic wallet. For the sake of this example, receive and change addresses with index 3-4 are considered unused and addresses with paths `m/49'/0'/0'/0/7` and `m/84'/0'/0'/0/2` are considered to have UTXOs. Assuming the dapp monitors all returned addresses for balance changes, a new request to `getAccountAddresses` is only needed when all UTXOs in provided addresses have been spent, or when all provided `receive` addresses or `change` addresses have been used. ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "getAccountAddresses", "params": { "account": "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu" } } // Result { "id": 1, "jsonrpc": "2.0", "result": [ { "address": "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu", "publicKey": "0330d54fd0dd420a6e5f8d3624f5f3482cae350f79d5f0753bf5beef9c2d91af3c", "path": "m/84'/0'/0'/0/0" }, { "address": "3KHhcgwPgYF9hE77zaKy2G36dpkcNtvQ33", "publicKey": "03b90230ca20150142bc2849a3df4517073978f32466214a0ebc00cac52f996989", "path": "m/49'/0'/0'/0/7" }, { "address": "bc1qp59yckz4ae5c4efgw2s5wfyvrz0ala7rgvuz8z", "publicKey": "038ffea936b2df76bf31220ebd56a34b30c6b86f40d3bd92664e2f5f98488dddfa", "path": "m/84'/0'/0'/0/2" }, { "address": "bc1qgl5vlg0zdl7yvprgxj9fevsc6q6x5dmcyk3cn3", "publicKey": "03de7490bcca92a2fb57d782c3fd60548ce3a842cad6f3a8d4e76d1f2ff7fcdb89", "path": "m/84'/0'/0'/0/3" }, { "address": "bc1qm97vqzgj934vnaq9s53ynkyf9dgr05rargr04n", "publicKey": "03995137c8eb3b223c904259e9b571a8939a0ec99b0717684c3936407ca8538c1b", "path": "m/84'/0'/0'/0/4" }, { "address": "bc1qv6vaedpeke2lxr3q0wek8dd7nzhut9w0eqkz9z", "publicKey": "03d0d243b6a3176fa20fa95cd7fb0e8e0829b83fc2b52053633d088c1a4ba91edf", "path": "m/84'/0'/0'/1/3" }, { "address": "bc1qetrkzfslk0d4kqjnu29fdh04tkav9vj3k36vuh", "publicKey": "02a8dee7573bcc7d3c1e9b9e267dbf0cd717343c31d322c5b074a3a97090a0d952", "path": "m/84'/0'/0'/1/4" } ] } ``` ### Example: Static Wallet The example below specifies a response from a static wallet. The returned address is used for both change and payments. It's the only address with UTXOs. ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "getAccountAddresses", "params": { "account": "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu" } } // Result { "id": 1, "jsonrpc": "2.0", "result": [ { "address": "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu", "publicKey": "0330d54fd0dd420a6e5f8d3624f5f3482cae350f79d5f0753bf5beef9c2d91af3c", "path": "m/84'/0'/0'/0/0" } ] } ``` ## signPsbt This method can be used to request the signature of a Partially Signed Bitcoin Transaction (PSBT) and covers use-cases e.g. involving multiple-recipient transactions, requiring granular control over which UTXOs to spend or how to route change. ### Parameters * `Object` * `account` : `String` - *(Required)* The connected account's first external address. * `psbt` : `String` - *(Required)* Base64 encoded string of the PSBT to sign. * `signInputs` : `Array` * `Object` * `address` : `String` - *(Required)* The address whose private key to use for signing. * `index` : `Integer` - *(Required)* Specifies which input to sign. * `sighashTypes` : `Integer[]` - *(Optional)* Specifies which part(s) of the transaction the signature commits to. Default is `[1]`. * `broadcast` : `Boolean` - *(Optional)* Whether to finalize and broadcast the transaction after signing it. Default is `false`. ### Returns * `Object` * `psbt` : `String` - *(Required)* The base64 encoded signed PSBT. * `txid` : `String` - *(Optional)* The transaction ID as a hex-encoded string, without 0x prefix. This must be returned if the transaction was broadcasted. ## signMessage This method is used to sign a message with one of the connected account's addresses. ### Parameters * `Object` * `account` : `String` - *(Required)* The connected account's first external address. * `message` : `String` - *(Required)* The message to be signed by the wallet. * `address` : `String` - *(Optional)* The address whose private key to use for signing the message. * `protocol` : `"ecdsa" | "bip322"` - *(Optional)* Preferred signature type. Default is `"ecdsa"`. ### Returns * `Object` * `address` : `String` - *(Required)* The Bitcoin address used to sign the message. * `signature` : `String` - *(Required)* Hex encoded bytes of the signature, without 0x prefix. * `messageHash` : `String` - *(Optional)* Hex encoded bytes of the message hash, without 0x prefix. ## Events ### bip122\_addressesChanged This event is used by wallets to notify dapps about connected accounts' current addresses, for example all addresses with a UTXO and a few unused addresses. The event data has the same format as the [getAccountAddresses](#getaccountaddresses) result. #### Implementation Details * Wallets **should** emit a `bip122_addressesChanged` event immediately after connection approval of a BIP122 chain. * Wallets **should** emit a `bip122_addressesChanged` event whenever a UTXO is spent or created for a connected account's addresses. * Dapps **should** listen for `bip122_addressesChanged` events, collect and monitor all addresses for UTXO and balance changes. Example [session\_event](https://specs.walletconnect.com/2.0/specs/clients/sign/session-events#session_event) payload as received by a dapp: ``` { "id": 1675759795769537, "topic": "95d6aca451b8e3c6d9d176761bf786f1cc0a6d38dffd31ed896306bb37f6ae8d", "params": { "event": { "name": "bip122_addressesChanged", "data": [ { "address": "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu", "publicKey": "0330d54fd0dd420a6e5f8d3624f5f3482cae350f79d5f0753bf5beef9c2d91af3c", "path": "m/84'/0'/0'/0/0" }, { "address": "3KHhcgwPgYF9hE77zaKy2G36dpkcNtvQ33", "publicKey": "03b90230ca20150142bc2849a3df4517073978f32466214a0ebc00cac52f996989", "path": "m/49'/0'/0'/0/7" }, { "address": "bc1qp59yckz4ae5c4efgw2s5wfyvrz0ala7rgvuz8z", "publicKey": "038ffea936b2df76bf31220ebd56a34b30c6b86f40d3bd92664e2f5f98488dddfa", "path": "m/84'/0'/0'/0/2" }, { "address": "bc1qgl5vlg0zdl7yvprgxj9fevsc6q6x5dmcyk3cn3", "publicKey": "03de7490bcca92a2fb57d782c3fd60548ce3a842cad6f3a8d4e76d1f2ff7fcdb89", "path": "m/84'/0'/0'/0/3" }, { "address": "bc1qm97vqzgj934vnaq9s53ynkyf9dgr05rargr04n", "publicKey": "03995137c8eb3b223c904259e9b571a8939a0ec99b0717684c3936407ca8538c1b", "path": "m/84'/0'/0'/0/4" }, { "address": "bc1qv6vaedpeke2lxr3q0wek8dd7nzhut9w0eqkz9z", "publicKey": "03d0d243b6a3176fa20fa95cd7fb0e8e0829b83fc2b52053633d088c1a4ba91edf", "path": "m/84'/0'/0'/1/3" }, { "address": "bc1qetrkzfslk0d4kqjnu29fdh04tkav9vj3k36vuh", "publicKey": "02a8dee7573bcc7d3c1e9b9e267dbf0cd717343c31d322c5b074a3a97090a0d952", "path": "m/84'/0'/0'/1/4" } ] }, "chainId": "bip122:000000000019d6689c085ae165831e93" } } ``` # Casper Source: https://docs.reown.com/advanced/multichain/rpc-reference/casper-rpc ## Methods ### casper\_sign\_deploy Use the `casper_sign_deploy` method to request the user to approve or reject the signature of a transaction (aka deploy). The wallet should validate the received deploy object and present the details to the user for his review. #### Parameters * `address`. Type: `string`. The chain namespace and the public key corresponding to the key pair that signs the transaction are separated with a colon character. * `deploy`. Type: `object`. A Deploy object as per the Casper protocol specification. #### Returns * `deploy`. Type: `object`. The Deploy object including the newly generated approval item as per the Casper protocol specification. If the user rejects the signature, the wallet returns the WalletConnect SDK error `USER_REJECTED`. #### Example Request: ```json { "id": 1, "jsonrpc": "2.0", "method": "casper_sign_deploy", "params": { "deploy": { "hash": "a3301c9da7f0183f1c8904bed7fc72cf563454509462cada378b3f42a92f7b4f", "header": { "account": "02032E126170e5f28443775330B5B5Fe29dCE1a1dD3269910349525935ccbaf352EA", "timestamp": "2024-02-01T08:41:59.207Z", "ttl": "30m", "gas_price": 1, "body_hash": "188d88eedd3dc64b4ac3f8ca9b74be2b2fa588e2d537875d22b7e1a68658d19e", "dependencies": [], "chain_name": "casper-test" }, "payment": { "ModuleBytes": { "module_bytes": "", "args": [["amount", { "bytes": "0400e1f505", "cl_type": "U512" }]] } }, "session": { "Transfer": { "args": [ ["amount", { "bytes": "0500f2052a01", "cl_type": "U512" }], [ "target", { "bytes": "0202e99759649fa63a72c685b72e696b30c90f1deabb02d0d9b1de45eb371a73e5bb", "cl_type": "PublicKey" } ], [ "id", { "bytes": "01d204000000000000", "cl_type": { "Option": "U64" } } ] ] } }, "approvals": [] }, "address": "casper:casper-test:02032E126170e5f28443775330B5B5Fe29dCE1a1dD3269910349525935ccbaf352EA" } } ``` Response: ```json { "id": 1, "jsonrpc": "2.0", "result": { "deploy": { "hash": "a3301c9da7f0183f1c8904bed7fc72cf563454509462cada378b3f42a92f7b4f", "header": { "account": "02032E126170e5f28443775330B5B5Fe29dCE1a1dD3269910349525935ccbaf352EA", "timestamp": "2024-02-01T08:41:59.207Z", "ttl": "30m", "gas_price": 1, "body_hash": "188d88eedd3dc64b4ac3f8ca9b74be2b2fa588e2d537875d22b7e1a68658d19e", "dependencies": [], "chain_name": "casper-test" }, "payment": { "ModuleBytes": { "module_bytes": "", "args": [["amount", { "bytes": "0400e1f505", "cl_type": "U512" }]] } }, "session": { "Transfer": { "args": [ ["amount", { "bytes": "0500f2052a01", "cl_type": "U512" }], [ "target", { "bytes": "0202e99759649fa63a72c685b72e696b30c90f1deabb02d0d9b1de45eb371a73e5bb", "cl_type": "PublicKey" } ], [ "id", { "bytes": "01d204000000000000", "cl_type": { "Option": "U64" } } ] ] } }, "approvals": [ { "signer": "02032E126170e5f28443775330B5B5Fe29dCE1a1dD3269910349525935ccbaf352EA", "signature": "02ad07c25d7cef27598f67c7bafce3e07e4198de7884f0e48041965c0f0be2690956d25bae0510bec9463da4aa6a5e591fb3cb88c8f31df85bc0b6f857b80f64e2" } ] } } } ``` ### casper\_sign\_message Use `casper_sign_message` to request the user to sign a message. It's recommended to use this method with human-readable text messages. Upon user approval, the wallet must generate a signature for the prefixed message `"Casper Message:\n" + message`. The prefix protects the user against misuse of this method, preventing a malicious actor from trying to trick the user into signing arbitrary data, like a network transaction. #### Parameters * `address`. Type: `string`. The chain namespace and the public key corresponding to the key pair that signs the transaction separated with a colon character. * `message`. Type: `string`. The message to be signed. #### Returns * `signature`. Type: `string`. The signature of the message. If the user rejects the signature, the wallet returns the WalletConnect SDK error `USER_REJECTED`. #### Example Request: ```json { "id": 1, "jsonrpc": "2.0", "method": "casper_sign_message", "params": { "message": "CSPR.studio wants you to sign in with your Casper account:\n0x01953...808f3 \n\nIssued At: 07/21/2023 10:07:25\nnonce: 428b62e4", "address": "casper:casper-test:0202a8e3e5E32800792F37F738d95BF2610d86E97922D13ab97945bb062824ed9E8A" } } ``` Response: ```json { "id": 1, "jsonrpc": "2.0", "method": "casper_sign_message", "result": { "signature": "b52482afd2392b715cc43d9ad9f1f7067752a10ba5b49b89bc61b398e478841e6d8a4a224aeb944a34f23d98a232cdab6e5a60a5e886e8b0719d7b84277c405f" } } ``` ## Events Currently, this specification doesn't define any required events for wallets. # Cosmos Source: https://docs.reown.com/advanced/multichain/rpc-reference/cosmos-rpc Cosmos JSON-RPC Methods ## cosmos\_getAccounts This method returns an array of key pairs available to sign from the wallet mapped with an associated algorithm and address on the blockchain. ### Parameters none ### Returns 1.`Array` - Array of accounts: 1.1. `Object` - Account Data object with parameters: 1.1.1. `algo` : `STRING` - algorithm used for signing 1.1.2. `address` : `STRING` - corresponding address for keypair 1.1.3. `pubkey` : `STRING` - base64 encoded public key for keypair ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "cosmos_getAccounts", "params": {} } // Result { "id": 1, "jsonrpc": "2.0", "result": [ { "algo": "secp256k1", "address": "cosmos1sguafvgmel6f880ryvq8efh9522p8zvmrzlcrq", "pubkey": "AgSEjOuOr991QlHCORRmdE5ahVKeyBrmtgoYepCpQGOW" } ] } ``` ## cosmos\_signDirect This method returns a signature for the provided document to be signed targeting the requested signer address corresponding to the keypair returned by the account data. ### Parameters 1. `Object` - Signing parameters: 1.1. `signerAddress` : `STRING` - corresponding address for keypair 1.2. `signDoc` : `Object` - Document to be signed: 1.2.2. `chainId` : `STRING` - identifier of blockchain 1.2.1. `accountNumber` : `STRING` - blockchain account number 1.2.3. `authInfoBytes` : `DATA` - encoded authentication information 1.2.4. `bodyBytes` : `DATA` - encoded body of message to sign ### Returns 1. `Object` - Signing parameters: 1.1. `signature` : `Object` - corresponding signature for signed documented 1.1.1. `pub_key` : `Object` - public key for keypair 1.1.1.1: `type` : `STRING` - type of public key 1.1.1.2: `value` : `STRING` - value of public key 1.1.2. `signature`: `STRING` - corresponding signature for signed documented 1.2. `signed` : `Object` - Signed document: 1.2.2. `chainId` : `STRING` - identifier of blockchain 1.2.1. `accountNumber` : `STRING` - blockchain account number 1.2.3. `authInfoBytes` : `DATA` - encoded authentication information 1.2.4. `bodyBytes` : `DATA` - encoded body of message to sign ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "cosmos_signDirect", "params": { "signerAddress": "cosmos1sguafvgmel6f880ryvq8efh9522p8zvmrzlcrq", "signDoc": { "chainId": "cosmoshub-4", "accountNumber": "1" "authInfoBytes": "CgoKABIECgIIARgBEhMKDQoFdWNvc20SBDIwMDAQwJoM", "bodyBytes": "CpABChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnAKLWNvc21vczFwa3B0cmU3ZmRrbDZnZnJ6bGVzamp2aHhobGMzcjRnbW1rOHJzNhItY29zbW9zMXF5cHF4cHE5cWNyc3N6ZzJwdnhxNnJzMHpxZzN5eWM1bHp2N3h1GhAKBXVjb3NtEgcxMjM0NTY3" } } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "signature": { "pub_key": { "type": "tendermint/PubKeySecp256k1", "value": "AgSEjOuOr991QlHCORRmdE5ahVKeyBrmtgoYepCpQGOW" }, "signature": "AnTrXtS2lr9CBwhTpRa8ZlKcVR9PeIXGaTpvodyJU05QvRKVjIkQfOZl5JhdkfxCY+a6rhwCOYVcbKQTJlMw4w==" }, "signed": { "chainId": "cosmoshub-4", "accountNumber": "1" "authInfoBytes": "CgoKABIECgIIARgBEhMKDQoFdWNvc20SBDIwMDAQwJoM", "bodyBytes": "CpABChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEnAKLWNvc21vczFwa3B0cmU3ZmRrbDZnZnJ6bGVzamp2aHhobGMzcjRnbW1rOHJzNhItY29zbW9zMXF5cHF4cHE5cWNyc3N6ZzJwdnhxNnJzMHpxZzN5eWM1bHp2N3h1GhAKBXVjb3NtEgcxMjM0NTY3" } } } ``` ## cosmos\_signAmino This method returns a signature for the provided document to be signed targeting the requested signer address corresponding to the keypair returned by the account data. ### Parameters 1. `Object` - Signing parameters: 1.1. `signerAddress` : `STRING` - corresponding address for keypair 1.2. `signDoc` : `Object` - Document to be signed: 1.2.2. `chain_id` : `STRING` - identifier of blockchain 1.2.1. `account_number` : `STRING` - blockchain account number 1.2.3. `sequence` : `STRING` - blockchain account sequence 1.2.4. `memo` : `STRING` - amino message memo 1.2.5. `msgs` : `Array` - array of amino messages to be signed: 1.2.5.1. `Object` - amino message object: 1.2.5.1.1. - `type` : `STRING` - amino message type 1.2.5.1.2. - `value` : `STRING` - amino message value 1.2.6. `fee` : `Object` - fee description object 1.2.6.1. `amount` : `Array` - array of currency fees: 1.2.6.1.1. `Object` - currency fee description object: 1.2.6.1.1.1. `denom` : `STRING` - currency denomination 1.2.6.1.1.2. `amount` : `STRING` - currency amount 1.2.6.2. `gas` : `STRING` - gas limit for execution ### Returns 1. `Object` - Signing parameters: 1.1. `signature` : `Object` - corresponding signature for signed documented 1.1.1. `pub_key` : `Object` - public key for keypair 1.1.1.1: `type` : `STRING` - type of public key 1.1.1.2: `value` : `STRING` - value of public key 1.1.2. `signature`: `STRING` - corresponding signature for signed documented 1.2. `signed` : `Object` - Signed document: 1.2.2. `chain_id` : `STRING` - identifier of blockchain 1.2.1. `account_number` : `STRING` - blockchain account number 1.2.3. `sequence` : `STRING` - blockchain account sequence 1.2.4. `memo` : `STRING` - amino message memo 1.2.5. `msgs` : `Array` - array of amino messages to be signed: 1.2.5.1. `Object` - amino message object: 1.2.5.1.1. - `type` : `STRING` - amino message type 1.2.5.1.2. - `value` : `STRING` - amino message value 1.2.6. `fee` : `Object` - fee description object 1.2.6.1. `amount` : `Array` - array of currency fees: 1.2.6.1.1. `Object` - currency fee description object: 1.2.6.1.1.1. `denom` : `STRING` - currency denomination 1.2.6.1.1.2. `amount` : `STRING` - currency amount 1.2.6.2. `gas` : `STRING` - gas limit for execution ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "cosmos_signAmino", "params": { "signerAddress": "cosmos1sguafvgmel6f880ryvq8efh9522p8zvmrzlcrq", "signDoc": { "chain_id": "foochain", "account_number": "7", "sequence": "54" "memo": "hello, world", "msgs": [], "fee": { "amount": [], "gas": "23" } } } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "signature": { "pub_key": { "type": "tendermint/PubKeySecp256k1", "value": "AgSEjOuOr991QlHCORRmdE5ahVKeyBrmtgoYepCpQGOW" }, "signature": "AnTrXtS2lr9CBwhTpRa8ZlKcVR9PeIXGaTpvodyJU05QvRKVjIkQfOZl5JhdkfxCY+a6rhwCOYVcbKQTJlMw4w==" }, "signed": { "chain_id": "foochain", "account_number": "7", "sequence": "54" "memo": "hello, world", "msgs": [], "fee": { "amount": [{"denom": "ufoo", "amount": "10000"}], "gas": "23" } } } } ``` # Dogecoin Source: https://docs.reown.com/advanced/multichain/rpc-reference/dogecoin-rpc Dogecoin JSON-RPC Methods We define an account as the group of addresses derived using the same account value in their [derivation paths](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#user-content-Path_levels). We use the first address of the [external chain](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#examples) ("first external address"), as the identifier for an account. An account's total balance is defined as the sum of all unspent transaction outputs (UTXOs) belonging to its entire group of addresses. 1. Dapps **must** only display the first external address as a connected account. 2. Wallets **must** only offer to connect the first external address(es). #### Account Definition The derivation path levels in the [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#path-levels) standard is: ``` m / purpose' / coin_type' / account' / change / address_index ``` Addresses with different `purpose`, `change` and `address_index` values are considered to belong to the same account. We use the first external P2PKH (purpose = 44) address as the default account identifier. For a specific seed phrase and path `m/44'/3'/0'/0/0` we get account 0 with identifier `DTyt9wHTgizR8CwK8HAsWDaoMMxcaRuLWJ`. Its total balance is the sum of all UTXO balances on all addresses with derivation paths: * `m/44'/3'/0'/change/address_index` If the wallet user changes to account 1 we get path `m/44'/3'/1'/0/0` with identifier `DBcZSePDaMMduBMLymWHXhkE5ArFEvkagU`. Its total balance is the sum of all UTXO balances on all addresses with derivation paths: * `m/44'/3'/1'/change/address_index` ## sendTransfer This method is used to sign and submit a transfer of any `amount` of Dogecoin to a single `recipientAddress`, optionally including a `changeAddress` for the change amount and `memo` set as the OP\_RETURN value by supporting wallets. The transaction will be signed and broadcast upon user approval. ### Parameters * `Object` * `account` : `String` - *(Required)* The connected account's first external address. * `recipientAddress` : `String` - *(Required)* The recipient's public address. * `amount` : `String` - *(Required)* The amount of Dogecoin to send, denominated in satoshis (Dogecoin base unit). * `changeAddress` : `String` - *(Optional)* The sender's public address to receive change. * `memo` : `String` - *(Optional)* The OP\_RETURN value as a hex string without 0x prefix, maximum 80 bytes. ### Returns * `Object` * `txid` : `String` - The transaction id as a hex string without 0x prefix. ### Example The example below specifies a simple transfer of 1.23 DOGE (123000000 Satoshi). ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "sendTransfer", "params": { "account": "DTyt9wHTgizR8CwK8HAsWDaoMMxcaRuLWJ", "recipient": "DBcZSePDaMMduBMLymWHXhkE5ArFEvkagU", "amount": "123000000", "memo": "636861726c6579206c6f766573206865" } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "txid": "f007551f169722ce74104d6673bd46ce193c624b8550889526d1b93820d725f7" } } ``` ## getAccountAddresses This method returns all current addresses needed for a dapp to fetch all UTXOs, calculate the total balance and prepare transactions. Dapps will typically use an indexing service to query for balances and UTXOs for all addresses returned by this method, such as: * [Blockbook API](https://github.com/trezor/blockbook/blob/master/docs/api.md#get-address) * [Bitcore API](https://github.com/bitpay/bitcore/blob/master/packages/bitcore-node/docs/api-documentation.md#address) We recognize that there are two broad classes of wallets in use today: 1. Wallets that generate a new change or receive address for every transaction ("dynamic wallet"). 2. Wallets that reuse the first external address for every transaction ("static wallet"). #### Implementation Details * All wallets **should** include the first external address and all addresses with one or more UTXOs, unless they're filtered by `intentions`. * Dynamic wallets **should** include minimum 2 unused change and receive addresses. Otherwise dapps may have to request [getAccountAddresses](#getAccountAddresses) after every transaction to discover the new addresses and keep track of the user's total balance. * All wallets **must** return fewer than 20 unused change and receive addresses to avoid breaking the [gap limit](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#address-gap-limit). ### Parameters * `Object` * `account` : `String` - *(Required)* The connected account's first external address. * `intentions` : `String[]` - *(Optional)* Filter what addresses to return, e.g. "payment" or "ordinal". ### Returns * `Array` * `Object` * `address` : `String` - *(Required)* Public address belonging to the account. * `publicKey` : `String` - *(Optional)* Public key for the derivation path in hex, without 0x prefix. * `path` : `String` - *(Optional)* Derivation path of the address e.g. "m/44'/3'/0'/0/0". * `intention` : `String` - *(Optional)* Intention of the address, e.g. "payment" or "ordinal". ### Example: Dynamic Wallet The example below specifies a result from a dynamic wallet. For the sake of this example, receive and change addresses with index 3-4 are considered unused and address with path `m/44'/3'/0'/0/2` is considered to have UTXOs. Assuming the dapp monitors all returned addresses for balance changes, a new request to `getAccountAddresses` is only needed when all UTXOs in provided addresses have been spent, or when all provided `receive` addresses or `change` addresses have been used. ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "getAccountAddresses", "params": { "account": "DTyt9wHTgizR8CwK8HAsWDaoMMxcaRuLWJ" } } // Result { "id": 1, "jsonrpc": "2.0", "result": [ { "address": "DTyt9wHTgizR8CwK8HAsWDaoMMxcaRuLWJ", "path": "m/44'/3'/0'/0/0" }, { "address": "DA6rZ9aV3mkz9uxNvddzzbXEEcSPN8SCUS", "path": "m/44'/3'/0'/0/2" }, { "address": "DDtQfA541GQU2KDrY3ofF5F5hsKxkFiUuG", "path": "m/44'/3'/0'/0/3" }, { "address": "D5A6wPFhCNChUiQHGXftD8DiNgc2G7yT1L", "path": "m/44'/3'/0'/0/4" }, { "address": "DFG9R8ENG4mK5gUiU1VRr3FBT13LfWJ4Fb", "path": "m/44'/3'/0'/1/3" }, { "address": "D7rakaGgZvaBH1vGTxnsQ3ZdV7ejX57hRy", "path": "m/44'/3'/0'/1/4" } ] } ``` ### Example: Static Wallet The example below specifies a response from a static wallet. The returned address is used for both change and payments. It's the only address with UTXOs. ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "getAccountAddresses", "params": { "account": "DTyt9wHTgizR8CwK8HAsWDaoMMxcaRuLWJ" } } // Result { "id": 1, "jsonrpc": "2.0", "result": [ { "address": "DTyt9wHTgizR8CwK8HAsWDaoMMxcaRuLWJ", "path": "m/44'/3'/0'/0/0" } ] } ``` ## signPsbt This method can be used to request the signature of a Partially Signed Bitcoin Transaction (PSBT) and covers use-cases e.g. involving multiple-recipient transactions, requiring granular control over which UTXOs to spend or how to route change. ### Parameters * `Object` * `account` : `String` - *(Required)* The connected account's first external address. * `psbt` : `String` - *(Required)* Base64 encoded string of the PSBT to sign. * `signInputs` : `Array` * `Object` * `address` : `String` - *(Required)* The address whose private key to use for signing. * `index` : `Integer` - *(Required)* Specifies which input to sign. * `sighashTypes` : `Integer[]` - *(Optional)* Specifies which part(s) of the transaction the signature commits to. Default is `[1]`. * `broadcast` : `Boolean` - *(Optional)* Whether to finalize and broadcast the transaction after signing it. Default is `false`. ### Returns * `Object` * `psbt` : `String` - *(Required)* The base64 encoded signed PSBT. * `txid` : `String` - *(Optional)* The transaction ID as a hex-encoded string, without 0x prefix. This must be returned if the transaction was broadcasted. ## signMessage This method is used to sign a message with one of the connected account's addresses. ### Parameters * `Object` * `account` : `String` - *(Required)* The connected account's first external address. * `message` : `String` - *(Required)* The message to be signed by the wallet. * `address` : `String` - *(Optional)* The address whose private key to use for signing the message. * `protocol` : `"ecdsa" | "bip322"` - *(Optional)* Preferred signature type. Default is `"ecdsa"`. ### Returns * `Object` * `address` : `String` - *(Required)* The Dogecoin address used to sign the message. * `signature` : `String` - *(Required)* Hex encoded bytes of the signature, without 0x prefix. * `messageHash` : `String` - *(Optional)* Hex encoded bytes of the message hash, without 0x prefix. ## Events ### bip122\_addressesChanged This event is used by wallets to notify dapps about connected accounts' current addresses, for example all addresses with a UTXO and a few unused addresses. The event data has the same format as the [getAccountAddresses](#getaccountaddresses) result. #### Implementation Details * Wallets **should** emit a `bip122_addressesChanged` event immediately after connection approval of a BIP122 chain. * Wallets **should** emit a `bip122_addressesChanged` event whenever a UTXO is spent or created for a connected account's addresses. * Dapps **should** listen for `bip122_addressesChanged` events, collect and monitor all addresses for UTXO and balance changes. Example [session\_event](https://specs.walletconnect.com/2.0/specs/clients/sign/session-events#session_event) payload as received by a dapp: ``` { "id": 1675759795769537, "topic": "95d6aca451b8e3c6d9d176761bf786f1cc0a6d38dffd31ed896306bb37f6ae8d", "params": { "event": { "name": "bip122_addressesChanged", "data": [ { "address": "DTyt9wHTgizR8CwK8HAsWDaoMMxcaRuLWJ", "path": "m/44'/3'/0'/0/0" }, { "address": "DA6rZ9aV3mkz9uxNvddzzbXEEcSPN8SCUS", "path": "m/44'/3'/0'/0/2" }, { "address": "DDtQfA541GQU2KDrY3ofF5F5hsKxkFiUuG", "path": "m/44'/3'/0'/0/3" }, { "address": "D5A6wPFhCNChUiQHGXftD8DiNgc2G7yT1L", "path": "m/44'/3'/0'/0/4" }, { "address": "DFG9R8ENG4mK5gUiU1VRr3FBT13LfWJ4Fb", "path": "m/44'/3'/0'/1/3" }, { "address": "D7rakaGgZvaBH1vGTxnsQ3ZdV7ejX57hRy", "path": "m/44'/3'/0'/1/4" } ] }, "chainId": "bip122:1a91e3dace36e2be3bf030a65679fe821" } } ``` # Ethereum Source: https://docs.reown.com/advanced/multichain/rpc-reference/ethereum-rpc Ethereum JSON-RPC Methods ## personal\_sign The sign method calculates an Ethereum specific signature with:`sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)))`. By adding a prefix to the message makes the calculated signature recognizable as an Ethereum specific signature. This prevents misuse where a malicious DApp can sign arbitrary data (e.g. transaction) and use the signature to impersonate the victim. **Note** See ecRecover to verify the signature. ### Parameters message, account 1. `DATA`, N Bytes - message to sign. 2. `DATA`, 20 Bytes - address. ### Returns `DATA`: Signature ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "personal_sign", "params":["0xdeadbeaf","0x9b2055d370f73ec7d8a03e965129118dc8f5bf83"], } // Result { "id": 1, "jsonrpc": "2.0", "result": "0xa3f20717a250c2b0b729b7e5becbff67fdaef7e0699da4de7ca5895b02a170a12d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee1b" } ``` ## eth\_sign The sign method calculates an Ethereum specific signature with: `sign(keccak256("\x19Ethereum Signed Message:\n" + len(message) + message)))`. By adding a prefix to the message makes the calculated signature recognizable as an Ethereum specific signature. This prevents misuse where a malicious DApp can sign arbitrary data (e.g. transaction) and use the signature to impersonate the victim. **Note** the address to sign with must be unlocked. ### Parameters account, message 1. `DATA`, 20 Bytes - address. 2. `DATA`, N Bytes - message to sign. ### Returns `DATA`: Signature ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "eth_sign", "params": ["0x9b2055d370f73ec7d8a03e965129118dc8f5bf83", "0xdeadbeaf"], } // Result { "id": 1, "jsonrpc": "2.0", "result": "0xa3f20717a250c2b0b729b7e5becbff67fdaef7e0699da4de7ca5895b02a170a12d887fd3b17bfdce3481f10bea41f45ba9f709d39ce8325427b57afcfc994cee1b" } ``` An example how to use solidity ecrecover to verify the signature calculated with `eth_sign` can be found [here](https://gist.github.com/bas-vk/d46d83da2b2b4721efb0907aecdb7ebd). The contract is deployed on the testnet Ropsten and Rinkeby. ## eth\_signTypedData Calculates an Ethereum-specific signature in the form of `keccak256("\x19Ethereum Signed Message:\n" + len(message) + message))` By adding a prefix to the message makes the calculated signature recognizable as an Ethereum specific signature. This prevents misuse where a malicious DApp can sign arbitrary data (e.g. transaction) and use the signature to impersonate the victim. **Note** the address to sign with must be unlocked. ### Parameters account, message 1. `DATA`, 20 Bytes - address. 2. `DATA`, N Bytes - message to sign containing type information, a domain separator, and data ### Example Parameters ```javascript [ "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", { types: { EIP712Domain: [ { name: "name", type: "string", }, { name: "version", type: "string", }, { name: "chainId", type: "uint256", }, { name: "verifyingContract", type: "address", }, ], Person: [ { name: "name", type: "string", }, { name: "wallet", type: "address", }, ], Mail: [ { name: "from", type: "Person", }, { name: "to", type: "Person", }, { name: "contents", type: "string", }, ], }, primaryType: "Mail", domain: { name: "Ether Mail", version: "1", chainId: 1, verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", }, message: { from: { name: "Cow", wallet: "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826", }, to: { name: "Bob", wallet: "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB", }, contents: "Hello, Bob!", }, }, ]; ``` ### Returns `DATA`: Signature ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "eth_signTypedData", "params": ["0x9b2055d370f73ec7d8a03e965129118dc8f5bf83", {see above}], } ' // Result { "id": 1, "jsonrpc": "2.0", "result": "0x4355c47d63924e8a72e509b65029052eb6c299d53a04e167c5775fd466751c9d07299936d304c153f6443dfa05f40ff007d72911b6f72307f996231605b915621c" } ``` ## eth\_sendTransaction Creates new message call transaction or a contract creation, if the data field contains code. ### Parameters 1. `Object` - The transaction object 2. `from`: `DATA`, 20 Bytes - The address the transaction is send from. 3. `to`: `DATA`, 20 Bytes - (optional when creating new contract) The address the transaction is directed to. 4. `data`: `DATA` - The compiled code of a contract OR the hash of the invoked method signature and encoded parameters. For details see [Ethereum Contract ABI](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) 5. `gas`: `QUANTITY` - (optional, default: 90000) Integer of the gas provided for the transaction execution. It will return unused gas. 6. `gasPrice`: `QUANTITY` - (optional, default: To-Be-Determined) Integer of the gasPrice used for each paid gas 7. `value`: `QUANTITY` - (optional) Integer of the value sent with this transaction 8. `nonce`: `QUANTITY` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. ### Example Parameters ```javascript [ { from: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", to: "0xBDE1EAE59cE082505bB73fedBa56252b1b9C60Ce", data: "0x", gasPrice: "0x029104e28c", gas: "0x5208", value: "0x00", }, ]; ``` ### Returns `DATA`, 32 Bytes - the transaction hash, or the zero hash if the transaction is not yet available. Use [eth\_getTransactionReceipt](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionreceipt) to get the contract address, after the transaction was mined, when you created a contract. ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "eth_sendTransaction", "params":[{see above}], } // Result { "id": 1, "jsonrpc": "2.0", "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331" } ``` ## eth\_signTransaction Signs a transaction that can be submitted to the network at a later time using with `eth_sendRawTransaction` ### Parameters 1. `Object` - The transaction object 2. `from`: `DATA`, 20 Bytes - The address the transaction is send from. 3. `to`: `DATA`, 20 Bytes - (optional when creating new contract) The address the transaction is directed to. 4. `data`: `DATA` - The compiled code of a contract OR the hash of the invoked method signature and encoded parameters. For details see [Ethereum Contract ABI](https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI) 5. `gas`: `QUANTITY` - (optional, default: 90000) Integer of the gas provided for the transaction execution. It will return unused gas. 6. `gasPrice`: `QUANTITY` - (optional, default: To-Be-Determined) Integer of the gasPrice used for each paid gas 7. `value`: `QUANTITY` - (optional) Integer of the value sent with this transaction 8. `nonce`: `QUANTITY` - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce. ### Example Parameters ```javascript [ { from: "0xb60e8dd61c5d32be8058bb8eb970870f07233155", to: "0xd46e8dd67c5d32be8058bb8eb970870f07244567", data: "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675", gas: "0x76c0", // 30400 gasPrice: "0x9184e72a000", // 10000000000000 value: "0x9184e72a", // 2441406250 nonce: "0x117", // 279 }, ]; ``` ### Returns `DATA` - the signed transaction data ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "eth_signTransaction", "params":[{see above}], } // Result { "id": 1, "jsonrpc": "2.0", "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331" } ``` ## eth\_sendRawTransaction Creates new message call transaction or a contract creation for signed transactions. ### Parameters 1. `DATA`, the signed transaction data. ### Returns `DATA`, 32 Bytes - the transaction hash, or the zero hash if the transaction is not yet available. Use [eth\_getTransactionReceipt](https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_gettransactionreceipt) to get the contract address, after the transaction was mined, when you created a contract. ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "eth_sendRawTransaction", "params":[ "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f07244567" ], } // Result { "id": 1, "jsonrpc": "2.0", "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331" } ``` # WC JSON-RPC for Everscale Source: https://docs.reown.com/advanced/multichain/rpc-reference/everscale-rpc Everscale JSON-RPC Methods ### ever\_sign Signature of a random message for authentication. ##### Parameters: 1. message - some message in base64; 2. withSignatureId - bool or number 3. hashData - bool ##### Returns: 1. signature - string signature in base64; 2. pubkey - public key of the wallet's address; ##### Example: ``` // Request { "id": 1, "jsonrpc": "2.0", "method": "ever_sign", "params": { "message": "some message in base64", "withSignatureId": true, "hashData": true } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "signature": "0xa3f207... in base64", "pubkey": "0x07bf94e...37e3" } } ``` ### ever\_sendMessage Creates message, sends it to the network, monitors its processing and returns transaction's id. ##### Parameters: 1. value - amount of coins attached to the message; 2. bounce - should the answer message be generated in case of an error; 3. destAddress - message destination address; 4. destPayload - message destination payload; 4.1. abi - destination contract ABI; 4.2. method - destination contract method; 4.3. params - destination contract method params ##### Returns: 1. txId - transaction's id in blockchain; ##### Example: ``` // Request { "id": 1, "jsonrpc": "2.0", "method": "ever_sendMessage", "params": { "source_address": "0:695e42...b8d", "value": 1000000000, "bounce": False, "destAddress": "0:b38d96...708", "destPayload": { "abi": "", "method": "", "params": {} }, } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "txId": "743e1c0046b82a48a2cf8cbe9a2059ce6f3862cfae377c77d9f1b4efd88d7acb" } } ``` ### ever\_signMessage Message that can then be sent to the blockchain. ##### Parameters: 1. value - amount of coins attached to the message; 2. bounce - should the answer message be generated in case of an error; 3. destAddress - message destination address; 4. destPayload - message destination payload; 4.1. abi - destination contract ABI; 4.2. method - destination contract method; 4.3. params - destination contract method params ##### Returns: 1. signedExtMessage - signed external message; 2. expireAt - message expiration timestamp ##### Example: ``` // Request { "id": 1, "jsonrpc": "2.0", "method": "ever_processMessage", "params": { "source_address": "0:695e42...b8d", "value": 1000000000, "bounce": False, "destAddress": "0:b38d96...708", "destPayload": { "abi": "", "method": "", "params": {} }, } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "signedExtMessage": "c0b0996a9f0ea8e472041857ff2da9cf8086a78603f823a7170891f43a217ff1", "expireAt": 1685594678 } } ``` ### ever\_sendExternalMessage Sends an external message to the contract. ##### Parameters: 1. destAddress - message destination address; 2. destPayload - message destination payload; 2.1. abi - destination contract ABI; 2.2. method - destination contract method; 2.3. params - destination contract method params ##### Returns: 1. txId - transaction's id in blockchain; ##### Example: ``` // Request { "id": 1, "jsonrpc": "2.0", "method": "ever_sendExternalMessage", "params": { "sourceAddress": "0:695e42...b8d", "destAddress": "0:b38d96...708", "destPayload": { "abi": "", "method": "", "params": {} }, } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "txId": "743e1c0046b82a48a2cf8cbe9a2059ce6f3862cfae377c77d9f1b4efd88d7acb" } }; ``` ### ever\_broadcastMessage Sends an internal message from the user account without waiting for the transaction. ##### Parameters: 1. value - amount of coins attached to the message; 2. bounce - should the answer message be generated in case of an error; 3. destAddress - message destination address; 4. destPayload - message destination payload; 4.1. abi - destination contract ABI; 4.2. method - destination contract method; 4.3. params - destination contract method params ##### Returns: 1. hash: string - external message hash; 2. account: string - destination account address (equals to source\_address); 3. expireAt: number - message expiration timestamp ##### Example: ``` // Request { "id": 1, "jsonrpc": "2.0", "method": "ever_broadcastMessage", "params": { "sourceAddress": "0:695e42...b8d", "value": 1000000000, "bounce": False, "destAddress": "0:b38d96...708", "destPayload": { "abi": "", "method": "", "params": {} }, } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "hash": "743e1c0046b82a48a2cf8cbe9a2059ce6f3862cfae377c77d9f1b4efd88d7acb", "account": "0:695e42...b8d", "expireAt": 1684327417543 } }; ``` ### ever\_broadcastExternalMessage Sends an external message to the contract without waiting for the transaction. ##### Parameters: 1. destAddress - message destination address; 2. destPayload - message destination payload; 2.1. abi - destination contract ABI; 2.2. method - destination contract method; 2.3. params - destination contract method params ##### Returns: 1. hash: string - external message hash; 2. account: string - destination account address (equals to source\_address); 3. expireAt: number - message expiration timestamp ##### Example: ``` // Request { "id": 1, "jsonrpc": "2.0", "method": "ever_broadcastExternalMessage", "params": { "sourceAddress": "0:695e42...b8d", "destAddress": "0:b38d96...708", "destPayload": { "abi": "", "method": "", "params": {} }, } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "hash": "743e1c0046b82a48a2cf8cbe9a2059ce6f3862cfae377c77d9f1b4efd88d7acb", "account": "0:b38d96...708", "expireAt": 1684327417543 } } ``` ### ever\_addTokenAsset Adds asset (TIP-3 or native tokens) to the selected account. ##### Parameters: 1. rootContract - asset root address. Note: you can add native coin by leaving this field empty ##### Returns: 1. newAsset: bool - returns true if the account did not have this asset before ##### Example: ``` // Request { "id": 1, "jsonrpc": "2.0", "method": "ever_addTokenAsset", "params": { "sourceAddress": "0:695e42...b8d", "rootContract": "0:b38d96...708" } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "newAsset": true } } ``` ### ever\_encryptData Encrypts arbitrary data with specified algorithm for each specified recipient. ##### Parameters: 1. recipientPublicKeys - public keys of recipients. Hex encoded; 2. algorithm - encryption algorithm. Currently supports only “ChaCha20Poly1305” 3. data - base64 encoded data; ##### Returns: 1. encryptedData - encrypted data for each recipient 1.1. algorithm - encryption algorithm 1.2. sourcePublicKey - hex encoded encryptor's public key 1.3. recipientPublicKey - hex encoded recipient public key 1.4. data - base64 encoded data 1.5. nonce - base64 encoded nonce ##### Example: ``` // Request { "id": 1, "jsonrpc": "2.0", "method": "ever_encryptData", "params": { "sourceAddress": "0:695e42...b8d", "recipientPublicKeys": ["0x6e74...4e95", "0x9532...403f"], "algorithm": "ChaCha20Poly1305", "data": "ZGF0YQ==" } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "encryptedData": [ { "algorithm": "ChaCha20Poly1305", "sourcePublicKey": "0x209f...d08f", "recipientPublicKey": "0x6e74...4e95", "data": "ZW5jRGF0YTE=", "nonce": "bm9uY2Ux" }, { "algorithm": "ChaCha20Poly1305", "sourcePublicKey": "0x209f...d08f", "recipientPublicKey": "0x6e74...4e95", "data":"ZW5jRGF0YTI=", "nonce":"bm9uY2Uy" } ] } }; ``` ### ever\_decryptData Decrypts encrypted data. ##### Parameters: 1. algorithm - encryption algorithm. Currently supports only “ChaCha20Poly1305” 2. recipientPublicKey - hex encoded recipient public key 3. data - base64 encoded data 4. nonce - base64 encoded nonce ##### Returns: 1. data - base64 encoded decrypted data ##### Example: ``` // Request { "id": 1, "jsonrpc": "2.0", "method": "ever_decryptData", "params": { "sourceAddress": "0:695e42...b8d", "algorithm": "ChaCha20Poly1305", "recipientPublicKey": "0x6e74...4e95", "data": "ZW5jRGF0YTE=", "nonce": "bm9uY2Ux" } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "data": "ZGF0YQ==" } }; ``` # Hedera Source: https://docs.reown.com/advanced/multichain/rpc-reference/hedera-rpc Hedera JSON-RPC Methods The following JSON-RPC methods offer native integration into Hedera utilizing the [Hedera APIs](https://hashgraph.github.io/hedera-protobufs/) and the [Hedera SDKs](https://docs.hedera.com/hedera/sdks-and-apis/sdks). Hedera documentation can be found at [docs.hedera.com](https://docs.hedera.com/hedera/). The following resources provide specific information referenced in the methods below. * The Hedera network structure is summarized by [Mainnet Nodes](https://docs.hedera.com/hedera/networks/mainnet/mainnet-nodes) * The full list of Hedera functionality is described by the protobuf definitions: [Hedera Functionality](https://hashgraph.github.io/hedera-protobufs/#proto.HederaFunctionality) * Further details about these methods can be found in the accompanying Hedera Improvement Proposal: [HIP-820](https://hips.hedera.com/hip/hip-820) * The `signerAccountId` utilized in the methods below is specified by [HIP-30](https://hips.hedera.com/hip/hip-30) * A Hedera Transaction ID is composed of the account id that pays for a transaction and the valid start timestamp in nanoseconds: [Hedera Transaction ID](https://docs.hedera.com/hedera/sdks-and-apis/sdks/transactions/transaction-id) * There are pre-processing validation response codes returned by the network: [ResponseCodeEnum](https://github.com/hashgraph/hedera-protobufs/blob/f36e05bd6bf3f572707ca9bb338f5ad6421a4241/services/response_code.proto#L32) *Hedera has a separate open-source project implementing parts of the [Ethereum JSON-RPC standard](https://docs.hedera.com/hedera/core-concepts/smart-contracts/json-rpc-relay) which is not covered in this documentation.* ## Methods * [`hedera_signAndExecuteTransaction`](#hedera_signandexecutetransaction) * [`hedera_signTransaction`](#hedera_signtransaction) * [`hedera_executeTransaction`](#hedera_executetransaction) * [`hedera_signAndExecuteQuery`](#hedera_signandexecutequery) * [`hedera_signMessage`](#hedera_signmessage) * [`hedera_getNodeAddresses`](#hedera_getnodeaddresses) ## hedera\_signAndExecuteTransaction The `hedera_signAndExecuteTransaction` method is a generic method for executing a transaction on the Hedera network. A dApp can begin by constructing a transaction with one of the Hedera SDKs or by constructing the raw protobuf messages and may select one or more consensus nodes that are authorized to execute the transaction. The dApp then constructs a list of valid transaction bytes that differ only in the node account id and serializes the list, for example by using the `toBytes()` method of an SDK. Finally, the dApp base64 encodes the resulting bytes. This final base64 encoded string of bytes is sent as a method param titled `transactionList` to the wallet. Wallets and SDKs must take special care to deserialize the list of transactions and validate that each transaction in the list differs only in the node authorized to receive the transaction and does NOT differ in intent before submitting to an end user for approval and ultimately signing. ### Parameters 1. `Object` - signAndExecuteTransaction parameters 1.1. `signerAccountId` : `String` - Hedera account id in the format `:..<-optional-checksum>` 1.2. `transactionList` : `String` - Base64 encoded string of TransactionList bytes ### Returns 1. `Object` - Result of transaction submission to Hedera network 1.1. `nodeId` : `String` - The Hedera node the transaction was submitted to 1.2. `transactionHash` : `String` - The hash of the transaction 1.3. `transactionId` : `String` - Transaction ID, which includes the payer account id and the valid start timestamp ### Error In certain conditions, the Hedera network will return a response that signifies a pre-processing validation error, for example, when the transaction has expired. In these cases, wallets will return an error with the following format: 1. `Object` - Result of transaction submission to Hedera network 1.1. `code` : 9000 - The reserved WalletConnect error code for unknown errors or errors not related to the WalletConnect protocol 1.2. `message` : `String` - A human readable string describing the nature of the failure 1.3. `data` : `Number` - An integer representing the ResponseCodeEnum value returned from the Hedera Node, which indicates the reason for the failure ### Example #### Request ```json { "id": 1, "jsonrpc": "2.0", "method": "hedera_signAndExecuteTransaction", "params": { "signerAccountId": "hedera:testnet:0.0.12345", "transactionList": "Co8BKowBCocBChoKDAjchKWmBhDW..." } } ``` #### Result ```json { "id": 1, "jsonrpc": "2.0", "result": { "nodeId": "0.0.3", "transactionHash": "252b8fd...", "transactionId": "0.0.12345678@1689281510.675369303" } } ``` #### Error ```json { "id": 1, "jsonrpc": "2.0", "error": { "code": 9000, "message": "The transaction failed with precheck code...", "data": 6 } } ``` ## hedera\_signTransaction The `hedera_signTransaction` signs a `TransactionBody` and returns a `SignatureMap` to the caller. ### Parameters 1. `Object` - signTransaction parameters 1.1 `signerAccountId` : `String` - Hedera account id in the format `:..<-optional-checksum>` 1.2 `transactionBody` : `String` - Base64 encoded string representation of TransactionBody ### Returns 1. `Object` - SignatureMap of related signed TransactionBody 1.1 `signatureMap` : `String` - Base64 encoded string of SignatureMap ### Example #### Request ```json { "id": 1, "jsonrpc": "2.0", "method": "hedera_signTransaction", "params": { "signerAccountId": "hedera:testnet:0.0.12345", "transactionBody": "Co8BKowBCocBChoKDAjchKWmBhDW..." } } ``` #### Result ```json { "id": 1, "jsonrpc": "2.0", "result": { "signatureMap": "VGhpcyBpcyBqdXN0IHNvbWUgc3R1..." } } ``` ## hedera\_executeTransaction When a dApp only requires the services of the controller to act as a relay to the Hedera network for submitting an already signed transaction, it can use the `hedera_executeTransaction` method. ### Parameters 1. `Object` - executeTransaction parameters 1.1 `transactionList` : `String` Base64 encoded TransactionList ### Returns 1. `Object` - Result of transaction submission to the Hedera network 1.1. `nodeId` : `String` - The Hedera node the transaction was submitted to 1.1. `transactionHash` : `String` - The hash of the transaction 1.1. `transactionId` : `String` - Transaction ID, which includes the payer account id and the valid start timestamp ### Error In certain conditions, the Hedera network with return a response that signifies a pre-processing validation error, for example, when the transaction has expired. In these cases, wallets will return an error with the following format: 1. `Object` - Result of transaction submission to the Hedera network 1.1. `code` : 9000 - The reserved WalletConnect error code for unknown errors or errors not related to the WalletConnect protocol 1.1. `message` : `String` - A human readable string describing the nature of the failure 1.1. `data` : `Number` - An integer representing the ResponseCodeEnum value returned from the Hedera Node, which indicates the reason for the failure ### Example #### Request ```json { "id": 1, "jsonrpc": "2.0", "method": "hedera_executeTransaction", "params": { "transactionList": "Co8BKowBCocBChoKDAjchKWmBhDW..." } } ``` #### Result ```json { "id": 1, "jsonrpc": "2.0", "result": { "nodeId": "0.0.3", "transactionHash": "252b8fd...", "transactionId": "0.0.12345678@1689281510.675369303" } } ``` #### Error ```json { "id": 1, "jsonrpc": "2.0", "error": { "code": 9000, "message": "The transaction failed with precheck code...", "data": 6 } } ``` ## hedera\_signAndExecuteQuery This method provides functionality to perform a query on a Hedera consensus node. Many Queries against consensus nodes have a transaction fee [Learn more about Queries](https://docs.hedera.com/hedera/sdks-and-apis/sdks/queries). Most requests that do not change network state can be performed against a [Mirror Node](https://docs.hedera.com/hedera/core-concepts/mirror-nodes) and for many use cases calling a mirror node endpoint is the recommended approach. ### Parameters 1. `Object` - signAndExecuteQuery parameters 1.1 `signerAccountId` : `String` - Hedera account id in the format `:..<-optional-checksum>` 1.2 `query` : `String` - base64 encoded Query ### Returns 1. `Object` - Result of the Query submitted to a Hedera consensus node 1.1. `response` : `String` - Base64 encoding of the Hedera API response ## hedera\_signMessage This method accepts a plain text string value as input. If approved by the user, the controller UTF-8 encodes this message prepended with "\x19Hedera Signed Message:\n" plus the length of the message and signs the resulting bytes in the same manner as HAPI transactions are signed. The resulting signature(s) are transmitted back to the user encoded in a SignatureMap structure. The pseudo code for computing the signature is as follows: ```javascript .sign("\x19Hedera Signed Message:\n" + len(message) + message) ``` ### Parameters 1. `Object` - signMessage parameters 1.1 `signerAccountId` : `String` - Hedera account id in the format `:..<-optional-checksum>` 1.2 `message` : `String` ### Returns 1. `Object` - signMessage result 1.1 `signatureMap` : `String` - Base64 encoded SignatureMap ### Example #### Request ```json { "id": 1, "jsonrpc": "2.0", "method": "hedera_signMessage", "params": { "signerAccountId": "hedera:testnet:0.0.12345" "message": "Co8BKowBCocBChoKDAjchKWmBhDW..." } } ``` #### Result ```json { "id": 1, "jsonrpc": "2.0", "result": { "signatureMap": "CAAQABjMrxoYABIGCAAQABgHGIDIr..." } } ``` ## hedera\_getNodeAddresses While constructing a transaction for transmission to a controller, a dApp needs to choose which Hedera Network node shall receive the transaction prior to signing (this is a requirement of the Hedera API Protocol). While a dApp can easily obtain a list of potential Hedera Nodes, a controller may not have an all-inclusive list nor a path to the node’s gRPC endpoint. The `hedera_getNodeAddresses` method allows a dApp to request a list of node wallet addresses known to the controller. The controller should only include nodes in this list that it is willing and able to submit transactions to at the time of the request. ### Returns 1. `Object` - signMessage result 1.1 `nodes` : `Array` - an array of strings in `..<-optional-checksum>` format, each identifying a node by its Hedera Address ### Example #### Request ```json { "id": 1, "jsonrpc": "2.0", "method": "hedera_getNodeAddresses" } ``` #### Result ```json { "id": 1, "jsonrpc": "2.0", "result": { "nodes": ["0.0.3", "0.0.4"] } } ``` # Litecoin Source: https://docs.reown.com/advanced/multichain/rpc-reference/litecoin-rpc Litecoin JSON-RPC Methods We define an account as the group of addresses derived using the same account value in their [derivation paths](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#user-content-Path_levels). We use the first address of the [external chain](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#examples) ("first external address"), as the identifier for an account. An account's total balance is defined as the sum of all unspent transaction outputs (UTXOs) belonging to its entire group of addresses. 1. Dapps **must** only display the first external address as a connected account. 2. Wallets **must** only offer to connect the first external address(es). #### Account Definition The derivation path levels in the [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#path-levels), [BIP49](https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki#user-content-Public_key_derivation), [BIP84](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki#public-key-derivation), [BIP86](https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki#user-content-Public_key_derivation) standards are: ``` m / purpose' / coin_type' / account' / change / address_index ``` Addresses with different `purpose`, `change` and `address_index` values are considered to belong to the same account. Valid `purpose` values are 44, 49, 84 and 86. We use the first external Native SegWit (purpose = 84) address as the default account identifier. For a specific seed phrase and path `m/84'/2'/0'/0/0` we get account 0 with identifier `ltc1q8c6fshw2dlwun7ekn9qwf37cu2rn755u9ym7p0`. Its total balance is the sum of all UTXO balances on all addresses with derivation paths: * `m/44'/2'/0'/change/address_index` * `m/49'/2'/0'/change/address_index` * `m/84'/2'/0'/change/address_index` * `m/86'/2'/0'/change/address_index` If the wallet user changes to account 1 we get path `m/84'/2'/1'/0/0` with identifier `ltc1qn9h77dt0s6ar78ptxq58t2ne7tyhvfnruc3e7d`. Its total balance is the sum of all UTXO balances on all addresses with derivation paths: * `m/44'/2'/1'/change/address_index` * `m/49'/2'/1'/change/address_index` * `m/84'/2'/1'/change/address_index` * `m/86'/2'/1'/change/address_index` ## sendTransfer This method is used to sign and submit a transfer of any `amount` of Litecoin to a single `recipientAddress`, optionally including a `changeAddress` for the change amount and `memo` set as the OP\_RETURN value by supporting wallets. The transaction will be signed and broadcast upon user approval. ### Parameters * `Object` * `account` : `String` - *(Required)* The connected account's first external address. * `recipientAddress` : `String` - *(Required)* The recipient's public address. * `amount` : `String` - *(Required)* The amount of Litecoin to send, denominated in litoshis (Litecoin base unit). * `changeAddress` : `String` - *(Optional)* The sender's public address to receive change. * `memo` : `String` - *(Optional)* The OP\_RETURN value as a hex string without 0x prefix, maximum 80 bytes. ### Returns * `Object` * `txid` : `String` - The transaction id as a hex string without 0x prefix. ### Example The example below specifies a simple transfer of 1.23 LTC (123000000 Litoshi). ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "sendTransfer", "params": { "account": "ltc1q8c6fshw2dlwun7ekn9qwf37cu2rn755u9ym7p0", "recipient": "ltc1qn9h77dt0s6ar78ptxq58t2ne7tyhvfnruc3e7d", "amount": "123000000", "memo": "636861726c6579206c6f766573206865" } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "txid": "f007551f169722ce74104d6673bd46ce193c624b8550889526d1b93820d725f7" } } ``` ## getAccountAddresses This method returns all current addresses needed for a dapp to fetch all UTXOs, calculate the total balance and prepare transactions. Dapps will typically use an indexing service to query for balances and UTXOs for all addresses returned by this method, such as: * [Blockbook API](https://github.com/trezor/blockbook/blob/master/docs/api.md#get-address) * [Bitcore API](https://github.com/bitpay/bitcore/blob/master/packages/bitcore-node/docs/api-documentation.md#address) We recognize that there are two broad classes of wallets in use today: 1. Wallets that generate a new change or receive address for every transaction ("dynamic wallet"). 2. Wallets that reuse the first external address for every transaction ("static wallet"). #### Implementation Details * All wallets **should** include the first external address and all addresses with one or more UTXOs, unless they're filtered by `intentions`. * Dynamic wallets **should** include minimum 2 unused change and receive addresses. Otherwise dapps may have to request [getAccountAddresses](#getAccountAddresses) after every transaction to discover the new addresses and keep track of the user's total balance. * All wallets **must** return fewer than 20 unused change and receive addresses to avoid breaking the [gap limit](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki#address-gap-limit). ### Parameters * `Object` * `account` : `String` - *(Required)* The connected account's first external address. * `intentions` : `String[]` - *(Optional)* Filter what addresses to return, e.g. "payment" or "ordinal". ### Returns * `Array` * `Object` * `address` : `String` - *(Required)* Public address belonging to the account. * `publicKey` : `String` - *(Optional)* Public key for the derivation path in hex, without 0x prefix. * `path` : `String` - *(Optional)* Derivation path of the address e.g. "m/84'/2'/0'/0/0". * `intention` : `String` - *(Optional)* Intention of the address, e.g. "payment" or "ordinal". ### Example: Dynamic Wallet The example below specifies a result from a dynamic wallet. For the sake of this example, receive and change addresses with index 3-4 are considered unused and addresses with paths `m/49'/2'/0'/0/7` and `m/84'/2'/0'/0/2` are considered to have UTXOs. Assuming the dapp monitors all returned addresses for balance changes, a new request to `getAccountAddresses` is only needed when all UTXOs in provided addresses have been spent, or when all provided `receive` addresses or `change` addresses have been used. ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "getAccountAddresses", "params": { "account": "ltc1q8c6fshw2dlwun7ekn9qwf37cu2rn755u9ym7p0" } } // Result { "id": 1, "jsonrpc": "2.0", "result": [ { "address": "ltc1q8c6fshw2dlwun7ekn9qwf37cu2rn755u9ym7p0", "path": "m/84'/2'/0'/0/0" }, { "address": "LXkGhTKmZpviAtYdDaxWbiJsdg4tA6EzrU", "path": "m/49'/2'/0'/0/7" }, { "address": "ltc1qj4plcuyhuzw0sycf99gcayzhhcddfj6xkcke5g", "path": "m/84'/2'/0'/0/2" }, { "address": "ltc1qsdxa6pseqekqg5d3uksaxnwrey2s2ujcx03alc", "path": "m/84'/2'/0'/0/3" }, { "address": "ltc1qhuvt3sq8xmx9ktzdfznkzvjl5zup7mg9zpwllw", "path": "m/84'/2'/0'/0/4" }, { "address": "ltc1qtjd3y5a2axpwzfjcj4y9zy50qfjuxwzm0vu5fq", "path": "m/84'/2'/0'/1/3" }, { "address": "ltc1qp7ujtprgl0quvcg0dj335p37r2mc2cxdc8xumq", "path": "m/84'/2'/0'/1/4" } ] } ``` ### Example: Static Wallet The example below specifies a response from a static wallet. The returned address is used for both change and payments. It's the only address with UTXOs. ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "getAccountAddresses", "params": { "account": "ltc1q8c6fshw2dlwun7ekn9qwf37cu2rn755u9ym7p0" } } // Result { "id": 1, "jsonrpc": "2.0", "result": [ { "address": "ltc1q8c6fshw2dlwun7ekn9qwf37cu2rn755u9ym7p0", "path": "m/84'/2'/0'/0/0" } ] } ``` ## signPsbt This method can be used to request the signature of a Partially Signed Bitcoin Transaction (PSBT) and covers use-cases e.g. involving multiple-recipient transactions, requiring granular control over which UTXOs to spend or how to route change. ### Parameters * `Object` * `account` : `String` - *(Required)* The connected account's first external address. * `psbt` : `String` - *(Required)* Base64 encoded string of the PSBT to sign. * `signInputs` : `Array` * `Object` * `address` : `String` - *(Required)* The address whose private key to use for signing. * `index` : `Integer` - *(Required)* Specifies which input to sign. * `sighashTypes` : `Integer[]` - *(Optional)* Specifies which part(s) of the transaction the signature commits to. Default is `[1]`. * `broadcast` : `Boolean` - *(Optional)* Whether to finalize and broadcast the transaction after signing it. Default is `false`. ### Returns * `Object` * `psbt` : `String` - *(Required)* The base64 encoded signed PSBT. * `txid` : `String` - *(Optional)* The transaction ID as a hex-encoded string, without 0x prefix. This must be returned if the transaction was broadcasted. ## signMessage This method is used to sign a message with one of the connected account's addresses. ### Parameters * `Object` * `account` : `String` - *(Required)* The connected account's first external address. * `message` : `String` - *(Required)* The message to be signed by the wallet. * `address` : `String` - *(Optional)* The address whose private key to use for signing the message. * `protocol` : `"ecdsa" | "bip322"` - *(Optional)* Preferred signature type. Default is `"ecdsa"`. ### Returns * `Object` * `address` : `String` - *(Required)* The Litecoin address used to sign the message. * `signature` : `String` - *(Required)* Hex encoded bytes of the signature, without 0x prefix. * `messageHash` : `String` - *(Optional)* Hex encoded bytes of the message hash, without 0x prefix. ## Events ### bip122\_addressesChanged This event is used by wallets to notify dapps about connected accounts' current addresses, for example all addresses with a UTXO and a few unused addresses. The event data has the same format as the [getAccountAddresses](#getaccountaddresses) result. #### Implementation Details * Wallets **should** emit a `bip122_addressesChanged` event immediately after connection approval of a BIP122 chain. * Wallets **should** emit a `bip122_addressesChanged` event whenever a UTXO is spent or created for a connected account's addresses. * Dapps **should** listen for `bip122_addressesChanged` events, collect and monitor all addresses for UTXO and balance changes. Example [session\_event](https://specs.walletconnect.com/2.0/specs/clients/sign/session-events#session_event) payload as received by a dapp: ``` { "id": 1675759795769537, "topic": "95d6aca451b8e3c6d9d176761bf786f1cc0a6d38dffd31ed896306bb37f6ae8d", "params": { "event": { "name": "bip122_addressesChanged", "data": [ { "address": "ltc1q8c6fshw2dlwun7ekn9qwf37cu2rn755u9ym7p0", "path": "m/84'/2'/0'/0/0" }, { "address": "LXkGhTKmZpviAtYdDaxWbiJsdg4tA6EzrU", "path": "m/49'/2'/0'/0/7" }, { "address": "ltc1qj4plcuyhuzw0sycf99gcayzhhcddfj6xkcke5g", "path": "m/84'/2'/0'/0/2" }, { "address": "ltc1qsdxa6pseqekqg5d3uksaxnwrey2s2ujcx03alc", "path": "m/84'/2'/0'/0/3" }, { "address": "ltc1qhuvt3sq8xmx9ktzdfznkzvjl5zup7mg9zpwllw", "path": "m/84'/2'/0'/0/4" }, { "address": "ltc1qtjd3y5a2axpwzfjcj4y9zy50qfjuxwzm0vu5fq", "path": "m/84'/2'/0'/1/3" }, { "address": "ltc1qp7ujtprgl0quvcg0dj335p37r2mc2cxdc8xumq", "path": "m/84'/2'/0'/1/4" } ] }, "chainId": "bip122:12a765e31ffd4059bada1e25190f6e98" } } ``` # NEAR Source: https://docs.reown.com/advanced/multichain/rpc-reference/near-rpc NEAR JSON-RPC Methods The method names below are based on the [Bridge Wallets](https://github.com/near/NEPs/blob/master/specs/Standards/Wallets/BridgeWallets.md#) Standard for NEAR. ## near\_getAccounts Retrieve all accounts visible to the session. `publicKey` references the underlying `FullAccess` key linked to each account. ### Parameters none ### Returns 1.`Array` - Array of accounts: 1.1. `Object` 1.1.1. `accountId` : `String` - The account name to which the publicKey corresponds as plain text 1.1.2. `publicKey` : `String` - The public counterpart of the key used to sign, expressed as a string with format `:` ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "near_getAccounts", "params": {} } // Result { "id": 1, "jsonrpc": "2.0", "result": [{ "accountId": "alice.near", "publicKey": "ed25519:DmnRVNb89cLKZY1cH1Zcr3rxMVD9r1cVfnDac7RFwM94" }] } ``` ## near\_signIn For dApps that often sign gas-only transactions, `FunctionCall` access keys can be created for one or more accounts to greatly improve the UX. While this could be achieved with `signTransactions`, it suggests a direct intention that a user wishes to sign in to a dApp's smart contract. ### Parameters 1. `Object` - Sign In parameters: 1.1. `permission` : `Object` - Function call key permission parameters 1.1.1. `receiverId` : `String` - smart contract for which the function call access key will be created 1.1.2. `methodNames` : `Array` - list of methods that can be called on the smart contract 1.2. `accounts` : `Array` - list of accounts for which a FunctionCall access key will be added: 1.2.1. `Object` - Account 1.2.1.1. `accountId` : `String` - The account name to which the publicKey corresponds as plain text 1.2.1.2. `publicKey` : `String` - The public counterpart of the key used to sign, expressed as a string with format `:` ### Returns void ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "near_signIn", "params": { "permission": { "receiverId": "guest-book.testnet", "methodNames": [] }, "accounts": [{ "accountId": "alice.near", "publicKey": "ed25519:DmnRVNb89cLKZY1cH1Zcr3rxMVD9r1cVfnDac7RFwM94" }] } } ``` ## near\_signOut Delete one or more `FunctionCall` access keys created with `signIn`. While this could be achieved with `signTransactions`, it suggests a direct intention that a user wishes to sign out from a dApp's smart contract. ### Parameters 1.`Array` - Array of accounts: 1.1. `Object` 1.1.1. `accountId` : `String` - The account name to which the publicKey corresponds as plain text 1.1.2. `publicKey` : `String` - The public counterpart of the key used to sign, expressed as a string with format `:` ### Returns void ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "near_signOut", "params": { "accounts": [{ "accountId": "alice.near", "publicKey": "ed25519:DmnRVNb89cLKZY1cH1Zcr3rxMVD9r1cVfnDac7RFwM94" }] } } ``` ## near\_signTransaction Sign a transaction. It makes use of [near-api-js](https://github.com/near/near-api-js) to enable interoperability with dApps that will already use it for constructing transactions and communicating with RPC endpoints. [Transaction](https://nomicon.io/RuntimeSpec/Transactions) passed to `signTransaction` must be encoded. ### Parameters 1. `Object` - Signing parameters: 1.1. `transaction` : `Uint8Array` - Encoded Transaction via transactions.Transaction.encode() ### Returns The result of `signTransaction` and is encoded [SignedTransaction](https://nomicon.io/RuntimeSpec/Transactions#signed-transaction) model. 1. `Uint8Array` - Encoded SignedTransaction via transactions.SignedTransaction.encode() ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "near_signTransaction", "params": { "transaction": { "type": "Buffer", "data": [32, 0, 0, 0, 100, 101, 118, 45, 49, 54, 55, 49, 51, 56, 55, 51, 57, 56 ...] } } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "type": "Buffer", "data": [32, 0, 0, 0, 100, 101, 118, 45, 49, 54, 55, 49, 51, 56, 55, 51, 57, 56 ...] } } ``` ## near\_signTransactions Sign a list of transactions. It makes use of [near-api-js](https://github.com/near/near-api-js) to enable interoperability with dApps that will already use it for constructing transactions and communicating with RPC endpoints. [Transactions](https://nomicon.io/RuntimeSpec/Transactions) passed to `signTransactions` must be encoded. ### Parameters 1. `Array` - Signing parameters: 1.1. `transactions` : `Array` - Array of Encoded Transaction via transactions.Transaction.encode() ### Returns The result of `signTransactions` and are encoded [SignedTransaction](https://nomicon.io/RuntimeSpec/Transactions#signed-transaction) models. 1. `Array` - Array of Encoded SignedTransaction via transactions.SignedTransaction.encode() ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "near_signTransactions", "params": { "transactions": [ { "type": "Buffer", "data": [32, 0, 0, 0, 100, 101, 118, 45, 49, 54, 55, 49, 53, 52, 49, 55, 56, 57, 51, 50 ...] }, { "type": "Buffer", "data": [32, 0, 0, 0, 100, 101, 118, 45, 49, 54, 55, 49, 53, 52, 49, 55, 56, 57, 51, 50 ...] } ] } } // Result { "id": 1, "jsonrpc": "2.0", "result": [ { "type": "Buffer", "data": [32, 0, 0, 0, 100, 101, 118, 45, 49, 54, 55, 49, 53, 52, 49, 55, 56, 57, 51, 50 ...] }, { "type": "Buffer", "data": [32, 0, 0, 0, 100, 101, 118, 45, 49, 54, 55, 49, 53, 52, 49, 55, 56, 57, 51, 50 ...] } ] } ``` # Solana Source: https://docs.reown.com/advanced/multichain/rpc-reference/solana-rpc Solana JSON-RPC Methods ## solana\_getAccounts This method returns an Array of public keys available to sign from the wallet. ### Parameters none ### Returns `Array` - Array of accounts: * `Object` : * `pubkey` : `String` - public key for keypair ### Example ```typescript // Request { "id": 1, "jsonrpc": "2.0", "method": "solana_getAccounts", "params": {} } // Result { "id": 1, "jsonrpc": "2.0", "result": [{ "pubkey": "722RdWmHC5TGXBjTejzNjbc8xEiduVDLqZvoUGz6Xzbp" }] } ``` ## solana\_requestAccounts This method returns an Array of public keys available to sign from the wallet. ### Parameters none ### Returns `Array` - Array of accounts: * `Object` : * `pubkey` : `String` - public key for keypair ### Example ```typescript // Request { "id": 1, "jsonrpc": "2.0", "method": "solana_getAccounts", "params": {} } // Result { "id": 1, "jsonrpc": "2.0", "result": [{ "pubkey": "722RdWmHC5TGXBjTejzNjbc8xEiduVDLqZvoUGz6Xzbp" }] } ``` ## solana\_signMessage This method returns a signature for the provided message from the requested signer address. ### Parameters `Object` - Signing parameters: * `message` : `String` - the message to be signed (base58 encoded) * `pubkey` : `String` - public key of the signer ### Returns `Object`: * `signature` : `String` - corresponding signature for signed message ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "solana_signMessage", "params": { "message": "37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7", "pubkey": "AqP3MyNwDP4L1GJKYhzmaAUdrjzpqJUZjahM7kHpgavm" } } // Result { "id": 1, "jsonrpc": "2.0", "result": { signature: "2Lb1KQHWfbV3pWMqXZveFWqneSyhH95YsgCENRWnArSkLydjN1M42oB82zSd6BBdGkM9pE6sQLQf1gyBh8KWM2c4" } } ``` ## solana\_signTransaction This method returns a signature over the provided instructions by the targeted public key. **WARNING**: Refer always to `transaction` param. The deprecated parameters are not compatible with versioned transactions. ### Parameters `Object` - Signing parameters:
* `transaction` : `String` - base64-encoded serialized transaction
* **\[deprecated]** `feePayer` : `String | undefined` - public key of the transaction fee payer
* **\[deprecated]** `instructions` : `Array` of `Object` or `undefined` - instructions to be atomically executed:
 - `Object` - instruction
 - `programId` : `String` - public key of the on chain program
 - `data` : `String | undefined` - encoded calldata for instruction
 - `keys` : `Array` of `Object` - account metadata used to define instructions
  - `Object` - key
   - `isSigner` : `Boolean` - true if an instruction requires a transaction signature matching `pubkey`
   - `isWritable` : `Boolean` - true if the `pubkey` can be loaded as a read-write account
   - `pubkey` : `String` - public key of authorized program
* **\[deprecated]** `recentBlockhash` : `String | undefined` - a recent blockhash
* **\[deprecated]** `signatures` : `Array` of `Object` or `undefined` - (optional) previous partial signatures for this instruction set
 - `Object` - partial signature
 - `pubkey` : `String` - pubkey of the signer
 - `signature` : `String` - signature matching `pubkey`
### Returns `Object`: * `signature`: `String` - corresponding signature for signed instructions * `transaction`?: `String | undefined` - optional: base64-encoded serialized transaction ### Example ```typescript // Request { "id": 1, "jsonrpc": "2.0", "method": "solana_signTransaction", "params": { "feePayer": "AqP3MyNwDP4L1GJKYhzmaAUdrjzpqJUZjahM7kHpgavm", "instructions": [{ "programId": "Vote111111111111111111111111111111111111111", "data": "37u9WtQpcm6ULa3VtWDFAWoQc1hUvybPrA3dtx99tgHvvcE7pKRZjuGmn7VX2tC3JmYDYGG7", "keys": [{ "isSigner": true, "isWritable": true, "pubkey": "AqP3MyNwDP4L1GJKYhzmaAUdrjzpqJUZjahM7kHpgavm" }] }], "recentBlockhash": "2bUz6wu3axM8cDDncLB5chWuZaoscSjnoMD2nVvC1swe", "signatures": [{ "pubkey": "AqP3MyNwDP4L1GJKYhzmaAUdrjzpqJUZjahM7kHpgavm", "signature": "2Lb1KQHWfbV3pWMqXZveFWqneSyhH95YsgCENRWnArSkLydjN1M42oB82zSd6BBdGkM9pE6sQLQf1gyBh8KWM2c4" }], "transaction": "r32f2..FD33r" } } // Result { "id": 1, "jsonrpc": "2.0", "result": { signature: "2Lb1KQHWfbV3pWMqXZveFWqneSyhH95YsgCENRWnArSkLydjN1M42oB82zSd6BBdGkM9pE6sQLQf1gyBh8KWM2c4" } } ``` ## solana\_signAllTransactions This method is responsible for signing a list of transactions. The wallet must sign all transactions and return the signed transactions in the same order as received. Wallets must sign all transactions or return an error if it is not possible to sign any of them. ### Parameters `Object` - Signing parameters: * `transactions` : `String[]` - base64-encoded serialized list of transactions
### Returns `Object`: * `transactions` : `String[]` - base64-encoded serialized list of signed transactions in the same order as received
### Example ```typescript // Request { "id": 1, "jsonrpc": "2.0", "method": "solana_signAllTransactions", "params": { "transactions": string[] } } // Response { "id": 1, "jsonrpc": "2.0", "result": { "transactions": string[] } } ``` ## solana\_signAndSendTransaction This method is responsible for signing and sending a transaction to the Solana network. The wallet must sent the transaction and return the signature that can be used as a transaction id. ### Parameters `Object` - transaction and options:
* `transaction` : `String` - the whole transaction serialized and encoded with base64
* `sendOptions` : `Object` - options for sending the transaction
* `skipPreflight` : `Boolean` - skip preflight checks
* `preflightCommitment` : `'processed' | 'confirmed' | 'finalized' | 'recent' | 'single' | 'singleGossip' | 'root' | 'max'` - preflight commitment level
* `maxRetries` : `Number` - maximum number of retries
* `minContextSlot` : `Number` - minimum context slot
### Returns `Object`: * `signature` : `String`, - the signature of the transaction encoded with base58 used as transaction id
### Example ```typescript // Request { "id": 1, "jsonrpc": "2.0", "method": "solana_signAndSendTransaction", "params": { "transaction": string, "sendOptions": { "skipPreflight"?: boolean, "preflightCommitment"?: 'processed' | 'confirmed' | 'finalized' | 'recent' | 'single' | 'singleGossip' | 'root' | 'max', "maxRetries"?: number, "minContextSlot"?: number, } } } // Response { "id": 1, "jsonrpc": "2.0", "result": { "signature": string } } ``` # Starknet Source: https://docs.reown.com/advanced/multichain/rpc-reference/starknet-rpc Starknet JSON-RPC Methods We define new types for starknet: * `FELT`, a number represented by a hex string. Prefixed with 0x. It can be left padded with zeroes or not. It follows the [Cairo Field Element spec](https://www.cairo-lang.org/docs/how_cairo_works/cairo_intro.html#field-elements) * `ABI`, a representation of a Starknet contract’s interface. As [Starknet ABI Spec](https://docs.starknet.io/documentation/architecture_and_concepts/Contracts/contract-abi/) ## starknet\_requestAddInvokeTransaction Requests the wallet to sign and submit a [INVOKE transaction](https://docs.starknet.io/documentation/architecture_and_concepts/Blocks/transactions/#invoke_transaction) This request might be processed before the account is deployed. In that scenario the wallet will ask the user to do the deployment and the requested transaction. ### Parameters ``` 1. `FELT`, `accountAddress` : Account that is being requested to send a transaction 2. `Object`, `executionRequest` : Transaction requested 2.1. `calls` : `Object[]` array of calls to perform 2.1.1. `contractAddress` : `Felt` 2.1.2. `entrypoint` : `Felt` 2.1.3. `calldata` : `Felt[]` (Optional) 2.2. `abis` : `ABI[]` (Optional) one or more contract abis which can be used to display the calls ``` ### Example Parameters ```javascript { "accountAddress": "0x003a8278a26f32452f156260d81b93efb0eca126b44df7b005a5b27e2bbc4a64", "executionRequest" : { "calls" : [ { "contractAddress": "0x003a8278a26f32452f156260d81b93efb0eca126b44df7b005a5b27e2bbc4a64", "entrypoint": "0x555278a26f32452f156260d81b93efb0eca126b44df7b005a5b27e2bbc4a64", "calldata": ["0x003", "0xa82705a5b27e2bbc4a64"] }, { "contractAddress": "0x00111178a26f32452f156260d81b93efb0eca126b44df7b005a5b27e2bbc4a64", "entrypoint": "0x0022228a26f32452f156260d81b93efb0eca126b44df7b005a5b27e2bbc4a64" } ], "abis" : [{ "inputs": [{ "name": "amount", "type": "felt" }], "name": "set_balance", "outputs": [], "type": "function" }] } } ``` ### Returns 1. `FELT`, `transaction_hash` : The hash of the transaction submitted by the wallet ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "starknet_requestAddInvokeTransaction", "params":{see above} } // Result { "id": 1, "jsonrpc": "2.0", "result": { "transaction_hash" : "0x01d666de4dc4d7e888190475ea6381a862e7d77cc3cb425e72ebf85e1d5144fa" } } ``` ## starknet\_signTypedData Request the wallet to sign an *Off-chain message* as defined here [Starknet Off-chain message spec](https://community.starknet.io/t/signing-transactions-and-off-chain-messages/66). This is similar to Ethereum's EIP-712 This request might be processed before the account is deployed. In that scenario the wallet will ask the user to do the deployment and sign the data ### Parameters account, message ``` 1. `FELT`, `accountAddress` : account address used for signing. 2. `Object`, `typedData` : typed data to sign containing type information, a domain separator, and data. It follows the Starknet Off-chain message spec ``` ### Example Parameters ```javascript { "accountAddress" : "0x003a8278a26f32452f156260d81b93efb0eca126b44df7b005a5b27e2bbc4a64", "typedData" : { "types" : { "StarkNetDomain ": [ { "name" : "name", "type" : "felt" }, { "name" : "version", "type" : "felt" }, { "name" : "chainId", "type" : "felt" } ], "Person" : [ { "name": "name", "type" : "felt" }, { "name": "wallet", "type" : "felt" } ], "Mail": [ { "name": "from", "type": "Person" }, { "name": "to", "type": "Person" }, { "name": "contents", "type": "felt" } ] }, "primaryType" : "Mail", "domain" : { "name" : "StarkNet Mail", "version" : "1", "chainId" : 1 }, "message" : { "from" : { "name" : "Cow", "wallet" : "0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826" }, "to": { "name" : "Bob", "wallet" : "0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB" }, "contents" : "Hello, Bob!" } } } ``` ### Returns 1. `FELT[]`, `signature` : Signature as an array of Felts ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "starknet_signTypedData", "params": ["0x003a8278a26f32452f156260d81b93efb0eca126b44df7b005a5b27e2bbc4a64", {see above}] } // Result { "id": 1, "jsonrpc": "2.0", "result": { "signature" : ["0x3a8278a26f32452f156260d81b93efb0eca126b44df7b005a5b27e2bbc4a64", "0x072e509b6502e2bbc4a649052eb6c299d53a04e16605b915621c", "0x07897a1b93efb0eca126b44df4646", "0x072e509b6502e2bbc4a649052eb6c299d53a04e16605b915621c"] } } ``` # Stellar Source: https://docs.reown.com/advanced/multichain/rpc-reference/stellar-rpc Stellar JSON-RPC Methods ## stellar\_signAndSubmitXDR This method sends the Stellar transaction encoded as [XDR](https://developers.stellar.org/api/introduction/xdr/) to the wallet. The wallet is expected to sign the transaction and submit it to the Stellar network. For accounts protected with [multisig](https://developers.stellar.org/docs/glossary/multisig/), the wallet should also handle the collection of signatures and submission of the transaction at a later time. The method returns the transaction status: `success` - if the transaction was successfully confirmed in the Stellar network, `pending` - if the transaction requires additional signatures ### Parameters 1. `Object` - Signing parameters: 1.1. `xdr` : `STRING` - stellar transaction encoded as XDR ### Returns 1. `Object` - Signing parameters: 1.1. `status` : `success` or `pending` ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "stellar_signAndSubmitXDR", "params": { "xdr": "AAAAAPewD+/6X8o0bx3bp49Wf+mUhG3o+TUrcjcst717DWJVAAAAyAFvzscADTkNAAAAAAAAAAAAAAACAAAAAAAAAAYAAAACWE1BVEsAAAAAAAAAAAAAAAPvNOuztX4IjvV8pztsEc1/ZnTz0G3p5Cx4vcf04+xUAAONfqTGgAAAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAD2NyeXB0b21hcmluZS5ldQAAAAAAAAAAAAAAAAF7DWJVAAAAQK3vfUCZ8mbjW3ssMd0n1tJTF9Fv6EbuJ6cWKkYXBqG5itqanPbFzIQoZEHbPS8nr2vo4dROvKI0uQzNcfExKwM=" } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "status": "success" } } ``` ## stellar\_signXDR This method sends the Stellar transaction encoded as [XDR](https://developers.stellar.org/api/introduction/xdr/) to the wallet. The wallet is expected to sign the transaction and return the signed transaction. ### Parameters 1. `Object` - Signing parameters: 1.1. `xdr` : `STRING` - stellar transaction encoded as XDR ### Returns 1. `Object` - Signing parameters: 1.1. `signedXDR` : `STRING` - stellar transaction encoded as XDR ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "stellar_signXDR", "params": { "xdr": "AAAAAPewD+/6X8o0bx3bp49Wf+mUhG3o+TUrcjcst717DWJVAAAAyAFvzscADTkNAAAAAAAAAAAAAAACAAAAAAAAAAYAAAACWE1BVEsAAAAAAAAAAAAAAAPvNOuztX4IjvV8pztsEc1/ZnTz0G3p5Cx4vcf04+xUAAONfqTGgAAAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAD2NyeXB0b21hcmluZS5ldQAAAAAAAAAAAAAAAAF7DWJVAAAAQK3vfUCZ8mbjW3ssMd0n1tJTF9Fv6EbuJ6cWKkYXBqG5itqanPbFzIQoZEHbPS8nr2vo4dROvKI0uQzNcfExKwM=" } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "signedXDR": "AAAAAPewD+/6X8o0bx3bp49Wf+mUhG3o+TUrcjcst717DWJVAAAAyAFvzscADTkNAAAAAAAAAAAAAAACAAAAAAAAAAYAAAACWE1BVEsAAAAAAAAAAAAAAAPvNOuztX4IjvV8pztsEc1/ZnTz0G3p5Cx4vcf04+xUAAONfqTGgAAAAAAAAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAD2NyeXB0b21hcmluZS5ldQAAAAAAAAAAAAAAAAF7DWJVAAAAQK3vfUCZ8mbjW3ssMd0n1tJTF9Fv6EbuJ6cWKkYXBqG5itqanPbFzIQoZEHbPS8nr2vo4dROvKI0uQzNcfExKwM=" } } ``` # Tezos Source: https://docs.reown.com/advanced/multichain/rpc-reference/tezos-rpc Tezos JSON-RPC Methods ## tezos\_getAccounts This method returns an array of public keys, which correspond to keypairs available in the wallet for signing. ### Parameters none ### Returns 1.`Array` - Array of accounts: 1.1. `Object` - Account Data object with parameters: 1.1.1. `algo` : `STRING` - algorithm used for signing 1.1.2. `address` : `STRING` - corresponding address for keypair 1.1.3. `pubkey` : `STRING` - public key for keypair ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "tezos_getAccounts", "params": {} } // Result { "id": 1, "jsonrpc": "2.0", "result": [ { "algo": "ed25519", "address": "tz1VQA4RP4fLjEEMW2FR4pE9kAg5abb5h5GL", "pubkey": "edpku4US3ZykcZifjzSGFCmFr3zRgCKndE82estE4irj4d5oqDNDvf" } ] } ``` ## tezos\_send This method returns a hash for the provided operations. They will be signed by the keypair corresponding to the requested signer address and sent to the blockchain. ### Parameters 1. `Object` - Signing parameters: 1.1. `account` : `STRING` - corresponding address for keypair 1.2. `operations` : `Array` - operations to be signed: 1.2.1. `Object` - identifier of blockchain 1.2.1.1. `kind` : `STRING` - type of the operation 1.2.1.2. `destination` : `STRING` - recipient of the operation 1.2.1.3. `amount` : `STRING` - mutez amount 1.2.1.4. `fee` : `STRING` - (optional) operation fee - NOTE: Not all wallets will respect this value because it's usually set by the wallet depending on network usage 1.2.1.5. `gas_limit` : `STRING` - (optional) integer of the gas\_limit 1.2.1.6. `storage_limit` : `STRING` - (optional) integer of the storage\_limit 1.2.1.7. `parameters` : `Object` - (optional) contract call data Note: All [RPC Operations](https://github.com/ecadlabs/taquito/blob/4dc6c391047b977b11eb92c7f5a5bc508ca32f01/packages/taquito/src/operations/types.ts#L553C13-L567) are valid. The above definition describes only the most common operation type. ### Returns 1. `Object` - Signing parameters: 1.1. `operationHash` : `STRING` - hash of the operation ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "tezos_send", "params": { "account": "tz1VQA4RP4fLjEEMW2FR4pE9kAg5abb5h5GL", "operations": [ { "kind": "transaction"; "amount": "1"; "destination": "tz1VQA4RP4fLjEEMW2FR4pE9kAg5abb5h5GL"; } ] } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "operationHash": "op..." } } ``` ## tezos\_sign This method returns a signature for the provided payload. It will be signed by the keypair corresponding to the requested signer address. ### Parameters 1. `Object` - Signing parameters: 1.1. `account` : `STRING` - corresponding address for keypair 1.2. `payload` : `STRING` - payload to be signed ### Returns 1. `Object` - Signing parameters: 1.1. `signature` : `STRING` - signature for signed payload ### Example ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "tezos_sign", "params": { "account": "tz1VQA4RP4fLjEEMW2FR4pE9kAg5abb5h5GL", "payload": "05010000004254", } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "signature": "edsig..." } } ``` # XRPL Source: https://docs.reown.com/advanced/multichain/rpc-reference/xrpl-rpc XRPL JSON-RPC Methods ## xrpl\_signTransaction This method is used to sign and submit a transaction to the XRP Ledger (XRPL). Every transaction has the same set of [common fields][XRPL Transaction Common Fields], plus additional fields based on the [transaction type][XRPL Transaction Types]. It is expected that the dapp provides all transaction fields defined as `required`, but not necessarily the `auto-fillable`. ### Parameters * `Object` * `tx_json` : `Object` - *(Required)* JSON specification of the transaction. * `autofill` : `Boolean` - *(Optional)* Defaults to `true`. Set to `false` to skip auto-filling parameters. * `submit` : `Boolean` - *(Optional)* Defaults to `true`. Set to `false` to skip submitting the transaction. Please note that if you set `submit` to `false`, your dapp will need to encode the signed `tx_json` to the required [binary format][XRPL Serialization], before you can send it as `tx_blob` to an XRPL node using the [submit][XRPL Signed Transaction] command. ### Returns * `Object` * `tx_json` : `Object` - JSON specification of the complete transaction as signed, including any fields that were auto-filled. ### Example The example below specifies a simple DEX order for selling 15,000 XRP in exchange for 7,072.8 USD. ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "xrpl_signTransaction", "params": { "tx_json": { "TransactionType": "OfferCreate", "Account": "rMBzp8CgpE441cp5PVyA9rpVV7oT8hP3ys", "Flags": 524288, "LastLedgerSequence": 7108682, "Expiration": 595640108, "TakerGets": "15000000000", "TakerPays": { "currency": "USD", "issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B", "value": "7072.8" } } } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "tx_json": { "Account": "rMBzp8CgpE441cp5PVyA9rpVV7oT8hP3ys", "Expiration": 595640108, "Fee": "10", "Flags": 524288, "OfferSequence": 1752791, "Sequence": 1752792, "LastLedgerSequence": 7108682, "SigningPubKey": "03EE83BB432547885C219634A1BC407A9DB0474145D69737D09CCDC63E1DEE7FE3", "TakerGets": "15000000000", "TakerPays": { "currency": "USD", "issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B", "value": "7072.8" }, "TransactionType": "OfferCreate", "TxnSignature": "30440220143759437C04F7B61F012563AFE90D8DAFC46E86035E1D965A9CED282C97D4CE02204CFD241E86F17E011298FC1A39B63386C74306A5DE047E213B0F29EFA4571C2C", "hash": "73734B611DDA23D3F5F62E20A173B78AB8406AC5015094DA53F53D39B9EDB06C" } } } ``` ## xrpl\_signTransactionFor This method is used to add a signature to a [multi-signed][XRPL Multisign] transaction. The same common fields and transaction types as single-signed transactions are supported. ### Parameters * `Object` * `tx_signer` : `String` - *(Required)* The XRPL address of the signer. * `tx_json` : `Object` - *(Required)* JSON specification of the transaction. * `autofill` : `Boolean` - *(Optional)* Defaults to `false`. Set to `true` to auto-fill parameters. * `submit` : `Boolean` - *(Optional)* Defaults to `false`. Set to `true` to submit the transaction. Please note that `autofill` and `submit` both defaults to `false`, since explicit transaction specification and controlled submission is typically needed for multi-signed transactions. ### Returns * `Object` * `tx_json` : `Object` - JSON specification of the complete transaction as signed, including any fields that were auto-filled. ### Example The example below specifies a multi-signed payment transaction, already signed ([in serial][XRPL Multisign Methods]) by 3 of 4 required signers. Since only one more signature is required, the optional `submit` parameter has been set to `true`. ```javascript // Request { "id": 1, "jsonrpc": "2.0", "method": "xrpl_signTransactionFor", "params": { "submit": true, "tx_signer": "rJ4wmkgK8n93UjtaqQTaj1vxBwQWdLrBjP", "tx_json": { "Account": "rh2EsAe2xVE71ZBjx7oEL2zpD4zmSs3sY9", "TransactionType": "Payment", "Amount": "400000000000000", "Destination": "r9NpyVfLfUG8hatuCCHKzosyDtKnBdsEN3", "Fee": "5000", "Flags": 2147483648, "LastLedgerSequence": 73541531, "Sequence": 38, "Signers": [ { "Signer": { "Account": "re3LGjhrCvthtWWwrfKbVJjXN9PYDeQDJ", "SigningPubKey": "0320ECD5569CAFA4E23147BE238DBFB268DB3B5A502ED339387AC7DCA0ADC6FB90", "TxnSignature": "3045022100EC2BF025E748A028187EDB3C350D518F91F05BC201EAFC9C92566DE9E48AA1B7022018847D172386E93679630E3905BD30481359E5766931944F79F1BA6D910F5C01" } }, { "Signer": { "Account": "rpcL6T32dYb6FDgdm4CnC1DZQSoMvvkLRd", "SigningPubKey": "030BF97DA9A563A9A0679DD527F615CF8EA6B2DB55543075B72822B8D39910B5E1", "TxnSignature": "304402201A891AF3945C81E2D6B95213B79E9A31635209AF0FB94DA8C0983D15F454179B0220388679E02CE6DE2AAC904A9C2F42208418BEF60743A7F9F76FC36D519902DA8C" } }, { "Signer": { "Account": "r3vw3FnkXn2L7St45tzpySZsXVgG75seNk", "SigningPubKey": "030BE281F6DFF9AFD260003375B64235DDBCD5B7A54511BE3DA1FEF1ADE4A85D87", "TxnSignature": "3044022049D36ACE39F1208B4C78A1550F458E54E21161FA4B52B3763C8FA9C4FE45B52C022003BE3579B5B5558A27BB7DC6A8ED163999A451665974138298469C1FDACA615F" } } ], "SigningPubKey": "" } } } // Result { "id": 1, "jsonrpc": "2.0", "result": { "tx_json": { "Account": "rh2EsAe2xVE71ZBjx7oEL2zpD4zmSs3sY9", "TransactionType": "Payment", "Amount": "400000000000000", "Destination": "r9NpyVfLfUG8hatuCCHKzosyDtKnBdsEN3", "Fee": "5000", "Flags": 2147483648, "LastLedgerSequence": 73541531, "Sequence": 38, "Signers": [ { "Signer": { "Account": "re3LGjhrCvthtWWwrfKbVJjXN9PYDeQDJ", "SigningPubKey": "0320ECD5569CAFA4E23147BE238DBFB268DB3B5A502ED339387AC7DCA0ADC6FB90", "TxnSignature": "3045022100EC2BF025E748A028187EDB3C350D518F91F05BC201EAFC9C92566DE9E48AA1B7022018847D172386E93679630E3905BD30481359E5766931944F79F1BA6D910F5C01" } }, { "Signer": { "Account": "rpcL6T32dYb6FDgdm4CnC1DZQSoMvvkLRd", "SigningPubKey": "030BF97DA9A563A9A0679DD527F615CF8EA6B2DB55543075B72822B8D39910B5E1", "TxnSignature": "304402201A891AF3945C81E2D6B95213B79E9A31635209AF0FB94DA8C0983D15F454179B0220388679E02CE6DE2AAC904A9C2F42208418BEF60743A7F9F76FC36D519902DA8C" } }, { "Signer": { "Account": "r3vw3FnkXn2L7St45tzpySZsXVgG75seNk", "SigningPubKey": "030BE281F6DFF9AFD260003375B64235DDBCD5B7A54511BE3DA1FEF1ADE4A85D87", "TxnSignature": "3044022049D36ACE39F1208B4C78A1550F458E54E21161FA4B52B3763C8FA9C4FE45B52C022003BE3579B5B5558A27BB7DC6A8ED163999A451665974138298469C1FDACA615F" } }, { "Signer": { "Account": "rJ4wmkgK8n93UjtaqQTaj1vxBwQWdLrBjP", "SigningPubKey": "02D5D616D4005B91DE02BF6E29157B514C667810860F389CF36DC9E4D5E73BFE79", "TxnSignature": "304402207589FA73E72F85A2C8F82BBCB3C7C67C455D4C14A946BA427A4735F4ED106123022069845499A9DE50F26765F097BA0EA3C96E56A1304B380E0533514AEEF29363D7" } } ], "SigningPubKey": "", "hash": "BA2AF0C652F46C97B85C1D17080EEC7422C092B0BD906DCA344B42EF30FA8285", } } } ``` [XRPL Transaction Common Fields]: https://xrpl.org/transaction-common-fields.html [XRPL Transaction Types]: https://xrpl.org/transaction-types.html [XRPL Signed Transaction]: https://xrpl.org/transaction-basics.html#example-signed-transaction-blob [XRPL Serialization]: https://xrpl.org/serialization.html#examples [XRPL Algorithms]: https://xrpl.org/cryptographic-keys.html#signing-algorithms [XRPL Multisign]: https://xrpl.org/multi-signing.html#multi-signing [XRPL Multisign Methods]: https://xrpl.org/send-a-multi-signed-transaction.html#3-get-additional-signatures # Ethereum Provider Source: https://docs.reown.com/advanced/providers/ethereum [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193) compliant Provider for the WalletConnect v2 protocol. Built on top of [Universal Provider](./universal) and [WalletConnectModal](../walletconnectmodal/about). You can use this on it's own or pass it down to libraries like ethers, viem or web3js. `showQrModal` has been deprecated as WalletConnect's Web3Modal is now rebranded as Reown's AppKit. If you are looking to use this, please refer to the ["**Use with AppKit**"](#use-with-appkit) section below. ## Installation ```bash npm npm install @walletconnect/ethereum-provider ``` ```bash Yarn yarn add @walletconnect/ethereum-provider ``` ```bash Bun bun add @walletconnect/ethereum-provider ``` ```bash pnpm pnpm add @walletconnect/ethereum-provider ``` ## Initialization Initialize Ethereum Provider by calling its `init` method and passing down the required arguments: ```ts import { EthereumProvider } from "@walletconnect/ethereum-provider"; const provider = await EthereumProvider.init({ projectId: "YOUR_PROJECT_ID", metadata: { name: "My Website", description: "My Website Description", url: "https://mywebsite.com", // origin must match your domain & subdomain icons: ["https://avatars.githubusercontent.com/u/37784886"], }, showQrModal: true, optionalChains: [1, 137, 2020], /*Optional - Add custom RPCs for each supported chain*/ rpcMap: { 1: "mainnet.rpc...", 137: "polygon.rpc...", }, }); ``` * Make sure that `url` from `metadata` matches your domain and subdomain. This will later be used by [Verify API](../../cloud/verify) to confirm if your application has been verified or not. * We recommend using `optionalChains` (optional namespaces) over `chains` (required namespaces).\ *Required namespaces* will block wallets from connecting to your application if any of the chains are not supported by the wallet. Smart Contract Wallets can only support one chain, the one that they had been deployed to, this might cause issues when using required namespaces. * Using `chains`, `methods` or `events` will create a *Required Namespaces* object internally. * `optionalMethods` and `optionalChains` default to the following methods and events: [Read source code](https://github.com/WalletConnect/walletconnect-monorepo/blob/v2.0/providers/ethereum-provider/src/constants/rpc.ts). * If `rpcMap` is not defined it will fallback to [Blockchain API](../../cloud/blockchain-api) RPCs. Keep in mind that Blockchain API supports a limited [list of chains](https://github.com/WalletConnect/rpc-proxy/blob/master/SUPPORTED_CHAINS.md). ### Init Params The Ethereum Provider's `init` method takes the following parameters: | Value | Description | Type | Required | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | -------- | | **projectId** | Your project ID obtained from Reown Cloud: [https://cloud.reown.com/](https://cloud.reown.com/) | `string` | true | | **optionalChains** | An array of the chain IDs you want to support. It is highly recommended to use "optionalChains" over "chains" for multi-chain dapps, ensuring compatibility with Smart Contract Wallets. | `number[]` | false | | **optionalMethods** | The Ethereum methods you want to support and send in the session proposal under the "optionalNamespaces" scope. If undefined, it defaults to all EIP-1193 compatible methods. | `string[]` | false | | **optionalEvents** | The Ethereum events you want to support and send in the session proposal under the "optionalNamespaces" scope. If undefined, it defaults to all EIP-1193 compatible events. | `string[]` | false | | **rpcMap** | An object whose keys are chain IDs and values are their RPC endpoints. | `Record` | false | | **metadata** | Your application's metadata. It is important to set the correct URL, as this will later be used by the Verify API to check if your domain has been verified. | `Metadata` | false | | **qrModalOptions** | An array of WalletConnectModal options. See WalletConnectModal options. | `QrModalOptions` | false | | **chains** | An array of required chain IDs you want to support. If the wallet does not support these chains, it will not be able to connect. Not recommended for multi-chain applications. | `number[]` | false | | **methods** | The required methods you want to support. Not recommended for multi-chain applications. | `string[]` | false | | **events** | The required events you want to support. Not recommended for multi-chain applications. | `string[]` | false | ## Use with AppKit The QRModal is enabled by default on reown's AppKit. In order to use it, all you need to do is to create an AppKit instance. ### Installation ```bash npm npm install @reown/appkit ``` ```bash Yarn yarn add @reown/appkit ``` ```bash Bun bun add @reown/appkit ``` ```bash pnpm pnpm add @reown/appkit ``` ### Setup Upon integrating the below code, you will be able to see the QRModal on your Web3 App. ```tsx import { createAppKit } from "@reown/appkit"; import { mainnet, arbitrum, sepolia } from "@reown/appkit/networks"; // 1. Get projectId from https://cloud.reown.com const projectId = "YOUR_PROJECT_ID"; // 2. Create the AppKit instance const modal = createAppKit({ networks: [mainnet, arbitrum, sepolia], projectId, }); ``` ## Use without AppKit You can subscribe to the `display_uri` event and handle the URI yourself. ```ts function handleURI(uri: string) { //code... } provider.on("display_uri", handleURI); await provider.connect(); // or const accounts = await provider.enable(); ``` You can then use the URI to generate a QR Code or redirect the user from the mobile browser to the wallet and request to connect. The later one will require you to use the wallet's deep link and the URI. You can get the deep link of wallets that support the WalletConnect v2 protocol from the [Explorer API](../../cloud/explorer.md). ## Sending Requests ```typescript const result = await provider.request({ method: "eth_requestAccounts" }); // OR provider.sendAsync({ method: "eth_requestAccounts" }, CallBackFunction); ``` ## Events ```typescript // chain changed provider.on("chainChanged", handler); // accounts changed provider.on("accountsChanged", handler); // session established provider.on("connect", handler); // session event - chainChanged/accountsChanged/custom events provider.on("session_event", handler); // connection uri provider.on("display_uri", handler); // session disconnected from the wallet - this won't be called when the disconnect function is called from the dapp. provider.on("disconnect", handler); ``` ## Session data Once a wallet is connected you can find the session data in the `provider.session` object. The session object includes the following properties, *among others*: * **namespaces**: `session.namespaces` is an object that contains the approved session data. Note that the `chains` object is an optional parameter and may be undefined. Therefore, we encourage apps to obtain the approved chains from the `session.accounts` object instead. ```ts interface Namespaces { chains?: string[]; accounts: string[]; methods: string[]; events: string[]; } ``` * **requiredNamespaces, optionalNamespaces & sessionProperties**: These objects contain the namespaces and properties proposed for the session. * **peer**: The `session.peer.metadata` object contains the metadata of the connected wallet. ```ts interface Metadata { name: string; description: string; url: string; icons: string[]; verifyUrl?: string; redirect?: { native?: string; universal?: string; }; } ``` Find the complete type definition of the `session` object [here](https://github.com/WalletConnect/walletconnect-monorepo/blob/022e4d492c9862ab9b17c1a7b12884bdcd992ae4/packages/types/src/sign-client/session.ts#L25). # Solana Adapter Source: https://docs.reown.com/advanced/providers/solana-adapter The WalletConnect Solana Adapter allows you to integrate the WalletConnect protocol into the Wallet Adapter library. If you are not familiar with the Wallet Adapter library it is recommended to use [AppKit instead](../../appkit//overview). AppKit now supports multichain, which means you can choose and configure multiple blockchain networks within your instance of AppKit, extending beyond just Ethereum-based (EVM) networks. ## Installation `bash npm npm install @walletconnect/solana-adapter ` `bash Yarn yarn add @walletconnect/solana-adapter ` `bash Bun bun add @walletconnect/solana-adapter ` `bash pnpm pnpm add @walletconnect/solana-adapter ` ## Cloud Configuration Create a new project on Reown Cloud at [https://cloud.reown.com](https://cloud.reown.com) and obtain a new project ID. **Don't have a project ID?** Head over to Reown Cloud and create a new project now! ## Implementation Add the `WalletConnectAdapter` to your wallets list. ```tsx {12, 22-27} import { ReactNode, useMemo, useState } from "react"; import { ConnectionProvider, WalletProvider, } from "@solana/wallet-adapter-react"; import { WalletAdapterNetwork } from "@solana/wallet-adapter-base"; import { WalletModalProvider } from "@solana/wallet-adapter-react-ui"; import { clusterApiUrl } from "@solana/web3.js"; import "@solana/wallet-adapter-react-ui/styles.css"; import { WalletConnectWalletAdapter } from "@walletconnect/solana-adapter"; export const SolanaContext = ({ children }: { children: ReactNode }) => { const endpoint = useMemo( () => clusterApiUrl(WalletAdapterNetwork.Mainnet), [] ); const wallets = useMemo( () => [ new WalletConnectWalletAdapter({ network: WalletAdapterNetwork.Mainnet, options: { projectId: "YOUR_PROJECT_ID", }, }), ], // eslint-disable-next-line react-hooks/exhaustive-deps [] ); return ( {children} ); }; ``` # Universal Provider Source: https://docs.reown.com/advanced/providers/universal Universal Provider is a multi-chain provider for WalletConnect v2 protocol. Find more about different supported chains [here](../../cloud/chains/overview.md). ## Installation ```bash npm npm install @walletconnect/universal-provider ``` ```bash Yarn yarn add @walletconnect/universal-provider ``` ```bash Bun bun add @walletconnect/universal-provider ``` ```bash pnpm pnpm add @walletconnect/universal-provider ``` ## Usage ```typescript import UniversalProvider from "@walletconnect/universal-provider"; // Initialize the provider const provider = await UniversalProvider.init({ projectId: "YOUR_PROJECT_ID", metadata: { name: "React App", description: "React App for WalletConnect", url: "https://walletconnect.com/", icons: ["https://avatars.githubusercontent.com/u/37784886"], }, client: undefined, // optional instance of @walletconnect/sign-client }); // create sub providers for each namespace/chain await provider.connect({ optionalNamespaces: { eip155: { methods: [ "eth_sendTransaction", "eth_signTransaction", "eth_sign", "personal_sign", "eth_signTypedData", ], chains: ["eip155:80001"], events: ["chainChanged", "accountsChanged"], rpcMap: { 80001: "https://rpc.walletconnect.com?chainId=eip155:80001&projectId=", }, }, }, pairingTopic: "<123...topic>", // optional topic to connect to skipPairing: false, // optional to skip pairing ( later it can be resumed by invoking .pair()) }); ``` ## Events ```typescript // Subscribe for pairing URI provider.on("display_uri", (uri) => { console.log("display_uri", uri); }); // Subscribe to session ping provider.on("session_ping", ({ id, topic }) => { console.log("session_ping", id, topic); }); // Subscribe to session event provider.on("session_event", ({ event, chainId }) => { console.log("session_event", event, chainId); }); // Subscribe to session update provider.on("session_update", ({ topic, params }) => { console.log("session_update", topic, params); }); // Subscribe to session delete provider.on("session_delete", ({ id, topic }) => { console.log("session_delete", id, topic); }); ``` ## Provider Methods ```typescript interface RequestArguments { method: string; params?: any[] | undefined; } // Send JSON RPC requests /** * @param payload * @param chain - optionally specify which chain should handle this request * in the format `:` e.g. `eip155:1` */ const result = await provider.request(payload: RequestArguments, chain: string | undefined); ``` ## Chain switching `DefaultChain` is the current chain that the provider will target for the next requested transaction. ```typescript // set the default chain to 56 provider.setDefaultChain(`eip155:56`, rpcUrl?: string | undefined); ``` ## Session data Once a wallet is connected you can find the session data in the `provider.session` object. The session object includes the following properties, *among others*: * **namespaces**: `session.namespaces` is an object that contains the approved session data. Note that the `chains` object is an optional parameter and may be undefined. Therefore, we encourage apps to obtain the approved chains from the `session.accounts` object instead. ```ts interface Namespaces { chains?: string[]; accounts: string[]; methods: string[]; events: string[]; } ``` * **requiredNamespaces, optionalNamespaces & sessionProperties**: These objects contain the namespaces and properties proposed for the session. * **peer**: The `session.peer.metadata` object contains the metadata of the connected wallet. ```ts interface Metadata { name: string; description: string; url: string; icons: string[]; verifyUrl?: string; redirect?: { native?: string; universal?: string; }; } ``` Find the complete type definition of the `session` object [here](https://github.com/WalletConnect/walletconnect-monorepo/blob/022e4d492c9862ab9b17c1a7b12884bdcd992ae4/packages/types/src/sign-client/session.ts#L25). # Push Server Source: https://docs.reown.com/advanced/push-server The Push Server sends WalletConnect protocol activity using FCM or APNs to users. The Push Server can be used with our [WalletKit SDK](../walletkit/overview). Several options exist for setting up the Push Server: 1. Using [Reown Cloud](#setup-in-walletconnect-cloud) (recommended) 2. Self-host the [Push Server](https://github.com/WalletConnect/push-server) 3. Write your own implementation using the [spec](https://specs.walletconnect.com/2.0/specs/servers/push/spec) It is recommended that you use Reown Cloud for simplicity and ease of integration. Typically you only need to self-host if you have concerns about our hosted platform having access to your FCM or APNs server credentials, such as for regulatory reasons. If you want to self-host or implement against the spec, please reach out to [devrel@walletconnect.com](mailto:devrel@walletconnect.com) for assistance. ## Setup in Reown Cloud 1. Create a Project in the Cloud App. Go to [Reown Cloud](https://cloud.reown.com/) and sign up for an account. 2. To get your project's Push URL, from the Cloud App, go into the settings tab and click on `Create Push URL`. ![create-push-url](https://mintlify.s3.us-west-1.amazonaws.com/reown-5552f0bb/images/assets/create-push-url.png) 3. From the same settings tab, you will see the FCM and the APNS settings becomes available to setup. Add your \[FCM]\(#Firebase Cloud Messaging API (FCM v1)) and/or [APNs](#apple-push-notifications-apns) details. ![fmc-and-apns-details-form](https://mintlify.s3.us-west-1.amazonaws.com/reown-5552f0bb/images/assets/apns-fmc-details.png) ### Firebase Cloud Messaging API (FCM v1) If you already have FCM Legacy enabled and then enable FCM v1, push notifications will automatically be sent with the newer FCM v1 API automatically. No migration of devices/apps is necessary. * In your [Firebase](https://console.firebase.google.com) project settings, under *Firebase Cloud Messaging API (V1)*, click the Manage Service Accounts link ![Manage service accounts link](https://mintlify.s3.us-west-1.amazonaws.com/reown-5552f0bb/images/assets/push-fcmv1-manage-service-accounts.png) * You may use the default `firebase-adminsdk` service account, but we recommend making a new, minimally privileged, service account. Eg a ready-made role from Firebase `Firebase Cloud Messaging API Admin` would only give access to messaging and notifications: * Click the *Create service account* button ![Create service account button](https://mintlify.s3.us-west-1.amazonaws.com/reown-5552f0bb/images/assets/push-fcmv1-create-sa-button.png) * Provide an arbitrary name and ID. E.g. `Reown Cloud Push Server` and click *Create and Continue* ![Provide a name](https://mintlify.s3.us-west-1.amazonaws.com/reown-5552f0bb/images/assets/push-fcmv1-create-sa.png) * Select the `Firebase Cloud Messaging API Admin` role and click *Continue* ![Select the Firebase Cloud Messaging API Admin role](https://mintlify.s3.us-west-1.amazonaws.com/reown-5552f0bb/images/assets/push-fcmv1-create-sa-grants.png) * Click Done * Next create keys for the service account by clicking on the `⋮` button next to the service account and selecting *Manage keys* ![Manage keys](https://mintlify.s3.us-west-1.amazonaws.com/reown-5552f0bb/images/assets/push-fcmv1-sa-manage-keys.png) * Click *Add key* -> *Create new key* ![Create new key](https://mintlify.s3.us-west-1.amazonaws.com/reown-5552f0bb/images/assets/push-fcmv1-sa-new-key.png) * Select *JSON* and click *Create* * A `.json` file containing the service account credentials will be automatically downloaded to your computer * Upload the credentials JSON file to your Cloud project's FCM V1 settings and click *Save* You should now see a green checkbox indicating that FCM V1 has been enabled! Now any clients that register themselves on the Push Server will receive FCM push notifications for relay messages to that client. ### Cloud Messaging API (FCM Legacy) FCM Legacy is deprecated and [will be removed June 20, 2024](https://firebase.google.com/docs/cloud-messaging/migrate-v1). We strongly encourage you to setup FCM v1 (above) instead. ![FCM legacy deprecated](https://mintlify.s3.us-west-1.amazonaws.com/reown-5552f0bb/images/assets/push-fcm-legacy-deprecated.png) When FCM v1 is enabled in Reown Cloud, it will replace the use of the legacy FCM API. No migration of devices/apps is necessary. Google's FCM allows you to use send notifications to both Android and Apple devices. At this time, we only support apps using the FCM client API. * Enable Legacy Cloud Messaging API in the Firebase project settings ![legacy-fcm-cloud-messaging](https://mintlify.s3.us-west-1.amazonaws.com/reown-5552f0bb/images/assets/legacy-fcm-cloud-messaging-api.png) * [Set up Android](https://firebase.google.com/docs/cloud-messaging/android/client) * [Set up Apple](https://firebase.google.com/docs/cloud-messaging/ios/client) ### Apple Push Notifications (APNs) Apple recommends using a Token-Based Connection for APNS over a Certificate-Based connection. Please refer to their documentation for instructions on obtaining either. * [Token-Based Connection](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_token-based_connection_to_apns) * [Certificate-Based Connection](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_certificate-based_connection_to_apns) # Content Security Policy (CSP) Source: https://docs.reown.com/advanced/security/content-security-policy ## Overview A Content Security Policy (CSP) is a security feature that helps protect web applications from various attacks like Cross-Site Scripting (XSS), clickjacking, and data injection. By specifying allowed content sources, CSPs minimize the risk of executing malicious content on your site. ## CSP Guidance ### AppKit The following is a **partial CSP** that covers WalletConnect's libraries and services for [AppKit](https://docs.walletconnect.com/appkit/overview). Note that **you may need to define additional sources based on your application's requirements**. ``` default-src 'self'; script-src 'self'; style-src https://fonts.googleapis.com; img-src * 'self' data: blob: https://walletconnect.org https://walletconnect.com https://secure.walletconnect.com https://secure.walletconnect.org https://tokens-data.1inch.io https://tokens.1inch.io https://ipfs.io https://cdn.zerion.io; font-src 'self' https://fonts.gstatic.com; connect-src 'self' https://rpc.walletconnect.com https://rpc.walletconnect.org https://relay.walletconnect.com https://relay.walletconnect.org wss://relay.walletconnect.com wss://relay.walletconnect.org https://pulse.walletconnect.com https://pulse.walletconnect.org https://api.web3modal.com https://api.web3modal.org https://keys.walletconnect.com https://keys.walletconnect.org https://notify.walletconnect.com https://notify.walletconnect.org https://echo.walletconnect.com https://echo.walletconnect.org https://push.walletconnect.com https://push.walletconnect.org wss://www.walletlink.org; frame-src 'self' https://verify.walletconnect.com https://verify.walletconnect.org https://secure.walletconnect.com https://secure.walletconnect.org; ``` You may need to list the RPC endpoints used by blockchain networks you have enabled (e.g. via the [`@wagmi/chains` package](https://wagmi.sh/core/api/chains)) as part of your `connect-src` definition. For a full of list of RPC sources used by `wagmi/viem`, please refer to [Viem's chain definitions](https://github.com/wevm/viem/tree/main/src/chains/definitions). ## Testing and Deploying Your CSP ### Test Your CSP in a Staging Environment Run through your standard user flows in a staging environment with CSP enforcement. This may include connecting to browser extension wallets, transacting, logging out, etc. Directives may need updates after SDK upgrades. Always test your CSP again before deploying updates to production. ### Using Report-Only Mode Use the `Content-Security-Policy-Report-Only` header, which sends violation reports without enforcing policies. This helps assess the impact of CSP changes without affecting functionality. ### Deployment First deploy your CSP in `report-only` mode. After validation, migrate to `Content-Security-Policy` for enforcement. ### Monitoring Configure `report-uri` or `report-to` to receive violation reports and set up a monitoring dashboard for review. # Deprecated WalletConnect SDKs Source: https://docs.reown.com/advanced/walletconnect-deprecations WalletConnect Inc is now Reown. As part of this transition, we are deprecating a number of repositories/packages across our supported platforms, and the transition to their equivalents published under the Reown organization. This page outlines the deprecation schedule and provides important information for users of affected repositories/packages. ## Deprecation Schedule ### 1. Limited Support Phase (September 17, 2024 - February 17, 2025) * Only critical bug fixes and security updates will be provided for the deprecated packages/repositories. * No new features or non-critical bug fixes will be implemented. ### 2. End-of-Life Phase (February 18, 2025 onwards) * All updates and support for the deprecated packages/repositories packages will cease. * Users are strongly encouraged to complete migration to packages published under Reown before this date. ## Affected Packages and Repositories The following packages and repositories are affected by this deprecation notice: ### Web **Packages** * `@walletconnect/web3wallet` deprecated in favor of `@reown/walletkit` * For guidance on how to update your existing `@walletconnect/web3wallet` implementation, please see the [WalletKit migration guide](/walletkit/upgrade/from-web3wallet-web). * `@web3modal/*` packages deprecated in favor of `@reown/appkit-*` packages * For guidance on how to update your existing `@web3modal/*` implementation, please see the [AppKit migration guide](/appkit/upgrade/to-reown-appkit-web). ### React Native **Packages** * `@web3modal/*-react-native` packages deprecated in favor of `@reown/appkit-*-react-native` packages For guidance on how to update your implementation, please see [React Native AppKit migration guide](/appkit/upgrade/from-web3modal-react-native) ### Swift * **Packages** * `Web3Wallet` deprecated in favor of `ReownWalletKit` * `Web3Modal` deprecated in favor of `ReownAppKit` * `WalletConnectRouter` deprecated in favor of`ReownRouter` **Repositories** * [https://github.com/WalletConnect/WalletConnectSwiftV2](https://github.com/WalletConnect/WalletConnectSwiftV2) in favor of [https://github.com/reown-com/reown-swift](https://github.com/reown-com/reown-swift) For guidance on how to update your Swift implementation, please see: * [Swift Migration from Web3Modal to AppKit](/appkit/upgrade/from-web3modal-ios) * [Swift Migration from Web3Wallet to WalletKit](/walletkit/upgrade/from-web3wallet-ios) ### Kotlin **Packages** * `com.walletconnect:android-bom` in favor of `com.reown:android-bom` * `com.walletconnect:android-core` in favor of `com.reown:android-core` * `com.walletconnect:web3wallet` in favor of `com.reown:walletkit` * `com.walletconnect:web3modal` in favor of `com.reown:appkit` * `com.walletconnect:sign` in favor of `com.reown:sign` * `com.walletconnect:notify` in favor of `com.reown:notify` **Repositories** * [https://github.com/WalletConnect/WalletConnectKotlinV2](https://github.com/WalletConnect/WalletConnectKotlinV2) in favor of [https://github.com/reown-com/reown-kotlin](https://github.com/reown-com/reown-kotlin) For guidance on how to update your Kotlin packages, please see: * [Migration from Web3Modal to AppKit](/appkit/upgrade/from-web3modal-android) * [Migration from Web3Wallet to WalletKit](/walletkit/upgrade/from-web3wallet-android) ### Unity **Packages** * `com.walletconnect.web3modal` in favor of `com.reown.appkit.unity` * `com.walletconnect.nethereum` in favor of `com.reown.nethereum.unity` * `com.walletconnect.core` in favor of `com.reown.sign.unity` and `com.reown.appkit.unity` * `com.walletconnect.modal` deprecated, migrate to `com.reown.appkit.unity` **Repositories** * [https://github.com/walletconnect/web3modalunity](https://github.com/walletconnect/web3modalunity) in favor of [https://github.com/reown-com/reown-dotnet](https://github.com/reown-com/reown-dotnet) * [https://github.com/walletconnect/walletconnectunity](https://github.com/walletconnect/walletconnectunity) in favor of [https://github.com/reown-com/reown-dotnet](https://github.com/reown-com/reown-dotnet) For guidance on how to update your Unity packages, please see the [Web3Modal to AppKit migration guide](/appkit/upgrade/from-web3modal-unity) ### .NET **Packages** * `WalletConnect.Sign` in favor of `Reown.Sign` * `WalletConnect.Web3Wallet` in favor of `Reown.WalletKit` **Repositories** * [https://github.com/WalletConnect/WalletConnectSharp](https://github.com/WalletConnect/WalletConnectSharp) in favor of [https://github.com/reown-com/reown-dotnet](https://github.com/reown-com/reown-dotnet) For guidance on how to update your NuGet packages, please see the [Web3Wallet to WalletKit migration guide](/walletkit/upgrade/from-web3wallet-unity) ### Flutter **Packages** * [walletconnect\_flutter\_v2](https://pub.dev/packages/walletconnect_flutter_v2) in favor of [reown\_walletkit](https://pub.dev/packages/reown_walletkit) * [web3modal\_flutter](https://pub.dev/packages/walletconnect_flutter_v2) in favor of [reown\_appkit](https://pub.dev/packages/reown_appkit) **Repositories** * [https://github.com/WalletConnect/WalletConnectFlutterV2](https://github.com/WalletConnect/WalletConnectFlutterV2) in favor of [https://github.com/reown-com/reown\_flutter](https://github.com/reown-com/reown_flutter) * [https://github.com/WalletConnect/Web3ModalFlutter](https://github.com/WalletConnect/Web3ModalFlutter) in favor of [https://github.com/reown-com/reown\_flutter](https://github.com/reown-com/reown_flutter) For guidance on how to update your Flutter packages, please see: * [Migration from Web3Modal to AppKit](/appkit/upgrade/from-web3modal-flutter) * [Migration from Web3Wallet to WalletKit](/walletkit/upgrade/from-web3wallet-flutter) ## Action Required 1. Identify the platforms and packages you are currently using from the list above. 2. Review the corresponding migration guide for your platform(s) using the links provided. 3. Plan your migration to packages published under Reown as soon as possible. 4. Complete the migration before February 17th 2025, to ensure continued support and access to the latest features and security updates. ## Support and Resources * If you encounter any issues during migration, please open an issue in the respective [Reown Github repository](https://github.com/reown-com). # Analytics Source: https://docs.reown.com/appkit/android/cloud/analytics ## Accessing Reown Analytics To access Reown Analytics and explore these insightful features, follow these simple steps: 1. Log In to your Cloud Account [here](https://cloud.reown.com/sign-in). 2. Click on your Project. 3. Click the Analytics Tab. 4. Select the Analytics section of your choice. By following these steps, you can easily access and leverage Reown Analytics to track your project's progress and make informed decisions to take your project to the next level. ## Understanding Reown Analytics Reown Cloud now includes Analytics to help you better understand your project's performance. Let's break down some terms and explore the new analytics sections in a simple manner. ## Analytics Sections **Definitions** Refer to [Definitions](#definitions) for the meaning of terms used in Reown Analytics. ### Relay #### Overview - Wallet/Dapp Sessions Displays the total count of established connections between your project and Reown SDK. #### Overview - Clients Indicates the total number of connections established from clients (device or browser if connecting on the web). #### Overview - Messages Shows the total messages exchanged between the configured Reown SDK and the Relay Server. #### Wallet/Dapp Sessions Shows the daily trend of established sessions over a 30 day period. #### Clients Shows the daily trend of client connections over a 30 day period. #### All Messages Shows the daily trend of messages connections over a 30 day period. #### Projects Lists the top ranked wallets/Dapps connected to your project. #### Countries and Continents Provides insights into user connections by displaying the countries and continents with the most connections. Learn more about the Relay [here](./relay) ### RPC #### Overview RPC Requests Represents the total count of remote procedure calls (RPC) made to the blockchain API for the last 30 days. #### RPC Request Volumes Displays the daily trend of API requests made to the blockchain API. #### RPC Chain Shows the top chain requests made by Chain ID. #### RPC Method Highlights the top-ranked methods called by your users. #### Countries Illustrates user connections by displaying the countries with the most connections. Learn more about the Blockchain API [here](./blockchain-api) ### AppKit #### Avg. Daily Visitors Indicates the daily average of unique visitors to your app’s AppKit. #### Avg. Daily Sessions Indicates the daily average of sessions. #### Avg. Daily Connections Indicates the daily average of connections made through AppKit. #### Sessions Indicates the total count of sessions. #### Successful connections Total count of all connections made between a wallet and your app. #### Countries Ranks the top countries with the highest user connections. #### Wallets Breakdown Ranks the top wallets that your users are connecting from. #### All Events This table and chart shows the count of various events that are triggered as the users interact with AppKit. #### Platform Sessions Provides a breakdown of sessions that have been created by device platform. #### Visitors Shows the daily trend of unique visitors to your app’s AppKit. #### Sessions Shows the daily trend of sessions created when the user signs a message with their connected wallet. #### Successful connections Shows the daily trend of successful connections to your app. ### Web3Inbox #### Subscribers - All Time Total count of all subscribers to your project. #### Notifications - All Time Total count of all notifications sent from your project. #### Subscribers Daily trend chart illustrating the growth of subscribers. #### Notifications Daily trend chart of total notifications received by your subscribers. #### Messaged Accounts Daily trend chart of unique wallets that received the notification. #### Subscribers by notification type This table shows the total count of subscribers by notification type over a 30 day period. ### Definitions Definitions of terms used in Reown Analytics. | Term | Description | | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Relay:Session** | A session within the context of Relay analytics denotes meaningful user actions, like signing transactions for NFT sales or trades, within a wallet or dapp. It emphasizes core SDK functionality. | | **AppKit:Session** | A session within the context of AppKit analytics represents the connection established between your project and your user’s device (includes browsers). Sessions are created when the user interacts with AppKit on your app. If user events are tracked within a 30-minute range, they will be considered within the same session. | | **Message** | Messages are data exchanges between the Reown SDK and the Relay Server, facilitating communication between your project and connected clients. | | **Client** | A client is a device or browser connected to your project. | | **Blockchain API** | The interface that allows your project to interact with the blockchain. Remote Procedure Calls (RPC) are used to request information or execute operations on the blockchain through this API. | | **Chain ID** | Chain ID identifies a specific blockchain network. Different blockchain networks, such as Ethereum Mainnet or a testnet, have unique Chain IDs. | # Blockchain API Source: https://docs.reown.com/appkit/android/cloud/blockchain-api The Blockchain API is the RPC service that powers AppKit's blockchain functions such as account balances, ENS resolution, transaction history, and more. Blockchain API is not the same as the WalletConnect protocol. WalletConnect protocol supports wallets on all chains using the [CAIP-25](https://chainagnostic.org/CAIPs/caip-25) standard. We do not accept requests for new chains to be added to our Blockchain API. Please see your SDK's relevant documentation on how to add RPC URLs for chains you want to use that Blockchain API does not. ## Features * AppKit built-in integration * Multi-chain mainnet and testnets * HTTP RPC support * Cloud metrics and reporting * The Identity API with near-instant ENS resolution * Transaction history ## Supported Chains The Blockchain API supports popular chains such as Ethereum, Binance Smart Chain, Solana, and more. See the full list of [supported chains](https://github.com/WalletConnect/blockchain-api/blob/master/SUPPORTED_CHAINS.md). ## Using the Blockchain API No config or setup is needed for AppKit integrations. For other usage, see the [Usage](https://github.com/walletconnect/blockchain-api#usage) section. ## Limits The Blockchain API is free for 2.5 million requests per 30 days. If you wish to increase your limits, please contact [sales@reown.com](mailto:sales@reown.com). ## Links * [Supported chains](https://github.com/WalletConnect/blockchain-api/blob/master/SUPPORTED_CHAINS.md) * [The Blockchain API GitHub repo](https://github.com/WalletConnect/blockchain-api) # Relay Source: https://docs.reown.com/appkit/android/cloud/relay ## Project ID The Project ID is consumed through URL parameters. URL parameters used: * `projectId`: Your Project ID can be obtained from [cloud.reown.com](https://cloud.reown.com) Example URL: `https://relay.walletconnect.com/?projectId=c4f79cc821944d9680842e34466bfbd` This can be instantiated from the client with the `projectId` in the `SignClient` constructor. ```javascript import SignClient from '@walletconnect/sign-client' const signClient = await SignClient.init({ projectId: 'c4f79cc821944d9680842e34466bfb' }) ``` ## Allowlist To help prevent malicious use of your project ID you are strongly encouraged to set an allowlist of [origins](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin) or application/bundle ids for mobile applications where the project ID is used. Requests from other origins will be denied. * Allowlist supports a list of origins in the format `[scheme://] --> */} 4. Click on the copy button and head over to your domain Name Registrar/Provider to edit your DNS records. Alternatively, if you can't manage DNS records for your project (eg: ENS or vercel.app) you can host a static file under `/.well-known/walletconnect.txt` which contains the entire verification code that you copied. If you are using the static file method, you can jump over step 7. 5. Under `Type`, select `TXT`. In the “Answer” section, paste the text you copied from the cloud dashboard. This field may vary across DNS dashboards. If you’re trying to register a subdomain, add it under `Host`. Feel free to leave TTL at its default value. {/* */} 6. Depending on your DNS settings, this might take a while to reflect. You can check out DNS settings for your website with CLI tools like Dig or with websites like [MXToolbox](https://mxtoolbox.com/SuperTool.aspx?action=txt) 7. Once this is done and you have confirmed this change is reflected, head on back to your Cloud Dashboard and click on Verify. 8. You should see a toast pop up in the bottom right section of your screen and the domain verification section should have a green tick next to it. # Actions Source: https://docs.reown.com/appkit/android/core/actions ## Chains ### Get selected chain You can get selected chain by calling the `getSelectedChain()` on the `AppKit` object. ```kotlin AppKit.getSelectedChain() ``` ## AppKit.ModalDelegate ```kotlin val appKitModalDelegate = object : AppKit.ModalDelegate { override fun onSessionApproved(approvedSession: Modal.Model.ApprovedSession) { // Triggered when receives the session approval from wallet } override fun onSessionRejected(rejectedSession: Modal.Model.RejectedSession) { // Triggered when receives the session rejection from wallet } override fun onSessionUpdate(updatedSession: Modal.Model.UpdatedSession) { // Triggered when receives the session update from wallet } override fun onSessionExtend(session: Modal.Model.Session) { // Triggered when receives the session extend from wallet } override fun onSessionEvent(sessionEvent: Modal.Model.SessionEvent) { // Triggered when the peer emits events that match the list of events agreed upon session settlement } override fun onSessionDelete(deletedSession: Modal.Model.DeletedSession) { // Triggered when receives the session delete from wallet } override fun onSessionRequestResponse(response: Modal.Model.SessionRequestResponse) { // Triggered when receives the session request response from wallet } override fun onProposalExpired(proposal: Modal.Model.ExpiredProposal) { // Triggered when a proposal becomes expired } override fun onRequestExpired(request: Modal.Model.ExpiredRequest) { // Triggered when a request becomes expired } override fun onConnectionStateChange(state: Modal.Model.ConnectionState) { //Triggered whenever the connection state is changed } override fun onError(error: Modal.Model.Error) { // Triggered whenever there is an issue inside the SDK } } ``` You have set delegate on AppKit to start getting updates from Wallet. ```kotlin AppKit.setDelegate(appKitModalDelegate) ``` ## Actions ### Disconnect ```kotlin AppKit.disconnect( onSuccess = { /* callback that letting you know that you have successfully disconnected */ }, onError = { error -> /* callback for error while trying to disconnection with a peer */ } ) ``` ### Request ```kotlin val requestParams = Modal.Params.Request( method = /* Selected method */, params = /* Method params */, ) AppKit.request( request = requestParams, onSuccess = { /* callback that letting you know that you have successful request */ }, onError = { error -> /* callback for error */ } ) ``` ### Get Active Account Returns the current active account connected via AppKit ```kotlin AppKit.getAccount() ``` ### Get Connection type Return information about the type of our connection ```kotlin AppKit.getConnectorType() ``` # Components Source: https://docs.reown.com/appkit/android/core/components You can use predefined AppKitComponent and add it in your application. As a view, dialog or modal. ```kotlin import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.ModalBottomSheetState import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import androidx.compose.material.ModalBottomSheetLayout setContent { val modalSheetState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden, skipHalfExpanded = true) val coroutineScope = rememberCoroutineScope() val navController = rememberNavController() ModalBottomSheetLayout( sheetContent = { AppKitComponent( shouldOpenChooseNetwork = true | false, closeModal = { coroutineScope.launch { modalSheetState.hide() } ) } ) { // content } } ``` ## Buttons You can add ready made button components to your application ### Web3Button ```kotlin import com.reown.appkit.ui.components.button.Web3Button import com.reown.appkit.ui.components.button.ConnectButtonSize import com.reown.appkit.ui.components.button.AccountButtonType import com.reown.appkit.ui.components.button.rememberAppKitState YourAppScreen(navController: NavController) { val appKitState = rememberAppKitState(navController = navController) Web3Button( state = appKitState, accountButtonType = AccountButtonType.NORMAL || AccountButtonType.MIXED, connectButtonSize = ConnectButtonSize.NORMAL || ConnectButtonSize.SMALL ) } ``` ```xml ``` ### Network Button ```kotlin import com.reown.appkit.ui.components.button.NetworkButton import com.reown.appkit.ui.components.button.rememberAppKitState YourAppScreen(navController: NavController) { val appKitState = rememberAppKitState(navController = navController) NetworkButton(state = appKitState) } ``` ```xml ``` ### Connect Button ```kotlin import com.reown.appkit.ui.components.button.ConnectButton import com.reown.appkit.ui.components.button.ConnectButtonSize import com.reown.appkit.ui.components.button.rememberAppKitState YourAppScreen(navController: NavController) { val appKitState = rememberAppKitState(navController = navController) ConnectButton( state = appKitState, buttonSize = ConnectButtonSize.NORMAL || ConnectButtonSize.SMALL ) } ``` ```xml ``` ### Account Button ```kotlin import com.reown.appkit.ui.components.button.AccountButton import com.reown.appkit.ui.components.button.AccountButtonType import com.reown.appkit.ui.components.button.rememberAppKitState YourAppScreen(navController: NavController) { val appKitState = rememberAppKitState(navController = navController) AccountButton( state = appKitState, buttonSize = AccountButtonType.NORMAL || AccountButtonType.MIXED ) } ``` ```xml ``` ### AppKit State AppKitState is an object that ensures communication between your application and the state of the AppKit. #### Create appKitState: NavController is required to create appKitState ```kotlin val appKitState = rememberAppKitState(navController) ``` #### AppKitState methods ```kotlin appKitState.isOpen ``` returns `StateFlow` whose value is updated depending on whether the appkit component is open ```kotlin appKitState.isConnected ``` returns `StateFlow` whose value depends on the active session in AppKit # Kotlin Source: https://docs.reown.com/appkit/android/core/installation Kotlin implementation of AppKit for Android applications. Android Core \ Appkit ### Requirements * Android min SDK 23 * Java 11 ## Installation root/build.gradle.kts: ```gradle allprojects { repositories { mavenCentral() maven { url "https://jitpack.io" } } } ``` app/build.gradle.kts ```gradle implementation(platform("com.reown:android-bom:$BOM_VERSION")) implementation("com.reown:android-core") implementation("com.reown:appkit") ``` ## Example Check the Kotlin example ## Test Apps Want to see AppKit in action? Download our sample AppKit apps below and explore what it can do. Enjoy! 😊 * [Android Build (Firebase)](https://appdistribution.firebase.google.com/pub/i/4cf60e7b49f9265e) # Sign In With Ethereum Source: https://docs.reown.com/appkit/android/core/one-click-auth AppKit provides a simple solution for integrating with "Sign In With Ethereum" (SIWE), a form of authentication that enables users to control their digital identity with their Ethereum account. SIWE is a standard also known as [EIP-4361](https://docs.login.xyz/general-information/siwe-overview/eip-4361). ## One-Click Auth One-Click Auth represents a key advancement within WalletConnect v2, streamlining the user authentication process in AppKit by enabling them to seamlessly connect with a wallet and sign a SIWE message with just one click. Connecting a wallet, proving control of an address with an off-chain signature, authorizing specific actions. These are the kinds of authorizations that can be encoded as "ReCaps". ReCaps are permissions for a specific website or dapp that can be compactly encoded as a long string in the message you sign and translated by any wallet into a straight-forward one-sentence summary. WalletConnect uses permissions expressed as ReCaps to enable a One-Click Authentication. ## Configure your AppKit Client To integrate SIWE with AppKit, you need to configure your AppKit client using `Modal.Model.AuthPayloadParams`, which are required to create a SIWE message for the user to sign: ```kotlin AppKit.setAuthRequestParams(authPayloadParams) ``` #### Example of AuthRequestParams ```kotlin val authParams = Modal.Model.AuthPayloadParams( chains = ["eip155:1", "eip155:137"], domain = "yourDappDomain.com", uri = "https://yourDappDomain.com/login", nonce = //uniqueNonce, statement = "I accept the Terms of Service: https://yourDappDomain.com/", methods = ["personal_sign", "eth_sendTransaction"], resources = null //// Here your dapp may request authorization with ReCaps ) ``` Configuring your AppKit client with Modal.Model.AuthPayloadParams will prioritize authentication requests over regular session proposals. If the wallet supports One-Click Auth, the session will be created and the user will automatically authenticate without needing to send another SIWE request over personal\_sign. If the wallet does not support One-Click Auth, it will fall back to the session proposal. In this case, to authenticate the user, AppKit will send another session request to prove address ownership. To check whether the user has signed a SIWE message, check `onSessionAuthenticateResponse` callback from `AppKit.ModalDelegate`: ```kotlin fun onSessionAuthenticateResponse(response: Modal.Model.SessionAuthenticateResponse) { // Triggered when Dapp receives the session authenticate response from wallet if (response is Modal.Model.SessionAuthenticateResponse.Result) { if (response.session != null) { // Authentication successful, session established } else { // Authentication successful, but no session created (SIWE-only flow) } } else { // Authentication request was rejected or failed } } ``` ### Fallback to SIWE Over Session Request If the wallet connecting to your dapp does not support One-Click Auth, the SDK will fallback to the `wc_sessionPropose` method and create a session with the wallet. AppKit will then inform the user that they need to sign a message to prove address ownership. AppKit will send a SIWE request to the wallet, and once the wallet responds with a signed message, use `onSIWEAuthenticationResponse` callback to check the result: ```kotlin override fun onSIWEAuthenticationResponse(response: Modal.Model.SIWEAuthenticateResponse) { if (response is Modal.Model.SIWEAuthenticateResponse.Result) { // message and signature } else { //error } } ``` ### Link Mode The latest release of AppKit supports link mode, a low latency mechanism for transporting One-Click Auth requests and session requests over universal links, reducing the need for a WebSocket connection with the Relay. This significantly enhances the user experience when connecting native dApps to native wallets by reducing the latency associated with networking connections, especially when the user has an unstable internet connection.