Tomo Connect SDK Lite

The Tomo Connect SDK Lite aims to define an easy-to-integrate and highly compatible Blockchain Provider API for dApps. This API allows dApps to easily connect to all kinds of wallets (including extension wallets, hardware wallets, and mobile wallets), retrieve account asset data, and sign messages and transactions (especially Babylon staking related transactions).

Integration

First, you need to add Tomo Connect SDK in to your project dependency:

npm install @tomo-inc/wallet-connect-sdk

Then initialize the UI view and context provider

import {
  TomoContextProvider,
  useTomoModalControl,
  useTomoWalletConnect
} from '@tomo-inc/wallet-connect-sdk'

export default function Demo() {
  return (
    <TomoContextProvider
      // optional
      style={{
        rounded: 'medium',
        theme: 'light',
        primaryColor: '#FF7C2A'
      }}
    >
      <ChildComponent />
    </TomoContextProvider>
  )
}

type ChildProps = {
  style: TomoProviderSetting['style']
  setStyle: (v: TomoProviderSetting['style']) => void
}
export function ChildComponent(props: ChildProps) {
  const tomoModal = useTomoModalControl()
  const tomoWalletConnect = useTomoWalletConnect()

  return (
    <div style={{ textAlign: 'right' }}>
      <button
        onClick={async () => {
          await tomoModal.open('connect')
        }}
      >
        Connect Wallet
      </button>
      <button
        onClick={async () => {
          await tomoWalletConnect.disconnect()
        }}
      >
        Disconnect Wallet
      </button>
    </div>
  )
}

Using the above code in your dApp, you can easily open Tomo BTC connect modal and interact with the supported BTC wallet.

Using the Provider API

Once you connect the wallet, you can use the following way to interact with the connect wallet:

import {
  useTomoProviders,
  useTomoModalControl,
  useTomoWalletConnect,
  useTomoWalletState
} from '@tomo-inc/wallet-connect-sdk'

// Open BTC connect modal
const tomoModal = useTomoModalControl();
tomoModal.open("connect");

// Check wallet connection status
const tomowalletState = useTomoWalletState();
const connected = tomowalletState.isConnected;

// Get provider
const providers = useTomoProviders();
const provider = providers.bitcoinProvider;

// Disconnect
const tomoWalletConnect = useTomoWalletConnect();
tomoWalletConnect.disconnect();

All the provider APIs are as follows:

export type Fees = {
  // fee for inclusion in the next block
  fastestFee: number
  // fee for inclusion in a block in 30 mins
  halfHourFee: number
  // fee for inclusion in a block in 1 hour
  hourFee: number
  // economy fee: inclusion not guaranteed
  economyFee: number
  // minimum fee: the minimum fee of the network
  minimumFee: number
}

// UTXO is a structure defining attributes for a UTXO
export interface UTXO {
  // hash of transaction that holds the UTXO
  txid: string
  // index of the output in the transaction
  vout: number
  // amount of satoshis the UTXO holds
  value: number
  // the script that the UTXO contains
  scriptPubKey: string
}

// supported networks
export enum Network {
  MAINNET = 'mainnet',
  TESTNET = 'testnet',
  SIGNET = 'signet'
}

export abstract class WalletProvider {
  abstract connectWallet(): Promise<this>
  abstract getWalletProviderName(): Promise<string>
  abstract getAddress(): Promise<string>
  abstract getPublicKeyHex(): Promise<string>
  abstract signPsbt(psbtHex: string): Promise<string>
  abstract signPsbts(psbtsHexes: string[]): Promise<string[]>
  abstract getNetwork(): Promise<Network>
  abstract signMessageBIP322(message: string): Promise<string>
  abstract on(eventName: string, callBack: () => void): void
  abstract off(eventName: string, callBack: () => void): void
  abstract switchNetwork(network: Network): Promise<void>
  abstract sendBitcoin(to: string, satAmount: number): Promise<string>
  abstract getNetworkFees(): Promise<Fees>
  abstract pushTx(txHex: string): Promise<string>
  abstract getUtxos(address: string, amount?: number): Promise<UTXO[]>
  abstract getBTCTipHeight(): Promise<number>
  abstract getBalance(): Promise<number>
}

Wallet Customization

Currently Tomo Connect SDK supports the following BTC wallet:

  • OKX Bitcoin

  • Unisat

  • Tomo Bitcoin

  • OneKey Bitcoin

  • Bitget Bitcoin

  • Keystone Bitcoin

If you want to support your own Bitcoin wallet into the wallet list, there are two ways:

