Guides
Adding a new signer to IdentityKit

Adding a New Signer to IdentityKit

To add your wallet as a signer to IdentityKit, follow these four steps:

  1. Clone the IdentityKit repository.
  2. Add your wallet configuration.
  3. Create a pull request.
  4. Wait for approval and merge of the pull request.

Steps

1. Clone the IdentityKit repository

First, clone the IdentityKit repository to your local machine. Open your terminal and run the following command:

git clone https://github.com/internet-identity-labs/identitykit.git

2. Add your wallet configuration

Open the packages/identitykit/src/lib/signers.ts file in your preferred code editor and add your wallet configuration. Ensure that each field is correctly filled out:

  • id: A unique identifier for your wallet. Make sure it is unique to avoid conflicts.
  • description: The description shown when the wallet is in feature mode.
  • providerUrl: The URL to connect to your wallet. This URL should be compatible with ICRC standards (opens in a new tab).
  • transportType: The method your wallet uses to communicate with the client's dApp. If your wallet is an extension, use TransportType.EXTENSION. For web dApps, you can choose TransportType.NEW_TAB.
  • label: The display name of your wallet.
  • icon: A base64-encoded SVG image representing your wallet.

Here is an example configuration:

const YourWalletSigner: SignerConfig = {
  id: "YourWalletSignerIdentifier",
  description: "Your wallet description.",
  providerUrl: "https://your-wallet-rpc-url.com",
  transportType: TransportType.NEW_TAB,
  label: "Your Wallet Name",
  icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0ac+Cg==",
}

2.1. Extension Wallet Case

If you are working with a non-extension wallet, this section may be skipped. The process for connecting an extension wallet to IdentityKit is more complex until the completion of ICRC-94 (opens in a new tab). To facilitate communication between IdentityKit and your extension wallet, two classes must be added. The Plug transport layer is provided as an example, and a similar Channel should be created for your wallet.

2.1.1. Add the Extension Wallet Channel

import { type Channel, type JsonRequest, type JsonResponse } from "@slide-computer/signer"
import { PlugTransportError } from "./plugTransport"
 
export class PlugChannel implements Channel {
  readonly #responseListeners = new Set<(response: JsonResponse) => void>()
 
  get closed(): boolean {
    return (
      !("ic" in window) ||
      typeof window.ic !== "object" ||
      !window.ic ||
      !("plug" in window.ic) ||
      typeof window.ic.plug !== "object" ||
      !window.ic.plug ||
      !("request" in window.ic.plug) ||
      typeof window.ic.plug.request !== "function"
    )
  }
 
  addEventListener(
    ...[event, listener]:
      | [event: "close", listener: () => void]
      | [event: "response", listener: (response: JsonResponse) => void]
  ): () => void {
    switch (event) {
      case "close":
        return () => {}
      case "response":
        this.#responseListeners.add(listener)
        return () => {
          this.#responseListeners.delete(listener)
        }
    }
  }
 
  async send(request: JsonRequest): Promise<void> {
    if (this.closed) throw new PlugTransportError("Plug wallet cannot be found")
 
    // @ts-ignore Call plug window method
    const response = await window.ic.plug.request(request)
 
    // One way messages, don't have a response
    if (request.id === undefined) return
 
    // Call listeners with response
    this.#responseListeners.forEach((listener) => listener(response))
  }
 
  async close(): Promise<void> {}
}

2.1.2. Add the Transport class as shown

import { type Channel, type Transport } from "@slide-computer/signer"
import { PlugChannel } from "./plugChannel"
 
export class PlugTransportError extends Error {
  constructor(message: string) {
    super(message)
    Object.setPrototypeOf(this, PlugTransportError.prototype)
  }
}
 
export class PlugTransport implements Transport {
  async establishChannel(): Promise<Channel> {
    return new PlugChannel()
  }
}

2.1.3. Add your Wallet ID and initialize the Transport class in the switch clause in packages/identitykit/src/lib/service/transport-builder/extension-transport.builder.ts for the repository.

import { Transport } from "@slide-computer/signer"
import { PlugTransport } from "@slide-computer/signer-transport-plug"
import { TransportBuilderRequest } from "./transport.builder"
 
export function getExtensionTransportBuilder({ id }: TransportBuilderRequest): Transport {
  switch (id) {
    case "Plug":
      return new PlugTransport()
    case "YouExtensionWallet":
      return new YourExtensionWalletTransport()
    default:
      throw Error("The extension wallet is not supported.")
  }
}

Submit these changes along with any other modifications in your pull request.

3. Create a pull request

After adding your wallet configuration, commit your changes and push them to the repository. Then, create a pull request (PR).

4. Wait for approval and merge of the pull request

Wait for the maintainers to review and approve your pull request. Once approved, it will be merged into the main branch, and the new version of the @nfid/identitykit NPM package (opens in a new tab) will be released.


By following these steps, you will successfully add your wallet as a signer to IdentityKit.