@nostr-dev-kit/ndk-wallet
Version:
83 lines (68 loc) • 2.67 kB
text/typescript
import { CheckStateEnum, type Proof, type ProofState } from "@cashu/cashu-ts";
import createDebug from "debug";
import { walletForMint } from "./mint";
import type { NDKCashuWallet } from "./wallet/index.js";
import type { WalletProofChange } from "./wallet/state/index.js";
const d = createDebug("ndk-wallet:cashu:validate");
/**
* Checks for spent proofs and consolidates all unspent proofs into a single token, destroying all old tokens
*/
export async function consolidateTokens(this: NDKCashuWallet) {
d("checking %d tokens for spent proofs", this.state.tokens.size);
const mints = new Set(
this.state.getMintsProofs({ validStates: new Set(["available", "reserved", "deleted"]) }).keys(),
);
d("found %d mints", mints.size);
mints.forEach((mint) => {
consolidateMintTokens(mint!, this);
});
}
export async function consolidateMintTokens(
mint: string,
wallet: NDKCashuWallet,
allProofs?: Proof[],
onResult?: (walletChange: WalletProofChange) => void,
onFailure?: (error: string) => void,
) {
allProofs ??= wallet.state.getProofs({ mint, includeDeleted: true, onlyAvailable: false });
const _wallet = await walletForMint(mint);
if (!_wallet) {
return;
}
let proofStates: ProofState[] = [];
try {
proofStates = await _wallet.checkProofsStates(allProofs);
} catch (e: any) {
onFailure?.(e.message);
return;
}
const spentProofs: Proof[] = [];
const unspentProofs: Proof[] = [];
const pendingProofs: Proof[] = [];
// index stability is guaranteed by cashu-ts
allProofs.forEach((proof, index) => {
const { state } = proofStates[index];
if (state === CheckStateEnum.SPENT) {
spentProofs.push(proof);
} else if (state === CheckStateEnum.UNSPENT) {
unspentProofs.push(proof);
} else {
pendingProofs.push(proof);
}
});
const walletChange: WalletProofChange = {
mint,
store: unspentProofs,
destroy: spentProofs,
};
onResult?.(walletChange);
const _totalSpentProofs = spentProofs.reduce((acc, proof) => acc + proof.amount, 0);
// if no spent proofs return as a noop
if (walletChange.destroy?.length === 0) return;
// mark pending proofs as unspent and reserve them
walletChange.store?.push(...pendingProofs);
const totalPendingProofs = pendingProofs.reduce((acc, proof) => acc + proof.amount, 0);
wallet.state.reserveProofs(pendingProofs, totalPendingProofs);
// Use wallet state update to handle the changes
return wallet.state.update(walletChange, "Consolidate");
}