Implementation
- Web
- iOS
- Android
- Flutter
- .NET
- Unity
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 Reown AppKit for the UI.2. Add listeners for desired 3. Create a new AppKit instance.4. Connect the application and specify session permissions.
@walletconnect/modal is now deprecated. Please use @reown/appkit instead. For migration guidance, see the WalletConnect Modal to Reown AppKit Core migration guide.For an example implementation, please refer to our
react-dapp-v2
example.Install Packages
Copy
npm install @walletconnect/sign-client
Copy
npm install @reown/appkit
Create a Session
1. Initiate your WalletConnect client with the relay server, using your Project ID.Copy
import SignClient from "@walletconnect/sign-client";
const signClient = await SignClient.init({
projectId: "<YOUR_PROJECT_ID>",
// optional parameters
relayUrl: "<YOUR RELAY URL>",
metadata: {
name: "Example Dapp",
description: "Example Dapp",
url: "#",
icons: ["https://walletconnect.com/walletconnect-logo.png"],
},
});
SignClient events.To listen to pairing-related events, please follow the guidance for Pairing
API event
listeners.
Copy
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.
});
Copy
import { createAppKit } from "@reown/appkit/core";
import { mainnet } from "@reown/appkit/networks";
const modal = createAppKit({
projectId: "<YOUR_PROJECT_ID>",
networks: [mainnet],
manualWCControl: true
});
Copy
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) {
modal.open({ 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.
modal.close();
}
} 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:Copy
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:Copy
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.
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:Copy
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 knownrequiredNamespace and calling find.Copy
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.Configure Sign Client
In order to initialize a client, call aconfigure method on the Sign instanceCopy
Sign.configure(crypto: CryptoProvider)
Subscribe for Sign publishers
When yourSign 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 publisherCopy
Sign.instance.sessionsPublisher
.receive(on: DispatchQueue.main)
.sink { [unowned self] (sessions: [Session]) in
// reload UI
}.store(in: &publishers)
Copy
public var sessionsPublisher: AnyPublisher<[Session], Never>
public var sessionProposalPublisher: AnyPublisher<Session.Proposal, Never>
public var sessionRequestPublisher: AnyPublisher<Request, Never>
public var socketConnectionStatusPublisher: AnyPublisher<SocketConnectionStatus, Never>
public var sessionSettlePublisher: AnyPublisher<Session, Never>
public var sessionDeletePublisher: AnyPublisher<(String, Reason), Never>
public var sessionResponsePublisher: AnyPublisher<Response, Never>
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
- Prepare namespaces that constraints minimal requirements for your dApp:
Copy
let methods: Set<String> = ["eth_sendTransaction", "personal_sign", "eth_signTypedData"]
let blockchains: Set<Blockchain> = [Blockchain("eip155:1")!, Blockchain("eip155:137")!]
let namespaces: [String: ProposalNamespace] = ["eip155": ProposalNamespace(chains: blockchains, methods: methods, events: []]
- 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:
Copy
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:Copy
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:Copy
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)
Copy
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 establishedsessionSettlePublisher will publish an event. Your dApp can start requesting wallet now.Copy
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)
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:Copy
try await Sign.instance.extend(topic: session.topic)
Where to go from here
- Try our Example dApp that is part of WalletConnectSwiftV2 repository.
- Build API documentation in XCode: go to Product -> Build Documentation
Initialization
Copy
val projectId = "" // Get Project ID at https://dashboard.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
}
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
Copy
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)
SignClient.DappDelegate passed to it for it to be able to expose asynchronously updates sent from the Wallet.Connect
Copy
val namespace: String = /*Namespace identifier, see for reference: https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md#syntax*/
val chains: List<String> = /*List of chains that wallet will be requested for*/
val methods: List<String> = /*List of methods that wallet will be requested for*/
val events: List<String> = /*List of events that wallet will be requested for*/
val requiredNamespaces: Map<String, Sign.Model.Namespaces.Proposal> = mapOf(namespace, Sign.Model.Namespaces.Proposal(accounts, methods, events)) /*Required namespaces to setup a session*/
val optionalNamespaces: Map<String, Sign.Model.Namespaces.Proposal> = 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*/
}
)
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:Copy
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
}
)
Copy
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
Copy
SignClient.getListOfSettledSessions()
SignClient.getListOfSettledSessions() which will return a list of type Session.Get list of pending session requests for a topic
Copy
SignClient.getPendingRequests(topic: String)
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 ofSignClient, you need to pass in the core and metadata parameters.Copy
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, useconnect with the required namespaces.Copy
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;
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.Copy
final SessionData session = await response.session.future;
Request Signatures
Once the session had been created, you can request signatures.Copy
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, usingonSessionEvent and registerEventHandler.Copy
signClient.onSessionEvent.subscribe((SessionEvent? session) {
// Do something with the event
});
signClient.registerEventHandler(
namespace: 'kadena',
event: 'kadena_transaction_updated',
);
To Test
Run tests usingflutter test.
Expected flutter version is: >3.3.10Useful Commands
flutter pub run build_runner build --delete-conflicting-outputs- Regenerates JSON Generatorsflutter doctor -v- get paths of everything installed.flutter pub getflutter upgradeflutter cleanflutter pub cache cleanflutter pub depsflutter pub run dependency_validator- show unused dependencies and moredart format lib/* -l 120flutter analyze
Setup
First you must setupSignClientOptions 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.Copy
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()
};
ConnectOptions which define what blockchain, RPC methods and events your dapp will use.C# ConstructorCopy
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",
}
}
}
}
};
Copy
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")
);
Copy
var dappClient = await WalletConnectSignClient.Init(dappOptions);
var connectData = await dappClient.Connect(dappConnectOptions);
Uri for the connection request from connectData.Copy
ExampleShowQRCode(connectData.Uri);
Approval Task object.Copy
Task<SessionStruct> sessionConnectTask = connectData.Approval;
SessionStruct sessionData = await sessionConnectTask;
// or
// SessionStruct sessionData = await connectData.Approval;
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 functionCopy
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 thetopic 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.Copy
var sessionTopic = sessionData.Topic;
Update Session
Update a session, adding/removing additional namespaces in the given topic.Copy
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 openCopy
var request = await dappClient.Extend(sessionTopic);
await request.Acknowledged();
Ping
Send a ping to the sessionCopy
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 requestparams 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<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 Request type
Create a class for the request and populate it with the JSON properties the request object has. For this example, we will useeth_sendTransactionThe params field for eth_sendTransaction has the object typeCopy
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";
}
Copy
params: [
{
from: "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
to: "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
gas: "0x76c0", // 30400
gasPrice: "0x9184e72a000", // 10000000000000
value: "0x9184e72a", // 2441406250
data: "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675",
},
]
dappClient.RequestCopy
[RpcMethod("eth_sendTransaction"), RpcRequestOptions(Clock.ONE_MINUTE, 99997)]
public class EthSendTransaction : List<Transaction>
{
public EthSendTransaction(params Transaction[] transactions) : base(transactions)
{
}
}
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 requiredWe use List<Transaction> 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 foreth_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.Copy
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<EthSendTransaction, string>(sessionTopic, request, wallet.ChainId);
Disconnecting
To disconnect a session, use theDisconnect function. You may optional provide a reason for the disconnectCopy
await dappClient.Disconnect(sessionTopic);
// or
await dappClient.Disconnect(sessionTopic, Error.FromErrorType(ErrorType.USER_DISCONNECTED));
Subscribe to session events
Copy
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.All features of WalletConnectSharp are accessible in WalletConnectUnity.
For complex scenarios, the
Features of WalletConnectUnity
- 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.
- Session Restoration: WalletConnectUnity includes methods to easily access and restore the active session from storage.
- Deep Linking Support: WalletConnectUnity automatically handles deep linking for mobile and desktop wallets.
- QR Code Generation: WalletConnectUnity provides a utility for generating QR codes.
Usage
To use WalletConnectUnity in your project:- Fill in the Project ID and Metadata fields in the
Assets/WalletConnectUnity/Resources/WalletConnectProjectConfigasset.- If you don’t have a Project ID, you can create one at Reown Dashboard.
- The
Redirectfields are optional. They are used to redirect the user back to your app after they approve or reject the session.
- Initialize
WalletConnectand connect the wallet:
Copy
// 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;
}
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.