Embedded Wallet SDK React

With the Embedded Wallet SDK, you can supercharge your dApp’s UX. It is super easy to integrate and completely customisable to meet your dApp’s styles. It also helps solve the current Snaps limitations and integrating this will allow users to view their balances, manage their assets, and more.

Installation

npm install @leapwallet/embedded-wallet-sdk-react

Usage

Get Started

import React from "react";
import { useChain } from "@cosmos-kit/react";
import { AccountModal } from "@leapwallet/embedded-wallet-sdk-react";
import "@leapwallet/embedded-wallet-sdk-react/styles.css";

const chainId = "osmosis-1";
const chain = "osmosis";
const restUrl = "https://rest.cosmos.directory/osmosis";

const YourApp = () => {
  const { address } = useChain(chain);
  const [isModalOpen, setIsModalOpen] = React.useState(false);

  return (
    <div>
      {/* other components */}
      <button onClick={() => setIsModalOpen(true)}>Open Modal</button>
      <AccountModal
        theme="dark"
        chainId={chainId}
        restUrl={restUrl}
        address={address}
        isOpen={isModalOpen}
        onClose={closeModal}
      />
      {/* other components */}
    </div>
  );
};

Props

NameTypeDescription

theme

"light" | "dark" | ThemeDefinition

Theme of the modal

chainId

string

Chain ID of the chain

restUrl

string

REST URL of the chain

address

string

Address of the user

isOpen

boolean

Whether the modal is open

onClose

() => void

Callback function when the modal is closed

config

Config

Config of the modal

Here is the type definition of Config:

type Config = {
  // This function is called to render the title of the modal
  title?: (page: Page) => React.ReactNode;
  // This function is called to render the sub-title of the modal
  subTitle?: (page: Page) => React.ReactNode;
  // Should the modal be closed when the backdrop is clicked
  closeOnBackdropClick?: boolean;
  // Should the modal be closed when the escape key is pressed
  closeOnEscape?: boolean;
  // Configure the action list on the home page
  actionListConfig?: ActionListConfig;
};

type ActionListConfig = Record<
  string,
  {
    label?: string;
    onClick?: (chainId: string) => void;
    enabled?: boolean;
  }
>;

enum Page {
  HOME = "home",
  ACTIVITY = "activity",
}

Example Configuration

import { Page, Actions } from '@leapwallet/snaps-sdk-react'

const config: Config = {
  title: (page) => {
    switch (page) {
      case Page.HOME:
        return "Assets";
      case Page.ACTIVITY:
        return "Activity";
    }
  },
  closeOnBackdropClick: true,
  closeOnEscape: true,
  actionListConfig: {
    [Actions.Swap]: {
      label: "Swap",
      onClick: (chainId) => {
        console.log(chainId);
      },
      enabled: true,
    },
    [Actions.Bridge]: {
      enabled: false,
    },
  },
};

Usage with Custom React UI

In case you want to create your own UI in react, we have exposed the react hooks that we use internally. If you are not using react, then you can check out the next page.

For making queries, we primarily use swr, so a lot of return values from hooks will have the same return type (except for the data).

User Balances

To fetch user balances, you can use useRichBalance hook.

const balanceQuery = useRichBalance(
  address,
  chainId,
  restUrl,
  swrConfiguration
);

Parameters -

  1. address - the wallet address your querying the balance for

  2. chainId - self explanatory

  3. restUrl (optional) - custom rest url for the node

  4. swrConfiguration (optional) - configure your swr query, click here for more information

User Activity

To fetch user activity, you can use useActivity hook. The return type of a @tanstack/react-query useInfiniteQuery hook.

const activityQuery = useActivity(address, chainId, restUrl);

Parameters -

  1. address - the wallet address your querying the balance for

  2. chainId - self explanatory

  3. restUrl (optional) - custom rest url for the node

Return Value -

The activityQuery.data.pages field will be a list of objects with the following fields -

{
    sender: [] // array of activity where user is sender of tokens
    recipient: [] // // array of activity where user is received of tokens
}

Usage Example -

Using the activity data

import { type ActivityCardContent } from '@leapwallet/snaps-sdk-core'

// flat list of activity
const activityList = activityQuery.data.pages
    .reduce((acc, cur) => {
        return [...acc, ...cur.sender.activity, ...cur.recipient.activity];
    }, [] as ActivityCardContent[]);
    
// you can now sort this list however you want

Triggering the next (data) page load using the last element on the list

const [searchQuery, setSearchQuery] = useState<string>('')

useEffect(() => {
  // track last item on the list
  const lastItem = document.querySelector("#activity-bottom");
  if (
    !lastItem ||
    activityQuery.isLoading ||
    activityQuery.isFetchingNextPage ||
    activityQuery.error ||
    searchQuery.trim().length > 0
  ) {
    return;
  }
  const handleIntersection = ([i]: IntersectionObserverEntry[]) => {
    if (i.isIntersecting) {
      activityQuery.fetchNextPage();
    }
  };
  const observer = new IntersectionObserver(handleIntersection, {
    root: null,
    rootMargin: "0px",
    threshold: 1.0,
  });
  observer.observe(lastItem);
  return () => {
    observer.disconnect();
  };
}, [activityQuery, debouncedSearchQuery]);

Last updated