Embedded Wallet Integration

To get started with integrating embedded wallets into your dapp, follow these steps:

  1. Create an Apillon account: If you don't have an Apillon account or project yet, create one on the Apillon dashboardopen in new window.

  2. Open the Embedded Wallet page and create a new embedded wallet integration: Go to the Embedded Wallet pageopen in new window on the Apillon developer console and create a new embedded wallet integration. Integration UUID is needed for using the SDK.

  3. Setup whitelist: Input the domains on which you allow the integration to work on. Leave empty if you allow all website (this is not recommended).

TIP

If you want to learn more about Apillon's Embedded Wallet Service, visit the embedded wallet service wiki page.

Prerequisites

React, Vue

A Vite plugin is required for running and building Vite apps with Embedded Wallet. This plugin enables Node API in the browser (eg. buffer, crypto).

npm install -D vite-plugin-node-polyfills
// vite.config.ts
import { defineConfig } from "vite";
import { nodePolyfills } from "vite-plugin-node-polyfills";

export default defineConfig({
  plugins: [nodePolyfills() /* ... */],
});

Next.js

To use the Embedded wallet UI, your Next app has to be in app router mode. When in pages routing mode, global CSS file imports throw an error. Github Discussionopen in new window.

Nuxt

When using Vite as the build tool, a Vite plugin is required for running and building Nuxt apps with Embedded Wallet. This plugin enables Node API in the browser (eg. buffer, crypto).

WARNING

The Embedded wallet integration includes a style (CSS) file imported through JavaScript. Nuxt fails to resolve this import by default. To avoid errors, the Embedded wallet dependency needs to be added to the build.transpileopen in new window setting.

npm i -D vite-plugin-node-polyfills
// nuxt.config.ts
import { nodePolyfills } from "vite-plugin-node-polyfills";

export default defineNuxtConfig({
  vite: {
    plugins: [nodePolyfills() /* ... */],
  },
  build: {
    transpile: ["@apillon/wallet-vue"],
  },
  /* ... */
});

Installation

npm install @apillon/wallet-react
npm install @apillon/wallet-vue
npm install @apillon/wallet-ui

Installing the wallet UI also installs the core wallet package @apillon/wallet-sdk as a dependency.

In the usage examples below you will see some imports from this package.

Add wallet widget

Replace the parameters with however you wish to setup your wallet.

import { WalletWidget } from "@apillon/wallet-react";

<WalletWidget
  clientId={"YOUR INTEGRATION UUID HERE"}
  defaultNetworkId={1287}
  networks={[
    {
      name: "Moonbase Testnet",
      id: 1287,
      rpcUrl: "https://rpc.testnet.moonbeam.network",
      explorerUrl: "https://moonbase.moonscan.io",
    },
    /* ... */
  ]}
/>
import { WalletWidget } from "@apillon/wallet-vue";

<WalletWidget
  clientId="YOUR INTEGRATION UUID HERE"
  :defaultNetworkId="1287"
  :networks="[
    {
      name: 'Moonbase Testnet',
      id: 1287,
      rpcUrl: 'https://rpc.testnet.moonbeam.network',
      explorerUrl: 'https://moonbase.moonscan.io',
    },
    /* ... */
  ]"
/>
import { EmbeddedWalletUI } from "@apillon/wallet-ui";

EmbeddedWalletUI("#wallet", {
  clientId: "YOUR INTEGRATION UUID HERE",
  defaultNetworkId: 1287,
  networks: [
    {
      name: "Moonbase Testnet",
      id: 1287,
      rpcUrl: "https://rpc.testnet.moonbeam.network",
      explorerUrl: "https://moonbase.moonscan.io",
    },
    /* ... */
  ]
});

Parameters

FieldTypeRequiredDescription
clientIdstringYesUUID of the integration that you obtain when creating it on the Apillon embedded wallet dashboardopen in new window.
defaultNetworkIdnumberNoChain ID set as default when opening wallet.
networksNetwork[]NoArray of network specifications
broadcastAfterSignbooleanNoAutomatically broadcast with SDK after confirming a transaction.
disableDefaultActivatorStylebooleanNoRemove styles from "open wallet" button
authFormPlaceholderstringNoPlaceholder displayed in input for username/email

Network Object

The Network Object defines the properties required to connect to a blockchain network.

TIP

To find the information for your desired network, visit chainlist.orgopen in new window.

FieldTypeDescription
namestringThe name of the network
idnumberThe unique Chain ID of the network
rpcUrlstringThe URL to the network's RPC server
explorerUrlstringThe URL to the network's block explorer

Use wallet

To access wallet signer and wallet information we provide core imports (hooks/composables):

import { useAccount, useContract, useWallet } from "@apillon/wallet-react";

export default function Component() {
  const { username, address, getBalance } = useAccount();
  const { wallet, signMessage, sendTransaction } = useWallet();

  const { read, write } = useContract({
    abi: [
      "function claim() public",
      "function balanceOf(address) view returns (uint256)",
      "function transfer(address to, uint256 amount) public returns (bool)",
    ],
    address: "0x67b9DA16d0Adf2dF05F0564c081379479d0448f8",
    chainId: 1287,
  });

  // using wallet core SDK
  const getWalletUserExists = (username: string) => {
    return wallet.userExists(username);
  };

  // sign a message
  const onSignMessage = await (msg: string) => {
    await signMessage(msg);
  };

  // contract read
  const logContractBalance = async (address: string) => {
    console.log(await read("balanceOf", [address]));
  };

  // contract write
  const onContractTransfer = async (address: string, amount: string) => {
    await write("transfer", [address, amount], "Token transfer");
  };

  return <></>;
}
<script lang="ts" setup>
import { useAccount, useContract, useWallet } from "@apillon/wallet-vue";