Submit Wallet PR

Submit a PR to https://github.com/UnyxTech/tomo-wallet-provider

The example PR can be found here

Implement Your BTC Provider

import {
  Network,
  WalletInfo,
  WalletProvider
} from '@tomo-inc/tomo-wallet-provider'
import { parseUnits } from '@tomo-inc/tomo-wallet-provider'

export const xyzProvider = 'xyz'

export class XYZWallet extends WalletProvider {
  private xyzWalletInfo: WalletInfo | undefined
  private bitcoinNetworkProvider: any

  constructor() {
    super()
    if (!window[xyzProvider]) {
      throw new Error('XYZ Wallet extension not found')
    }

    this.bitcoinNetworkProvider = window[xyzProvider]
  }

  connectWallet = async (): Promise<this> => {
    const workingVersion = '1.0.0'
    if (!this.bitcoinNetworkProvider) {
      throw new Error('XYZ Wallet extension not found')
    }
    if (this.bitcoinNetworkProvider.getVersion) {
      const version = await this.bitcoinNetworkProvider.getVersion()
      if (version < workingVersion) {
        throw new Error('Please update XYZ Wallet to the latest version')
      }
    }

    let addresses = null
    let pubKey = null
    try {
      addresses = await this.bitcoinNetworkProvider.connectWallet()
      pubKey = await this.bitcoinNetworkProvider.getPublicKey()
      if (!addresses || addresses.length === 0 || !pubKey) {
        throw new Error('BTC is not enabled in XYZ Wallet')
      }
    } catch (error) {
      throw new Error('BTC is not enabled in XYZ Wallet')
    }

    this.xyzWalletInfo = {
      publicKeyHex: pubKey,
      address: addresses[0]
    }
    return this
  }

  getWalletProviderName = async (): Promise<string> => {
    return 'XYZ'
  }

  getAddress = async (): Promise<string> => {
    return (await this.bitcoinNetworkProvider.getAccounts())[0]
  }

  getPublicKeyHex = async (): Promise<string> => {
    if (!this.xyzWalletInfo) {
      throw new Error('XYZ Wallet not connected')
    }
    return this.xyzWalletInfo.publicKeyHex
  }

  signPsbt = async (psbtHex: string): Promise<string> => {
    if (!this.xyzWalletInfo) {
      throw new Error('XYZ Wallet not connected')
    }
    return await this.bitcoinNetworkProvider.signPsbt(psbtHex)
  }

  signPsbts = async (psbtsHexes: string[]): Promise<string[]> => {
    if (!this.xyzWalletInfo) {
      throw new Error('XYZ Wallet not connected')
    }
    return await this.bitcoinNetworkProvider.signPsbts(psbtsHexes)
  }

  signMessageBIP322 = async (message: string): Promise<string> => {
    if (!this.xyzWalletInfo) {
      throw new Error('XYZ Wallet not connected')
    }
    return await this.bitcoinNetworkProvider.signMessage(
      message,
      'bip322-simple'
    )
  }

  getNetwork = async (): Promise<Network> => {
    return await this.bitcoinNetworkProvider.getNetwork()
  }

  on = (eventName: string, callBack: () => void) => {
    return this.bitcoinNetworkProvider.on(eventName, callBack)
  }

  off = (eventName: string, callBack: () => void) => {
    return this.bitcoinNetworkProvider.off(eventName, callBack)
  }

  getBalance = async (): Promise<number> => {
    const result = await this.bitcoinNetworkProvider.getBalance()
    return result
  }

  pushTx = async (txHex: string): Promise<string> => {
    return await this.bitcoinNetworkProvider.pushTx(txHex)
  }

  async switchNetwork(network: Network) {
    return await this.bitcoinNetworkProvider.switchNetwork(network)
  }

  async sendBitcoin(to: string, satAmount: number) {
    const result = await this.bitcoinNetworkProvider.sendBitcoin(
      to,
      Number(parseUnits(satAmount.toString(), 8))
    )
    return result
  }
}

Then you can use it in the wallet contxt provider

<TomoContextProvider
  additionalWallets={[
    {
      id: 'xyz',
      name: 'XYZ BTC Wallet',
      chainType: 'bitcoin',
      connectProvider: XYZWallet,
      type: 'extension',
      img: 'https://your wallet logo.svg'
    }
  ]}
  // optional
  uiOptions={{
    termsAndServiceUrl: 'https://your wallet terms',
    privacyPolicyUrl: 'https://your wallet privacy'
  }}
>
</TomoContextProvider>

Last updated