How to get started with WalletKit

Here’s a step-by-step guide to building a seamless React wallet integration with WalletKit and Vite.

As blockchain technology continues to evolve, interacting with decentralized applications (dApps) has become a cornerstone of the digital experience. Reown has emerged a game-changer, significantly enhancing the way we think about wallets and their interaction with blockchain applications. This cutting-edge protocol provides a seamless and secure way to connect wallets, ensuring user privacy and data protection at every step.

In this blog, we'll explore how to integrate Reown WalletKit into a wallet application using React and Vite.

Set up your React project with Vite

To start, we need to set up a React project using Vite. Vite is a fast and modern build tool that streamlines the development process.

1. Create a React project using Vite

Open your terminal and run the following command to create a new Vite project: Follow the prompts to configure your project, selecting "React" as the framework.

npm create vite@latest

2. Install the required dependencies

Once your project is set up, navigate to the project directory and install the necessary dependencies for Reown:

npm install @reown/web3wallet @reown/core @reown/utils

Set up WalletKit in 2 simple steps

With the project setup complete, the next step is to initialize WalletKit and set up the necessary components to enable wallet functionality.

1. Obtain a project ID

Visit cloud.reown.com to obtain a project ID. This ID is essential for interacting with the Reown API.

2. Initialize WalletKit

Create a new component or update your App.tsx file with the following code to initialize WalletKit:

import './App.css';
import { useEffect, useState } from 'react';
import { Core } from '@reown/core';
import { Web3Wallet } from '@reown/web3wallet';
import { SessionType, WalletKitType } from './walletKit/types';
import { subscribeOnInit } from './walletKit/helpers';
import { getSdkError } from '@reown/utils';

function App() {
  const [walletKit, setWalletKit] = useState<WalletKitType>();
  const [uri, setUri] = useState<string>('');
  const [session, setSession] = useState<SessionType>();

  useEffect(() => {
    async function initWalletKit() {
      const core = new Core({
        projectId: 'YOUR_PROJECT_ID',
      });

      const web3wallet = await Web3Wallet.init({
        core, // <- pass the shared `core` instance
        metadata: {
          name: 'Demo app',
          description: 'Demo Client as Wallet/Peer',
          url: 'www.reown.com',
          icons: [],
        },
      });

      setWalletKit(web3wallet);
    }
    initWalletKit();
  }, []);

  // Additional code will be added here...
}

export default App;


Replace 'YOUR_PROJECT_ID' with the actual project ID you obtained earlier.

Handling session proposals

Now that WalletKit is initialized, we need to handle session proposals. Session proposals are requests from dApps to connect to your wallet.

1. Create a helper for session proposals

Add a helper function to manage session proposals. This function will approve or reject session proposals based on your app's configuration.

import { Web3WalletTypes } from '@reown/web3wallet';
import { SessionType, WalletKitType } from './types';
import { buildApprovedNamespaces, getSdkError } from '@reown/utils';

export function subscribeOnInit(web3wallet: WalletKitType) {
  let session: SessionType;

  async function onSessionProposal({ id, params }: Web3WalletTypes.SessionProposal) {
    try {
      // ------- namespaces builder util ------------ //
      const approvedNamespaces = buildApprovedNamespaces({
        proposal: params,
        supportedNamespaces: {
          eip155: {
            chains: ['eip155:1', 'eip155:137'],
            methods: ['eth_sendTransaction', 'personal_sign'],
            events: ['accountsChanged', 'chainChanged'],
            accounts: [
              'eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb',
              'eip155:137:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb',
            ],
          },
        },
      });

      session = await web3wallet.approveSession({
        id,
        namespaces: approvedNamespaces,
      });

      console.log(session);
    } catch (error) {
      console.error(error);

      await web3wallet.rejectSession({
        id: id,
        reason: getSdkError('USER_REJECTED'),
      });
    }
  }

  web3wallet.on('session_proposal', onSessionProposal);

  return {
    session,
    unsubscribe: () => web3wallet.off('session_proposal', onSessionProposal),
  };
}

2. Import and use the helper function

In your App.tsx file, use the helper function inside a useEffect hook to ensure it runs once during the app lifecycle.

useEffect(() => {
  if (!walletKit) return;

  const result = subscribeOnInit(walletKit);
  setSession(result.session);

  return result.unsubscribe;
}, [walletKit]);

Connect and disconnect functions

Now that session proposals are handled, we need to implement functions to connect and disconnect the wallet.

1. Create connect and disconnect functions

Add the following functions to your App.tsx file to manage wallet connections:

async function connect() {
  if (!walletKit) throw Error('WalletKit instance is undefined');
  if (!uri) throw Error('Reown URI is undefined');

  await walletKit.pair({ uri });
}

async function disconnect() {
  if (!walletKit) throw Error('WalletKit instance is undefined');
  if (!session) throw Error('Session is undefined');

  await walletKit.disconnectSession({
    topic: session.topic,
    reason: getSdkError('USER_DISCONNECTED'),
  });
}

Creating the user interface

With the core functionality in place, let's create a simple user interface to connect and disconnect from dApps.

1. Add states and UI elements

Modify the App.tsx file to include input fields and buttons for connecting and disconnecting:

if (!walletKit) {
  return 'Loading...';
}

if (session) {
  return (
    <div className='container'>
      React Wallet
      <div>wallet account: {session.namespaces['eip155'].accounts[0]}</div>
      <div>Connected to: {session.peer.metadata.name}</div>
      <button onClick={disconnect} disabled={!uri}>
        Disconnect
      </button>
    </div>
  );
}

return (
  <div className='container'>
    React Wallet
    <input
      type='text'
      placeholder='Reown URI'
      value={uri}
      onChange={(e) => setUri(e.target.value)}
    />
    <button onClick={connect} disabled={!uri}>
      Accept Request
    </button>
  </div>
);

Listening to transaction requests

Finally, we need to listen for transaction requests from connected dApps.

1. Subscribe to transaction requests

Inside our helper function we can add an event listener for session_request events to handle transaction and signature requests:

web3wallet.on('session_request', async (event) => {
  const { topic, params, id } = event;
  const { request } = params;
  const requestParamsMessage = request.params[0];

  // convert `requestParamsMessage` by using a method like hexToUtf8
  const message = hexToUtf8(requestParamsMessage);

  // sign the message
  const signedMessage = await wallet.signMessage(message);

  const response = { id, result: signedMessage, jsonrpc: '2.0' };

  await web3wallet.respondSessionRequest({ topic, response });
});

Simplify your build, amplify your impact

Congratulations! You have successfully built a wallet using Reown WalletKit with React and Vite. This wallet allows users to connect to dApps supporting Reown and securely manage their blockchain interactions.

This code serves as a solid foundation for a more robust and feature-rich wallet, and you can easily extend it with global state management, transaction history, token management, and beyond.

By leveraging WalletKit's powerful features, you can provide users with a seamless and secure way to engage with blockchain apps.

Related articles