Wallet Connect Logo

Wallet Connect

Wallet Connect SDK made in ❤️ with dart.


Getting started

To configure your app use latest version of wallet_connect_dart_v2, see pub.dev

Note: In order to use wallet_connect_dart_v2 alongside the legacy v1 sdk, see wallet_connect.


Dapp Usage

For detailed implementation of dapp usage, see example-dapp.


Wallet Usage

For detailed implementation of wallet usage, see example-wallet.

  1. Initialization
  2. Pairing via QR
  3. Pairing Via URI
  4. Responding to Session Proposal
  5. Responding to Dapp Requests
  6. Responding to Dapp Events
  7. Responding to Ping
  8. Responding to Session Delete
  9. Sending Requests to Dapp

Initialization

import 'package:wallet_connect_dart_v2/wallet_connect_dart_v2.dart';
final signClient = await SignClient.init(
      projectId: "PROJECY_ID",
      relayUrl: "RELAY_URL" // or leaving it empty, uses default "wss://relay.walletconnect.com",
      metadata: const AppMetadata(
        name: "Demo app",
        description: "Demo Client as Wallet/Peer",
        url: "www.walletconnect.com",
        icons: [],
      ),
      database: 'DB_NAME', // optional, if empty all session data will be stored in memory
    );

Pairing via QR code

We have used ScanView for this you can use any other package as well.

Scan the QR code to get pairing URI.

ScanView(
  controller: ScanController(),
  onCapture: (data) {
       if (Uri.tryParse(value) != null) {
         signClient.pair(value);
     }
  },
);

Pairing via URI

Directly use pair functionality from SignClient instance

await signClient.pair(value);

Responding to Session Proposal

The SignClientEvent.SESSION_PROPOSAL event is emitted when a dapp initiates a new session with a user's wallet. The event will include a proposal object with information about the dapp and requested permissions. The wallet should display a prompt for the user to approve or reject the session. If approved, call approveSession and pass in the proposal.id and requested namespaces.

You can listen for this event while initializing client:

signClient.on(SignClientEvent.SESSION_PROPOSAL.value, (data) {
      final eventData = data as SignClientEventParams<RequestSessionPropose>;

      // Show session proposal data to the user i.e. in a popup with options to approve / reject it

      const approve = true;
      // On Approve Session Proposal
      if(approve) {
        //
        final SessionNamespaces namespaces = {
          // Provide the namespaces and chains (e.g. `eip155` for EVM-based chains) being requested by dapp.
          "eip155": SessionNamespace(
              // `accounts` addresses need to be passed from the wallet side int the specified format as per the number of chains being requested by dapp
              accounts: ["eip155:1:0x0000000000..., eip155:10:0x0000000000..."],
              // `methods and `events` Can be accessed at `eventData.params!.requiredNamespaces`
              methods: [
                  "eth_sendTransaction",
                  "eth_signTransaction",
                  "eth_sign",
                  "personal_sign",
                  "eth_signTypedData",
              ],
              events: ["chainChanged", "accountsChanged"],
          )
        };

        final params = SessionApproveParams(
              id: eventData.id!,
              namespaces: namespaces,
            );
        signClient.approve(params);
      }
      // Or Reject Session Proposal
      else {
        final params = SessionRejectParams(
              id: eventData.id!,
              reason: formatErrorMessage(
                  error: getSdkError(SdkErrorKey.USER_DISCONNECTED),
              ),
            );
        signClient.reject(params);
      }
    });

Responding to Dapp Requests

The SignClientEvent.SESSION_REQUEST event is triggered when a dapp sends a request to the wallet for a specific action, such as signing a transaction. This event is emitted by the dapp and received by the wallet. To respond to the request, wallets should call the specific required sign function and pass in details from the request. You can then approve or reject the request based on the response.

signClient.on(SignClientEvent.SESSION_REQUEST.value, (data) async {
      final eventData = data as SignClientEventParams<RequestSessionRequest>;
      final String method = eventData.params!.request.method;

      // Example handling some methods from EVM-based chains
      if (method == "personal_sign") {
        final requestParams =
              (eventData.params!.request.params as List).cast<String>();
        final dataToSign = requestParams[0];
        final address = requestParams[1];

        // Handle request params to generate necessary result and send back the response to dapp.
        final signedDataHex = personalSign(dataToSign, address);
        // Approve the request
        signClient!.respond(
          SessionRespondParams(
            topic: eventData.topic!,
            response: JsonRpcResult<String>(
              id: eventData.id!,
              result: signedDataHex,
            ),
          ),
        );
        // Or Reject the request with error
        _signClient!.respond(SessionRespondParams(
          topic: eventData.topic!,
          response: JsonRpcError(id: eventData.id!),
        ));
      } else if (method == "eth_sign") {
        // Handle `eth_sign`
      } else if (method == "eth_signTypedData") {
        // Handle `eth_signTypedData`
      } else if (method == "eth_sendTransaction") {
        // Handle `eth_sendTransaction`
      } else if (method == "eth_signTransaction") {
        // Handle `eth_signTransaction`
      }
    });

