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

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