UNPKG

@nostr-dev-kit/ndk-wallet

Version:
125 lines (97 loc) 3.73 kB
import type NDK from "@nostr-dev-kit/ndk"; import { NDKCashuMintList, type NDKEvent, NDKKind, type NDKPrivateKeySigner } from "@nostr-dev-kit/ndk"; import { NDKCashuWallet } from "."; /** * This function checks if the user had legacy cashu wallets, if they do, it migrates them to the new format. */ export async function migrateCashuWallet(ndk: NDK) { let mintList = await getMintList(ndk); const oldWallets = await getOldWallets(ndk); if (oldWallets.length === 0) return; const privKeys = new Map<string, NDKPrivateKeySigner>(); const mints = new Set<string>(); const newWallet = new NDKCashuWallet(ndk); for (const wallet of oldWallets) { const { privkey, mints: walletMints } = await extractInfoFromLegacyWallet(wallet); if (privkey) { // get the privkey of the wallet newWallet.addPrivkey(privkey); } // add the mints from the wallet for (const mint of walletMints) mints.add(mint); } cleanupMints(mints); if (mintList) { cleanupMintList(mintList); for (const mint of mintList.mints) mints.add(mint); // Sync the mint list mintList.mints = Array.from(mints); // If the mint list didn't have a p2pk, set it to the first pubkey if (!mintList.p2pk && privKeys.size > 0) mintList.p2pk = Array.from(privKeys.keys())[0]; await mintList.toNostrEvent(); } else { mintList = new NDKCashuMintList(ndk); mintList.mints = Array.from(mints); await mintList.toNostrEvent(); } newWallet.mints = Array.from(mints); // publish the new wallet await newWallet.publish(); mintList.p2pk = await newWallet.getP2pk(); // publish the mint list await mintList.publishReplaceable(); // delete the old wallets for (const wallet of oldWallets) { wallet.tags = [["d", wallet.dTag ?? ""], ["deleted"]]; await wallet.publishReplaceable(); } } async function getMintList(ndk: NDK) { const activeUser = ndk.activeUser; if (!activeUser) throw new Error("No active user"); const mintList = await ndk.fetchEvent({ kinds: [NDKKind.CashuMintList], authors: [activeUser.pubkey], }); if (!mintList) return; return NDKCashuMintList.from(mintList); } /** * Get non-deleted legacy cashu wallets */ async function getOldWallets(ndk: NDK) { const user = ndk.activeUser; if (!user) throw new Error("No active user"); const walletEvents = await ndk.fetchEvents([{ kinds: [NDKKind.LegacyCashuWallet], authors: [user.pubkey] }]); return Array.from(walletEvents).filter((event) => !event.hasTag("deleted")); } /** * Extract info from legacy wallet */ async function extractInfoFromLegacyWallet(wallet: NDKEvent) { const mints: string[] = []; let privkey: string | undefined; try { // decrypt the wallet content, extract the privkey const origContent = wallet.content; await wallet.decrypt(); const privTags = JSON.parse(wallet.content); for (const tag of privTags) { if (tag[0] === "privkey") privkey = tag[1]; if (tag[0] === "mint") mints.push(tag[1]); } wallet.content = origContent; return { privkey, mints }; } catch (error) { console.error("Error decrypting legacy wallet", error); } return { privkey, mints }; } function cleanupMints(mints: Set<string>) { // remove testnut mints for (const mint of mints) if (mint.match(/testnut/)) mints.delete(mint); return mints; } function cleanupMintList(mintList: NDKCashuMintList) { mintList.mints = mintList.mints.filter((mint) => !mint.match(/testnut/)); }