burner-connector
Version:
169 lines • 7.45 kB
JavaScript
import { createConnector, normalizeChainId } from "wagmi";
import { http, BaseError, RpcRequestError, SwitchChainError, createWalletClient, custom, fromHex, getAddress, } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { getHttpRpcClient, hexToBigInt, hexToNumber, numberToHex } from "viem/utils";
import { burnerWalletId, burnerWalletName, loadBurnerPK } from "../utils/index.js";
export class ConnectorNotConnectedError extends BaseError {
constructor() {
super("Connector not connected.");
Object.defineProperty(this, "name", {
enumerable: true,
configurable: true,
writable: true,
value: "ConnectorNotConnectedError"
});
}
}
export class ChainNotConfiguredError extends BaseError {
constructor() {
super("Chain not configured.");
Object.defineProperty(this, "name", {
enumerable: true,
configurable: true,
writable: true,
value: "ChainNotConfiguredError"
});
}
}
export const burner = ({ useSessionStorage = false, rpcUrls = {} } = {}) => {
let connected = true;
let connectedChainId;
return createConnector((config) => ({
id: burnerWalletId,
name: burnerWalletName,
type: burnerWalletId,
async connect({ chainId } = {}) {
const provider = await this.getProvider();
const accounts = await provider.request({
method: "eth_accounts",
});
let currentChainId = await this.getChainId();
if (chainId && currentChainId !== chainId && this.switchChain) {
const chain = await this.switchChain({ chainId });
currentChainId = chain.id;
}
connected = true;
return { accounts, chainId: currentChainId };
},
async getProvider({ chainId } = {}) {
const chain = config.chains.find((x) => x.id === chainId) ?? config.chains[0];
// Use custom RPC URL if provided, otherwise fallback to default
const url = rpcUrls[chain.id] || chain.rpcUrls.default.http[0];
if (!url)
throw new Error("No rpc url found for chain");
const burnerAccount = privateKeyToAccount(loadBurnerPK({ useSessionStorage }));
const client = createWalletClient({
chain: chain,
account: burnerAccount,
transport: http(url),
});
const request = async ({ method, params }) => {
if (method === "eth_sendTransaction") {
const actualParams = params[0];
const hash = await client.sendTransaction({
account: burnerAccount,
data: actualParams?.data,
to: actualParams?.to,
value: actualParams?.value ? hexToBigInt(actualParams.value) : undefined,
gas: actualParams?.gas ? hexToBigInt(actualParams.gas) : undefined,
nonce: actualParams?.nonce ? hexToNumber(actualParams.nonce) : undefined,
maxPriorityFeePerGas: actualParams?.maxPriorityFeePerGas
? hexToBigInt(actualParams.maxPriorityFeePerGas)
: undefined,
maxFeePerGas: actualParams?.maxFeePerGas
? hexToBigInt(actualParams.maxFeePerGas)
: undefined,
gasPrice: (actualParams?.gasPrice
? hexToBigInt(actualParams.gasPrice)
: undefined),
});
return hash;
}
if (method === "personal_sign") {
// first param is Hex data representation of message,
// second param is address of the signer
const rawMessage = params[0];
const signature = await client.signMessage({
account: burnerAccount,
message: { raw: rawMessage },
});
return signature;
}
if (method === "eth_signTypedData_v4") {
// first param is address of the signer
// second param is stringified typed data
const stringifiedData = params[1];
const signature = await client.signTypedData(JSON.parse(stringifiedData));
return signature;
}
if (method === "eth_accounts") {
return [burnerAccount.address];
}
if (method === "wallet_switchEthereumChain") {
connectedChainId = fromHex(params[0].chainId, "number");
this.onChainChanged(connectedChainId.toString());
return;
}
const body = { method, params };
const httpClient = getHttpRpcClient(url);
const { error, result } = await httpClient.request({ body });
if (error)
throw new RpcRequestError({ body, error, url });
return result;
};
return custom({ request })({ retryCount: 0 });
},
onChainChanged(chain) {
const chainId = normalizeChainId(chain);
config.emitter.emit("change", { chainId });
},
async getAccounts() {
if (!connected)
throw new ConnectorNotConnectedError();
const provider = await this.getProvider();
const accounts = await provider.request({ method: "eth_accounts" });
const burnerAddress = accounts.map((x) => getAddress(x))[0];
return [burnerAddress];
},
async onDisconnect() {
config.emitter.emit("disconnect");
connected = false;
},
async getChainId() {
const provider = await this.getProvider();
const hexChainId = await provider.request({ method: "eth_chainId" });
return fromHex(hexChainId, "number");
},
async isAuthorized() {
if (!connected)
return false;
const accounts = await this.getAccounts();
return !!accounts.length;
},
onAccountsChanged(accounts) {
if (accounts.length === 0)
this.onDisconnect();
else
config.emitter.emit("change", {
accounts: accounts.map((x) => getAddress(x)),
});
},
async switchChain({ chainId }) {
const provider = await this.getProvider();
const chain = config.chains.find((x) => x.id === chainId);
if (!chain)
throw new SwitchChainError(new ChainNotConfiguredError());
await provider.request({
method: "wallet_switchEthereumChain",
params: [{ chainId: numberToHex(chainId) }],
});
return chain;
},
disconnect() {
console.log("disconnect from burnerwallet");
connected = false;
return Promise.resolve();
},
}));
};
//# sourceMappingURL=burner.js.map