Adding a New Signer to IdentityKit
To add your wallet as a signer to IdentityKit, follow these four steps:
- Clone the IdentityKit repository.
- Add your wallet configuration.
- Create a pull request.
- 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.
- 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 chooseTransportType.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. 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 will be released.
By following these steps, you will successfully add your wallet as a signer to IdentityKit.