Responding to Dapp Events

signClient!.on(SignClientEvent.SESSION_EVENT.value, (data) {
      final eventData = data as SignClientEventParams<RequestSessionEvent>;
      // Handle events request
    });

Responding to Ping

signClient!.on(SignClientEvent.SESSION_PING.value, (data) {
      final eventData = data as SignClientEventParams<void>;
      // Handle Ping request
    });

Responding to Session Delete

 signClient!.on(SignClientEvent.SESSION_DELETE.value, (data) {
      final eventData = data as SignClientEventParams<void>;
      // Handle Session Delete request
    });

Sending Requests to Dapp

Session Delete

If either the dapp or the wallet decides to disconnect the session, the SignClientEvent.SESSION_DELETE event will be emitted. The wallet should listen for this event in order to update the UI.

To disconnect a session from the wallet, call the disconnect function and pass in the topic and reason. You can optionally send the reason for disconnect to dapp.

await signClient.disconnect(topic: "TOPIC");

Extend a Session

To extend the session, call the extend method and pass in the new topic. The SignClientEvent.SESSION_UPDATE event will be emitted from the wallet.

await signClient.extend("TOPIC");

Updating a Session​

The SignClientEvent.SESSION_UPDATE event is emitted from the wallet when the session is updated by calling update. To update a session, pass in the new SessionUpdateParams

await signClient.update(params);

Emit a Session Event

To emit sesssion events, call the emit and pass in the params. It takes SessionEmitParams as a parameter.

final SessionEmitParams params = SessionEmitParams(
    topic: "TOPIC",
    event: SessionEmitEvent(
      name: "NAME",
      data: ["DATA_1"],
    ),
    chainId: "CHAIN_ID");
await signClient.emit(params);

Libraries

wc_utils/relay_auth/api
core/models/app_metadata
wc_utils/relay_auth/base64
core/crypto/constants
core/keychain/constants
sign/sign-client/pending_request/constants
core/constants
sign/sign-client/session/constants
wc_utils/misc/heartbeat/constants
wc_utils/jsonrpc/utils/constants
core/subscriber/constants
core/history/constants
sign/sign-client/proposal/constants
core/store/constants
core/pairing/constants
sign/sign-client/client/constants
sign/engine/constants
core/relayer/constants
core/publisher/constants
core/expirer/constants
core/messages/constants
wc_utils/relay_auth/constants
core/core
utils/crypto
core/crypto/crypto
sign/engine/engine
wc_utils/jsonrpc/utils/error
utils/error
wc_utils/misc/events/events
core/expirer/expirer
wc_utils/jsonrpc/utils/format
wc_utils/misc/heartbeat/heartbeat
core/history/history
core/i_core
core/crypto/i_crypto
sign/engine/i_engine
core/expirer/i_expirer
wc_utils/misc/heartbeat/i_heart_beat
wc_utils/jsonrpc/provider/i_json_rpc_connection
wc_utils/jsonrpc/provider/i_json_rpc_provider
core/keychain/i_key_chain
wc_utils/misc/keyvaluestorage/i_key_value_storage
core/messages/i_message_tracker
core/pairing/i_pairing
sign/sign-client/pending_request/i_pending_request
sign/sign-client/proposal/i_proposal
core/publisher/i_publisher
core/relayer/i_relayer
sign/sign-client/session/i_session
sign/sign-client/client/i_sign_client
core/store/i_store
core/subscriber/i_subscriber
core/topicmap/i_topicmap
wc_utils/jsonrpc/provider/json_rpc_provider
wc_utils/relay/jsonrpc
core/keychain/key_chain
wc_utils/misc/keyvaluestorage/key_value_storage
utils/list
wc_utils/misc/logger/logger
core/messages/message_tracker
utils/misc
core/crypto/models
sign/sign-client/jsonrpc/models
sign/engine/models
wc_utils/relay/models
sign/sign-client/proposal/models
sign/sign-client/client/models
core/relayer/models
core/subscriber/models
core/publisher/models
wc_utils/jsonrpc/models/models
core/expirer/models
core/pairing/models
core/history/models
sign/sign-client/pending_request/models
sign/sign-client/session/models
wc_utils/relay_auth/models
utils/namespaces
core/pairing/pairing
sign/sign-client/pending_request/pending_request
sign/sign-client/proposal/proposal
core/publisher/publisher
utils/relay
wc_utils/relay_auth/relay_auth
core/relayer/relayer
sign/sign-client/session/session
sign/sign-client/client/sign_client
core/store/store
core/subscriber/subscriber
utils/timeout_completer
core/topicmap/topicmap
utils/uri
wc_utils/jsonrpc/utils/url
wc_utils/relay_auth/utils
utils/validator
wc_utils/jsonrpc/utils/validator
wallet_connect_dart_v2
wc_utils/jsonrpc/ws-connection/ws