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.
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 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.
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.
Pairing and session permissions
URI
The pairing proposal between a wallet and a dapp is made using an URI. 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:
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., e.g.: signClient.core.pairing.pair()
.
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). 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.
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.
Populate Authentication Payload
Approving Authentication Requests
Note
- 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.
- 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.
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 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.
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.
Pairing and session permissions
URI
The pairing proposal between a wallet and a dapp is made using an URI. 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:
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., e.g.: signClient.core.pairing.pair()
.
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). 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.
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.
Populate Authentication Payload
Approving Authentication Requests
Note
- 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.
- 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.
Configure Networking and Pair Clients
Confirm you have configured the Network and Pair Client first
Configure Sign Client
In order to initialize a client, call a configure
method on the Sign instance
Subscribe for Sign Publishers
The following publishers are available to subscribe:
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/, which is v2 protocol compliant.
Once you derive a URI from the QR code call pair
method:
if everything goes well, you should handle following event:
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.
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.
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 specification and be prefixed with a chain identifier. chain_id + : + account_address. You can find more on blockchain identifiers in CAIP2. Our Account
type meets the criteria.
Accounts sent in session approval must at least match all requested blockchains.
Example proposal namespaces request:
Example session namespaces response:
💡 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.
Example usage
Approve Session
Reject Session
When session is successfully approved sessionSettlePublisher
will publish a Session
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:
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
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.
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:
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.
Update Session
If you want to update user session’s chains, accounts, methods or events you can use session update method.
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:
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.
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.
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:
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.
Note
- 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.
- 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.
Where to go from here
- Try our example wallet implementation here.
- Build API documentation in XCode: go to Product -> Build Documentation
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
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.
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
semantics.
To send an approval, pass a Proposer’s Public Key along with the map of namespaces to the SignClient.approveSession
function.
Session Rejection
To send a rejection for the Session Proposal, pass a proposerPublicKey, rejection reason and rejection code to
the SignClient.rejectSession
function.
Session Disconnect
To disconnect from a settled session, pass a disconnection reason with code and the Session topic to the SignClient.disconnect
function.
Respond 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
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
semantics and syntax.
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
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
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.
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:
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.
Note
- 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.
- 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.
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.
Once you have the options defined, you can initialize the SDK.
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.
The wallet can then approve or reject the proposal using either of the following:
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.
Update Session
Update a session, adding/removing additional namespaces in the given topic.
Extend Session
Extend a session’s expiry time so the session remains open
Ping
Send a ping to the session
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<T>
to workaround this. For example, for eth_sendTransaction
, use List<Transaction>
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
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:
We can handle the eth_getTransactionReceipt
session request by doing the following:
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
The callback returns a Task
, so the callback can be made async. To return a response, you must set the Response
field in RequestEventArgs<T, TR>
with the desired response.
Disconnecting
To disconnect a session, use the Disconnect
function. You may optional provide a reason for the disconnect
Was this page helpful?