UNPKG

xchange-create

Version:
163 lines (140 loc) 4.44 kB
import { useCallback, useEffect, useRef, useState } from "react" import { useTargetNetwork } from "./useTargetNetwork" import { useLocalStorage } from "usehooks-ts" import { Chain, createWalletClient, Hex, http, HttpTransport, PrivateKeyAccount, WalletClient, } from "viem" import { generatePrivateKey, privateKeyToAccount } from "viem/accounts" import { usePublicClient } from "wagmi" const burnerStorageKey = "xchangeCreate.burnerWallet.sk" /** * Checks if the private key is valid */ const isValidSk = (pk: Hex | string | undefined | null): boolean => { return pk?.length === 64 || pk?.length === 66 } /** * If no burner is found in localstorage, we will generate a random private key */ const newDefaultPrivateKey = generatePrivateKey() /** * Save the current burner private key to local storage */ export const saveBurnerSK = (privateKey: Hex): void => { if (typeof window != "undefined" && window != null) { window?.localStorage?.setItem(burnerStorageKey, privateKey) } } /** * Gets the current burner private key from local storage */ export const loadBurnerSK = (): Hex => { let currentSk: Hex = "0x" if (typeof window != "undefined" && window != null) { currentSk = (window?.localStorage ?.getItem?.(burnerStorageKey) ?.replaceAll('"', "") ?? "0x") as Hex } if (!!currentSk && isValidSk(currentSk)) { return currentSk } else { saveBurnerSK(newDefaultPrivateKey) return newDefaultPrivateKey } } type BurnerAccount = { walletClient: WalletClient | undefined account: PrivateKeyAccount | undefined // creates a new burner account generateNewBurner: () => void // explicitly save burner to storage saveBurner: () => void } /** * Creates a burner wallet */ export const useBurnerWallet = (): BurnerAccount => { const [burnerSk, setBurnerSk] = useLocalStorage<Hex>( burnerStorageKey, newDefaultPrivateKey, { initializeWithValue: false, } ) const { targetNetwork } = useTargetNetwork() const publicClient = usePublicClient({ chainId: targetNetwork.id }) const [walletClient, setWalletClient] = useState<WalletClient<HttpTransport, Chain, PrivateKeyAccount>>() const [generatedPrivateKey, setGeneratedPrivateKey] = useState<Hex>("0x") const [account, setAccount] = useState<PrivateKeyAccount>() const isCreatingNewBurnerRef = useRef(false) const saveBurner = useCallback(() => { setBurnerSk(generatedPrivateKey) }, [setBurnerSk, generatedPrivateKey]) const generateNewBurner = useCallback(() => { if (publicClient && !isCreatingNewBurnerRef.current) { console.log("🔑 Create new burner wallet...") isCreatingNewBurnerRef.current = true const randomPrivateKey = generatePrivateKey() const randomAccount = privateKeyToAccount(randomPrivateKey) const client = createWalletClient({ chain: publicClient.chain, account: randomAccount, transport: http(), }) setWalletClient(client) setGeneratedPrivateKey(randomPrivateKey) setAccount(randomAccount) setBurnerSk(() => { console.log("🔥 Saving new burner wallet") isCreatingNewBurnerRef.current = false return randomPrivateKey }) return client } else { console.log("⚠ Could not create burner wallet") } // eslint-disable-next-line react-hooks/exhaustive-deps }, [publicClient?.chain.id]) /** * Load wallet with burnerSk * connect and set wallet, once we have burnerSk and valid provider */ useEffect(() => { if (burnerSk && publicClient?.chain.id) { let wallet: | WalletClient<HttpTransport, Chain, PrivateKeyAccount> | undefined = undefined if (isValidSk(burnerSk)) { const randomAccount = privateKeyToAccount(burnerSk) wallet = createWalletClient({ chain: publicClient.chain, account: randomAccount, transport: http(), }) setGeneratedPrivateKey(burnerSk) setAccount(randomAccount) } else { wallet = generateNewBurner() } if (wallet == null) { throw "Error: Could not create burner wallet" } setWalletClient(wallet) saveBurner() } // eslint-disable-next-line react-hooks/exhaustive-deps }, [burnerSk, publicClient?.chain.id]) return { walletClient, account, generateNewBurner, saveBurner, } }