const { info, getBalance } = useAccount();
const { wallet, signMessage, sendTransaction } = useWallet();

const { read, write } = useContract({
  abi: [
    "function claim() public",
    "function balanceOf(address) view returns (uint256)",
    "function transfer(address to, uint256 amount) public returns (bool)",
  ],
  address: "0x67b9DA16d0Adf2dF05F0564c081379479d0448f8",
  chainId: 1287,
});

// using wallet core SDK
function getWalletUserExists(username: string) {
  return wallet.value.userExists(username);
}

// sign a message
async function onSignMessage(msg: string) {
  await signMessage(msg);
}

// contract read
async function logContractBalance(address: string) {
  console.log(await read("balanceOf", [address]));
}

// contract write
async function onContractTransfer(address: string, amount: string) {
  await write("transfer", [address, amount], "Token transfer");
}
</script>

<template>
  <div></div>
</template>

Ethers 5 and 6

To use with ethersopen in new window library we provide a specialized ethers signer.

import { EmbeddedEthersSigner } from "@apillon/wallet-sdk";

You can create a signer like with any other ethers signer as such:

const signer = new EmbeddedEthersSigner();

// eg. sign a message
await signer.signMessage("test message");

Viem

To use viemopen in new window we provide a specialized Viem adapter.

import { EmbeddedViemAdapter } from "@apillon/wallet-sdk";
import { moonbaseAlpha } from "viem/chains";

Use can use the adapter to get the user's account and use it with Viem:

const adapter = new EmbeddedViemAdapter();
const account = adapter.getAccount();

const walletClient = createWalletClient({
  chain: moonbaseAlpha,
  transport: http(),
  account,
});

// eg. sign a message
await account.signMessage({ message: "test message" });

// eg. send a plain transaction
await walletClient.sendRawTransaction({
  serializedTransaction: await walletClient.signTransaction(
    await walletClient.prepareTransactionRequest({
      to: "...",
      value: parseUnits("0.01", 18),
    })
  ),
});

Wagmi

We provide an EIP-1193 provider that can be used with Wagmiopen in new window or any other integration that supports it.

import { getProvider as getEmbeddedProvider } from "@apillon/wallet-sdk";

const wagmiConfig = {
  /* ... */
  connectors: [
    new InjectedConnector({
      chains,
      options: {
        getProvider() {
          return getEmbeddedProvider() as any;
        },
      },
    }),
  ],
};

TypeScript

Embedded wallet can be used with plain TypeScript by interacting with the wallet SDK directly.

TIP

Find out more about the SDK in the github repositoryopen in new window

<button id="sdk-sign">(SDK) Sign message</button>
<button id="sdk-native-transfer">(SDK) Transfer native balance</button>
<button id="sdk-contract-transfer">(SDK) Contract write (transfer)</button>
import { getEmbeddedWallet } from "@apillon/wallet-sdk";

document.getElementById("sdk-sign")?.addEventListener("click", async () => {
  const w = getEmbeddedWallet();

  if (w) {
    await w.signMessage({
      message: "test message",
      mustConfirm: true,
    });
  }
});
import { getEmbeddedWallet } from "@apillon/wallet-sdk";

document
  .getElementById("sdk-native-transfer")
  ?.addEventListener("click", async () => {
    const w = getEmbeddedWallet();

    if (w) {
      const result = await w.signPlainTransaction({
        tx: {
          to: "...",
          value: "10000000",
        },
        mustConfirm: true,
      });

      console.log(result);

      if (result) {
        console.log(
          await w.broadcastTransaction(result.signedTxData, result.chainId)
        );
      }
    }
  });
import { getEmbeddedWallet } from "@apillon/wallet-sdk";

document
  .getElementById("sdk-contract-transfer")
  ?.addEventListener("click", async () => {
    const w = getEmbeddedWallet();

    if (w) {
      const result = await w.signContractWrite({
        contractAbi: [
          "function claim() public",
          "function balanceOf(address) view returns (uint256)",
          "function transfer(address to, uint256 amount) public returns (bool)",
        ],
        contractAddress: "0x67b9DA16d0Adf2dF05F0564c081379479d0448f8",
        contractFunctionName: "transfer",
        contractFunctionValues: ["...", "10000000"],
        chainId: 1287,
        mustConfirm: true,
      });

      console.log(result);

      if (result) {
        console.log(
          await w.broadcastTransaction(
            result.signedTxData,
            result.chainId,
            "JS transfer"
          )
        );
      }
    }
  });

Create custom UI

All the functionalities of embedded wallets are contained in base package @apillon/wallet-sdk. The SDK exposes all the core methods of the wallet and you can create completely custom UI of the wallet on top of it.

TIP

For detailed technical documentation about the embedded wallet SDK, visit the github repositoryopen in new window

NPM Packages

Examples

React

Next.js

Vue.js

Nuxt

TypeScript