# Add Custom Wallets

It is easy to add all kinds of wallets to Tomo Connect SDK.  Here is an example of how to add a Bitcoin wallet to Tomo Connect SDK.

### Fork Tomo Wallet Provider Repo

Please fork the main branch of <https://github.com/UnyxTech/tomo-wallet-provider> into your own repo. After you finish the following integration steps, submit a PR to the `tomo-wallet-provider` repo.

### Add Your Wallet Icon and Wallet Info

Put your wallet icon into the `icons` folder, and create your wallet info into the `list.ts`, such as:

```javascript
  {
    name: "Tomo",
    icon: tomoIcon,
    wallet: TomoWallet,
    provider: tomoProvider,
    linkToDocs: "https://tomo.inc/",
  }
```

### Create Your Wallet Provider

Put your wallet provider into the `providers` folder, and it should extend the `WalletProvider` defined in the library.

Example:

```javascript
import { getNetworkConfig } from "@/config/network.config";
import {
  getAddressBalance,
  getFundingUTXOs,
  getNetworkFees,
  getTipHeight,
  pushTx,
} from "@/utils/mempool_api";

import {
  Fees,
  Network,
  UTXO,
  WalletInfo,
  WalletProvider,
} from "../wallet_provider";

export const tomoProvider = "tomo_btc";

// Internal network names
const INTERNAL_NETWORK_NAMES = {
  [Network.MAINNET]: "mainnet",
  [Network.TESTNET]: "testnet",
  [Network.SIGNET]: "signet",
};

export class TomoWallet extends WalletProvider {
  private tomoWalletInfo: WalletInfo | undefined;
  private bitcoinNetworkProvider: any;
  private networkEnv: Network | undefined;

  constructor() {
    super();

    // check whether there is Tomo extension
    if (!window[tomoProvider]) {
      throw new Error("Tomo Wallet extension not found");
    }
    this.networkEnv = getNetworkConfig().network;

    this.bitcoinNetworkProvider = window[tomoProvider];
  }

  connectWallet = async (): Promise<this> => {
    const workingVersion = "1.2.0";
    if (!this.bitcoinNetworkProvider) {
      throw new Error("Tomo Wallet extension not found");
    }
    if (!this.networkEnv) {
      throw new Error("Network not found");
    }
    if (this.bitcoinNetworkProvider.getVersion) {
      const version = await this.bitcoinNetworkProvider.getVersion();
      if (version < workingVersion) {
        throw new Error("Please update Tomo Wallet to the latest version");
      }
    }

    await this.bitcoinNetworkProvider.switchNetwork(
      INTERNAL_NETWORK_NAMES[this.networkEnv],
    );

    let addresses = null;
    let pubKey = null;
    try {
      // this will not throw an error even if user has no BTC Signet enabled
      addresses = await this.bitcoinNetworkProvider.connectWallet();
      pubKey = await this.bitcoinNetworkProvider.getPublicKey();
      if (!addresses || addresses.length === 0 || !pubKey) {
        throw new Error("BTC is not enabled in Tomo Wallet");
      }
    } catch (error) {
      throw new Error("BTC is not enabled in Tomo Wallet");
    }

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

  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");
    }
    // sign the PSBT
    return await this.bitcoinNetworkProvider.signPsbt(psbtHex);
  };

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

    // sign the PSBTs
    return await this.bitcoinNetworkProvider.signPsbts(psbtsHexes);
  };

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

  getNetwork = async (): Promise<Network> => {
    const internalNetwork = await this.bitcoinNetworkProvider.getNetwork();

    for (const [key, value] of Object.entries(INTERNAL_NETWORK_NAMES)) {
      if (value === internalNetwork) {
        return key as Network;
      }
    }

    throw new Error("Unsupported network");
  };

  on = (eventName: string, callBack: () => void) => {
    if (!this.tomoWalletInfo) {
      throw new Error("Tomo Wallet not connected");
    }
    // subscribe to account change event
    if (eventName === "accountChanged") {
      return this.bitcoinNetworkProvider.on(eventName, callBack);
    }
  };

  // Mempool calls

  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[]> => {
    // mempool call
    return await getFundingUTXOs(address, amount);
  };

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.tomo.inc/tomo-sdk/tomo-web-sdk/wallet-providers/add-custom-wallets.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
