From 26ec56e46a1f424dca2d632b4ca7d129f5f6de78 Mon Sep 17 00:00:00 2001 From: ByteAtATime Date: Sat, 5 Oct 2024 11:32:37 -0700 Subject: [PATCH 1/2] feat: allow for custom ids passed in through a config --- example/app/wagmiConfig.ts | 9 +++- .../src/burnerConnector/burner.ts | 22 +++++--- packages/burner-connector/src/index.ts | 2 +- packages/burner-connector/src/utils/index.ts | 15 +++--- .../rainbowkit/rainbowkitBurnerConnector.ts | 6 +-- .../rainbowkit/rainbowkitBurnerWallet.ts | 52 ++++++++++++++++--- 6 files changed, 79 insertions(+), 27 deletions(-) diff --git a/example/app/wagmiConfig.ts b/example/app/wagmiConfig.ts index c9e20c1..7997737 100644 --- a/example/app/wagmiConfig.ts +++ b/example/app/wagmiConfig.ts @@ -5,7 +5,14 @@ import { metaMaskWallet } from "@rainbow-me/rainbowkit/wallets"; import { createClient, http } from "viem"; import { rainbowkitBurnerWallet } from "burner-connector"; -const wallets = [metaMaskWallet, rainbowkitBurnerWallet]; +const wallets = [ + metaMaskWallet, + // default burner wallet + rainbowkitBurnerWallet, + // burner wallet with custom id and name + rainbowkitBurnerWallet({ id: "burnerWallet1", name: "Burner Wallet 1" }), + rainbowkitBurnerWallet({ id: "burnerWallet2", name: "Burner Wallet 2" }), +]; const walletConnectProjectID = "3a8170812b534d0ff9d794f19a901d64"; const wagmiConnectors = connectorsForWallets( [ diff --git a/packages/burner-connector/src/burnerConnector/burner.ts b/packages/burner-connector/src/burnerConnector/burner.ts index fc17f23..9814e0e 100644 --- a/packages/burner-connector/src/burnerConnector/burner.ts +++ b/packages/burner-connector/src/burnerConnector/burner.ts @@ -12,7 +12,7 @@ import { } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { getHttpRpcClient, hexToBigInt, hexToNumber, numberToHex } from "viem/utils"; -import { burnerWalletId, burnerWalletName, loadBurnerPK } from "../utils/index.js"; +import { defaultBurnerId, defaultBurnerName, loadBurnerPK } from "../utils/index.js"; export class ConnectorNotConnectedError extends BaseError { override name = "ConnectorNotConnectedError"; @@ -30,13 +30,23 @@ export class ChainNotConfiguredError extends BaseError { type Provider = ReturnType, EIP1193RequestFn>>; -export const burner = () => { +export type BurnerConnectorConfig = { + id?: string; + name?: string; + storageKey?: string; +}; + +const defaultBurnerStorageKey = "burnerWallet.pk"; + +export const burner = (burnerConfig: BurnerConnectorConfig = {}) => { let connected = true; let connectedChainId: number; + + const storageKey = burnerConfig.storageKey ?? burnerConfig.id + ".pk" ?? defaultBurnerStorageKey; return createConnector((config) => ({ - id: burnerWalletId, - name: burnerWalletName, - type: burnerWalletId, + id: burnerConfig.id ?? defaultBurnerId, + name: burnerConfig.name ?? defaultBurnerName, + type: burnerConfig.id ?? defaultBurnerId, async connect({ chainId } = {}) { const provider = await this.getProvider(); const accounts = await provider.request({ @@ -55,7 +65,7 @@ export const burner = () => { const url = chain.rpcUrls.default.http[0]; if (!url) throw new Error("No rpc url found for chain"); - const burnerAccount = privateKeyToAccount(loadBurnerPK()); + const burnerAccount = privateKeyToAccount(loadBurnerPK(burnerConfig.storageKey ?? storageKey)); const client = createWalletClient({ chain: chain, account: burnerAccount, diff --git a/packages/burner-connector/src/index.ts b/packages/burner-connector/src/index.ts index 540211e..e634f91 100644 --- a/packages/burner-connector/src/index.ts +++ b/packages/burner-connector/src/index.ts @@ -1,2 +1,2 @@ -export { burner } from "./burnerConnector/burner.js"; +export { burner, type BurnerConnectorConfig } from "./burnerConnector/burner.js"; export { rainbowkitBurnerWallet } from "./wallets/rainbowkit/index.js"; diff --git a/packages/burner-connector/src/utils/index.ts b/packages/burner-connector/src/utils/index.ts index 053278b..61eaa93 100644 --- a/packages/burner-connector/src/utils/index.ts +++ b/packages/burner-connector/src/utils/index.ts @@ -1,9 +1,8 @@ import type { Hex } from "viem"; import { generatePrivateKey } from "viem/accounts"; -const burnerStorageKey = "burnerWallet.pk"; -export const burnerWalletId = "burnerWallet" as const; -export const burnerWalletName = "Burner Wallet" as const; +export const defaultBurnerId = "burnerWallet" as const; +export const defaultBurnerName = "Burner Wallet" as const; /** * Checks if the private key is valid @@ -15,19 +14,19 @@ const isValidPK = (pk: Hex | string | undefined | null): boolean => { /** * Save the current burner private key to local storage */ -export const saveBurnerPK = (privateKey: Hex): void => { +export const saveBurnerPK = (privateKey: Hex, storageKey: string): void => { if (typeof window !== "undefined" && window != null) { - window?.localStorage?.setItem(burnerStorageKey, privateKey); + window?.localStorage?.setItem(storageKey, privateKey); } }; /** * Gets the current burner private key from local storage */ -export const loadBurnerPK = (): Hex => { +export const loadBurnerPK = (storageKey: string): Hex => { let currentSk: Hex = "0x"; if (typeof window !== "undefined" && window != null) { - currentSk = (window?.localStorage?.getItem?.(burnerStorageKey)?.replaceAll('"', "") ?? "0x") as Hex; + currentSk = (window?.localStorage?.getItem?.(storageKey)?.replaceAll('"', "") ?? "0x") as Hex; } if (!!currentSk && isValidPK(currentSk)) { @@ -35,6 +34,6 @@ export const loadBurnerPK = (): Hex => { } // If no burner is found in localstorage, we will generate a random private key const newDefaultPrivateKey = generatePrivateKey(); - saveBurnerPK(newDefaultPrivateKey); + saveBurnerPK(newDefaultPrivateKey, storageKey); return newDefaultPrivateKey; }; diff --git a/packages/burner-connector/src/wallets/rainbowkit/rainbowkitBurnerConnector.ts b/packages/burner-connector/src/wallets/rainbowkit/rainbowkitBurnerConnector.ts index b7dc7fa..37ff284 100644 --- a/packages/burner-connector/src/wallets/rainbowkit/rainbowkitBurnerConnector.ts +++ b/packages/burner-connector/src/wallets/rainbowkit/rainbowkitBurnerConnector.ts @@ -1,13 +1,13 @@ import type { WalletDetailsParams } from "@rainbow-me/rainbowkit"; import { createConnector } from "@wagmi/core"; import type { EIP1193RequestFn, Transport, WalletRpcSchema } from "viem"; -import { burner } from "../../burnerConnector/burner.js"; +import { burner, type BurnerConnectorConfig } from "../../burnerConnector/burner.js"; type Provider = ReturnType, EIP1193RequestFn>>; -export const rainbowkitBurnerConnector = (walletDetails: WalletDetailsParams) => { +export const rainbowkitBurnerConnector = (burnerConfig: BurnerConnectorConfig = {}) => (walletDetails: WalletDetailsParams) => { return createConnector((config) => ({ - ...burner()(config), + ...burner(burnerConfig)(config), ...walletDetails, })); }; diff --git a/packages/burner-connector/src/wallets/rainbowkit/rainbowkitBurnerWallet.ts b/packages/burner-connector/src/wallets/rainbowkit/rainbowkitBurnerWallet.ts index 7163624..290eb3a 100644 --- a/packages/burner-connector/src/wallets/rainbowkit/rainbowkitBurnerWallet.ts +++ b/packages/burner-connector/src/wallets/rainbowkit/rainbowkitBurnerWallet.ts @@ -1,17 +1,53 @@ import type { Wallet } from "@rainbow-me/rainbowkit"; -import { burnerWalletId, burnerWalletName } from "../../utils/index.js"; import { rainbowkitBurnerConnector } from "./rainbowkitBurnerConnector.js"; +import type { BurnerConnectorConfig } from "../../burnerConnector/burner.js"; +import { defaultBurnerId, defaultBurnerName } from "../../utils/index.js"; const burnerWalletIconBase64 = "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzUzIiBoZWlnaHQ9IjM1MiIgdmlld0JveD0iMCAwIDM1MyAzNTIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHg9IjAuNzE2MzA5IiB5PSIwLjMxNzEzOSIgd2lkdGg9IjM1MS4zOTQiIGhlaWdodD0iMzUxLjM5NCIgZmlsbD0idXJsKCNwYWludDBfbGluZWFyXzNfMTUxKSIvPgo8Y2lyY2xlIGN4PSIzNC40OTUzIiBjeT0iMzQuNDk1MyIgcj0iMzQuNDk1MyIgdHJhbnNmb3JtPSJtYXRyaXgoLTEgMCAwIDEgMjA3LjAxOCAyNTQuMTIpIiBmaWxsPSIjRkY2NjBBIi8+CjxwYXRoIGQ9Ik0xNTQuMzE4IDMxNy45NTVDMTcxLjI3MyAzMTAuODkgMTc2LjU4MiAyOTAuNzE1IDE3Ni4xNTcgMjgzLjQ4N0wyMDcuMDE4IDI4OC44NjRDMjA3LjAxOCAzMDMuMzE0IDIwMC4yMTIgMzA5LjQwMiAxOTcuODI0IDMxMi40MzNDMTkzLjQ3NCAzMTcuOTU1IDE3My4zNTEgMzMwLjAzIDE1NC4zMTggMzE3Ljk1NVoiIGZpbGw9InVybCgjcGFpbnQxX3JhZGlhbF8zXzE1MSkiLz4KPGcgZmlsdGVyPSJ1cmwoI2ZpbHRlcjBfZF8zXzE1MSkiPgo8cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTIyNy4zNzcgMzAyLjI3NkMyMjYuNDI2IDMwNS44OTcgMjMwLjMxNSAzMDkuNDA1IDIzMy4zOTYgMzA3LjI3OUMyNTQuNTM4IDI5Mi42ODQgMjcwLjQ3OSAyNjkuOTQ1IDI3NC44OSAyNDcuNDg5QzI4Mi4yNCAyMTAuMDcxIDI3Mi4yMzUgMTc1LjcyNyAyMzguMDI4IDE0NS45MjVDMjAwLjg3NCAxMTMuNTU2IDE5MS44NDQgODguNDU2MSAxOTAuMTYyIDUwLjg3MThDMTg5Ljc5NyA0Mi43MjE4IDE4MS42MDQgMzcuMjk0NyAxNzQuODI0IDQxLjgzMTdDMTUyLjY2OCA1Ni42NTc0IDEzMi41MTIgODQuNDk5IDEzOC45MTEgMTIwLjc1OEMxNDEuMDA0IDEzMi42MjEgMTQ2Ljc5NCAxNDEuMDE2IDE1MS45NyAxNDguNTIzQzE1OC40OTEgMTU3Ljk3OCAxNjQuMDM5IDE2Ni4wMjMgMTU5Ljk5NyAxNzcuODFDMTU1LjIwMyAxOTEuNzk0IDEzOS4xMzQgMTk5LjE2MiAxMjguNzQ3IDE5Mi40MjlDMTE0LjE3IDE4Mi45ODEgMTEzLjI1MyAxNjYuNjUxIDExNy45NjkgMTQ5LjQ1NkMxMTguOTAyIDE0Ni4wNTUgMTE1LjQ3MSAxNDMuMjA0IDExMi42OCAxNDUuMzU5QzkxLjM2MDQgMTYxLjgyMSA2OS4xNTMyIDE5OS4yNjcgNzcuNjY0NyAyNDcuNDg5Qzg1Ljk3OTIgMjc2LjIxMiA5Ny45Mjc3IDI5Mi41MzcgMTEwLjk3MSAzMDEuNTQxQzExMy43NjMgMzAzLjQ2OCAxMTcuMTU5IDMwMC42MzEgMTE2LjU5NyAyOTcuMjg2QzExNi4wODEgMjk0LjIxMiAxMTUuODEzIDI5MS4wNTQgMTE1LjgxMyAyODcuODMzQzExNS44MTMgMjU2LjUxMyAxNDEuMjAzIDIzMS4xMjMgMTcyLjUyMyAyMzEuMTIzQzIwMy44NDIgMjMxLjEyMyAyMjkuMjMyIDI1Ni41MTMgMjI5LjIzMiAyODcuODMzQzIyOS4yMzIgMjkyLjgyNCAyMjguNTg3IDI5Ny42NjUgMjI3LjM3NyAzMDIuMjc2WiIgZmlsbD0idXJsKCNwYWludDJfbGluZWFyXzNfMTUxKSIvPgo8L2c+CjxkZWZzPgo8ZmlsdGVyIGlkPSJmaWx0ZXIwX2RfM18xNTEiIHg9IjcyLjExMTIiIHk9IjM2LjQ5NCIgd2lkdGg9IjIwOC43NDIiIGhlaWdodD0iMjc1LjEyIiBmaWx0ZXJVbml0cz0idXNlclNwYWNlT25Vc2UiIGNvbG9yLWludGVycG9sYXRpb24tZmlsdGVycz0ic1JHQiI+CjxmZUZsb29kIGZsb29kLW9wYWNpdHk9IjAiIHJlc3VsdD0iQmFja2dyb3VuZEltYWdlRml4Ii8+CjxmZUNvbG9yTWF0cml4IGluPSJTb3VyY2VBbHBoYSIgdHlwZT0ibWF0cml4IiB2YWx1ZXM9IjAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDEyNyAwIiByZXN1bHQ9ImhhcmRBbHBoYSIvPgo8ZmVPZmZzZXQvPgo8ZmVHYXVzc2lhbkJsdXIgc3RkRGV2aWF0aW9uPSIxLjg0NTA2Ii8+CjxmZUNvbXBvc2l0ZSBpbjI9ImhhcmRBbHBoYSIgb3BlcmF0b3I9Im91dCIvPgo8ZmVDb2xvck1hdHJpeCB0eXBlPSJtYXRyaXgiIHZhbHVlcz0iMCAwIDAgMCAxIDAgMCAwIDAgMC40MiAwIDAgMCAwIDAgMCAwIDAgMC43IDAiLz4KPGZlQmxlbmQgbW9kZT0ibXVsdGlwbHkiIGluMj0iQmFja2dyb3VuZEltYWdlRml4IiByZXN1bHQ9ImVmZmVjdDFfZHJvcFNoYWRvd18zXzE1MSIvPgo8ZmVCbGVuZCBtb2RlPSJub3JtYWwiIGluPSJTb3VyY2VHcmFwaGljIiBpbjI9ImVmZmVjdDFfZHJvcFNoYWRvd18zXzE1MSIgcmVzdWx0PSJzaGFwZSIvPgo8L2ZpbHRlcj4KPGxpbmVhckdyYWRpZW50IGlkPSJwYWludDBfbGluZWFyXzNfMTUxIiB4MT0iMTc2LjQxMyIgeTE9IjAuMzE3MTM5IiB4Mj0iMTc2LjQxMyIgeTI9IjM1MS43MTEiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agc3RvcC1jb2xvcj0iI0ZGRjI3OSIvPgo8c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNGRkQzMzYiLz4KPC9saW5lYXJHcmFkaWVudD4KPHJhZGlhbEdyYWRpZW50IGlkPSJwYWludDFfcmFkaWFsXzNfMTUxIiBjeD0iMCIgY3k9IjAiIHI9IjEiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiBncmFkaWVudFRyYW5zZm9ybT0idHJhbnNsYXRlKDIxOC4wNDggMjQ5LjM0Nykgcm90YXRlKDEyNC4wMTgpIHNjYWxlKDg5LjI5NTUgMjY0LjgwOSkiPgo8c3RvcCBvZmZzZXQ9IjAuNjQwODUiIHN0b3AtY29sb3I9IiNGRjY2MEEiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjRkZCRTE1Ii8+CjwvcmFkaWFsR3JhZGllbnQ+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQyX2xpbmVhcl8zXzE1MSIgeDE9IjE3Ni40ODIiIHkxPSI0MC4xODQxIiB4Mj0iMTc2LjQ4MiIgeTI9IjMxNy4yNzgiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agb2Zmc2V0PSIwLjMzODU0MiIgc3RvcC1jb2xvcj0iI0ZGOEYzRiIvPgo8c3RvcCBvZmZzZXQ9IjAuNjU2MjUiIHN0b3AtY29sb3I9IiNGRjcwMjAiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjRkYzRDAwIi8+CjwvbGluZWFyR3JhZGllbnQ+CjwvZGVmcz4KPC9zdmc+Cg=="; +// This is a workaround for backwards compatibility with previous versions of burner-connector +// It allows us to either pass in a burnerConfig (new) or directly pass the connector into rainbowkit (old) +class BurnerWallet extends Function implements Wallet { + private _bound: BurnerWallet; + + public id = defaultBurnerId; + public iconUrl = burnerWalletIconBase64; + public iconBackground = "#ffffff"; + public createConnector = rainbowkitBurnerConnector({}); + + constructor(private burnerConfig?: BurnerConnectorConfig) { + super("...args", "return this._bound._call(...args)"); + + this._bound = this.bind(this); + + this._bound.burnerConfig = burnerConfig; + this._bound.id = defaultBurnerId; + this._bound.iconUrl = burnerWalletIconBase64; + this._bound.iconBackground = "#ffffff"; + this._bound.createConnector = rainbowkitBurnerConnector({}); + + return this._bound; + } + + _call() { + return { + id: this.burnerConfig?.id ?? defaultBurnerId, + name: this.burnerConfig?.name ?? defaultBurnerName, + iconUrl: burnerWalletIconBase64, + iconBackground: "#ffffff", + createConnector: rainbowkitBurnerConnector(this.burnerConfig), + }; + } + + override get name() { + return defaultBurnerName; + } +} + /** * Wagmi config for burner wallet */ -export const rainbowkitBurnerWallet = (): Wallet => ({ - id: burnerWalletId, - name: burnerWalletName, - iconUrl: burnerWalletIconBase64, - iconBackground: "#ffffff", - createConnector: rainbowkitBurnerConnector, -}); +export const rainbowkitBurnerWallet = (burnerConfig?: BurnerConnectorConfig) => { + return new BurnerWallet(burnerConfig); +}; From 28aed030800bf1a37f2dbd72b6f41fbcb16b81de Mon Sep 17 00:00:00 2001 From: ByteAtATime Date: Sat, 5 Oct 2024 11:44:50 -0700 Subject: [PATCH 2/2] fix: override types for rainbowkitBurnerWallet --- .../src/wallets/rainbowkit/rainbowkitBurnerWallet.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/burner-connector/src/wallets/rainbowkit/rainbowkitBurnerWallet.ts b/packages/burner-connector/src/wallets/rainbowkit/rainbowkitBurnerWallet.ts index 290eb3a..b02acac 100644 --- a/packages/burner-connector/src/wallets/rainbowkit/rainbowkitBurnerWallet.ts +++ b/packages/burner-connector/src/wallets/rainbowkit/rainbowkitBurnerWallet.ts @@ -45,9 +45,14 @@ class BurnerWallet extends Function implements Wallet { } } +type BurnerWalletConnector = { + (): Wallet; + (burnerConfig?: BurnerConnectorConfig): () => Wallet; +} + /** * Wagmi config for burner wallet */ -export const rainbowkitBurnerWallet = (burnerConfig?: BurnerConnectorConfig) => { - return new BurnerWallet(burnerConfig); +export const rainbowkitBurnerWallet: BurnerWalletConnector = (burnerConfig?: BurnerConnectorConfig) => { + return new BurnerWallet(burnerConfig) as any; // unfortunately, typescript doesn't know that BurnerWallet is callable };