Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: allow for custom ids passed in through a config #23

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion example/app/wagmiConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
[
Expand Down
22 changes: 16 additions & 6 deletions packages/burner-connector/src/burnerConnector/burner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -30,13 +30,23 @@ export class ChainNotConfiguredError extends BaseError {

type Provider = ReturnType<Transport<"custom", Record<any, any>, EIP1193RequestFn<WalletRpcSchema>>>;

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<Provider>((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({
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion packages/burner-connector/src/index.ts
Original file line number Diff line number Diff line change
@@ -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";
15 changes: 7 additions & 8 deletions packages/burner-connector/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -15,26 +14,26 @@ 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)) {
return currentSk;
}
// If no burner is found in localstorage, we will generate a random private key
const newDefaultPrivateKey = generatePrivateKey();
saveBurnerPK(newDefaultPrivateKey);
saveBurnerPK(newDefaultPrivateKey, storageKey);
return newDefaultPrivateKey;
};
Original file line number Diff line number Diff line change
@@ -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<Transport<"custom", Record<any, any>, EIP1193RequestFn<WalletRpcSchema>>>;

export const rainbowkitBurnerConnector = (walletDetails: WalletDetailsParams) => {
export const rainbowkitBurnerConnector = (burnerConfig: BurnerConnectorConfig = {}) => (walletDetails: WalletDetailsParams) => {
return createConnector<Provider>((config) => ({
...burner()(config),
...burner(burnerConfig)(config),
...walletDetails,
}));
};
Original file line number Diff line number Diff line change
@@ -1,17 +1,58 @@
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;
}
}

type BurnerWalletConnector = {
(): Wallet;
(burnerConfig?: BurnerConnectorConfig): () => Wallet;
}

/**
* Wagmi config for burner wallet
*/
export const rainbowkitBurnerWallet = (): Wallet => ({
id: burnerWalletId,
name: burnerWalletName,
iconUrl: burnerWalletIconBase64,
iconBackground: "#ffffff",
createConnector: rainbowkitBurnerConnector,
});
export const rainbowkitBurnerWallet: BurnerWalletConnector = (burnerConfig?: BurnerConnectorConfig) => {
return new BurnerWallet(burnerConfig) as any; // unfortunately, typescript doesn't know that BurnerWallet is callable
};