Bitcoin Integration

Tomo Extension Wallet injects tomo_btc into the window object in your browser. dApp can easily interact with the wallet via window.tomo_btc. The following demo code shows how it works:

const example = async () => {
    // connect to tomo wallet and get accounts
    const accounts = await window.tomo_btc.requestAccounts()
    
    // the first account is the selected account
    const account = accounts[0]
        
    const signature = await window.tomo_btc.signMessage('Hello Tomo', 'bip322-simple')
    // do something about the signature
}

Tomo extension wallet follows the wallet adaptor interface defined by Babylon chain. Any Bitcoin ecosystem dApps can use the following Tomo implementation.

import { WalletProvider, Network, Fees, UTXO, WalletInfo } from "./wallet_provider";
import {
  getAddressBalance,
  getTipHeight,
  getFundingUTXOs,
  getNetworkFees,
  pushTx
} from "../mempool_api";

export class TOMOWallet extends WalletProvider {
  private tomoWalletInfo: WalletInfo | undefined;

  constructor() {
    super();
  }

  connectWallet = async (): Promise<this> => {
    const workingVersion = "1.1.1";
    if (!window.tomo_btc) {
      throw new Error("Tomo extension wallet not found");
    }

    const tomowallet = window.tomo_btc;
    let result = null;
    try {
      result = await tomowallet?.requestAccounts();
    } catch (error) {
      throw new Error("Bitcoin is not enabled in Tomo wallet");
    }

    let compressedPublicKey = null;
    try {
      compressedPublicKey = await tomowallet?.getPublicKey();
    } catch (error) {
      throw new Error("Bitcoin is not enabled in Tomo wallet");
    }

    if (compressedPublicKey && result[0]) {
      this.tomoWalletInfo = {
        publicKeyHex: compressedPublicKey,
        address: result[0],
      };
      return this;
    } else {
      throw new Error("Failed to connect to Tomo wallet");
    }
  };

  getWalletProviderName = async (): Promise<string> => {
    return "Tomo";
  };

  getAddress = async (): Promise<string> => {
    if (!this.tomoWalletInfo) {
      throw new Error("Tomo wallet not connected");
    }
    return this.tomoWalletInfo.address;
  };

  getPublicKeyHex = async (): Promise<string> => {
    if (!this.tomoWalletInfo) {
      throw new Error("Tomo wallet not connected");
    }
    return this.tomoWalletInfo.publicKeyHex;
  };

  signPsbt = async (psbtHex: string): Promise<string> => {
    if (!this.tomoWalletInfo) {
      throw new Error("Tomo wallet not connected");
    }
    return await window?.tomo_btc?.signPsbt(psbtHex);
  };

  signPsbts = async (psbtsHexes: string[]): Promise<string[]> => {
    if (!this.tomoWalletInfo) {
      throw new Error("Tomo wallet not connected");
    }
    return await window?.tomo_btc?.signPsbts(psbtsHexes);
  };

  signMessageBIP322 = async (message: string): Promise<string> => {
    if (!this.tomoWalletInfo) {
      throw new Error("TOMO Wallet not connected");
    }
    return await window?.tomo_btc?.signMessage(
      message,
      "bip322-simple",
    );
  };

  getNetwork = async (): Promise<Network> => {
    return "testnet";
  };

  on = (eventName: string, callBack: () => void) => {
    if (!this.tomoWalletInfo) {
      throw new Error("TOMO Wallet not connected");
    }
    if (eventName === "accountChanged") {
      return window.tomo_btc.on(eventName, callBack);
    }
  };

  getBalance = async (): Promise<number> => {
    return await getAddressBalance(await this.getAddress());
  };

  getNetworkFees = async (): Promise<Fees> => {
    return await getNetworkFees();
  };

  pushTx = async (txHex: string): Promise<string> => {
    return await pushTx(txHex);
  };

  getUtxos = async (address: string, amount: number): Promise<UTXO[]> => {
    return await getFundingUTXOs(address, amount);
  };

  getBTCTipHeight = async (): Promise<number> => {
    return await getTipHeight();
  };
}

Last updated