@nostr-dev-kit/ndk-wallet
Version:
98 lines (84 loc) • 3.18 kB
text/typescript
import type { Proof } from "@cashu/cashu-ts";
import type { NDKCashuToken, NDKEventId } from "@nostr-dev-kit/ndk";
import type { WalletState } from ".";
/**
* Adds or updates the token in the wallet state, optionally associating proofs with the token
*/
export function addToken(this: WalletState, token: NDKCashuToken) {
if (!token.mint) throw new Error("BUG: Token has no mint");
const currentEntry = this.tokens.get(token.id);
const state = currentEntry?.state ?? "available";
this.tokens.set(token.id, { token, state });
// go through the proofs this token is claiming
let _added = 0;
let _invalid = 0;
for (const proof of token.proofs) {
const val = maybeAssociateProofWithToken(this, proof, token, state);
if (val === false) {
_invalid++;
} else {
_added++;
}
}
}
function maybeAssociateProofWithToken(
walletState: WalletState,
proof: Proof,
token: NDKCashuToken,
state: "available" | "reserved" | "deleted",
): boolean | null {
const proofC = proof.C;
const proofEntry = walletState.proofs.get(proofC);
if (!proofEntry) {
walletState.addProof({
mint: token.mint!,
state,
tokenId: token.id,
timestamp: token.created_at!,
proof: proof,
});
return true;
}
// already associated
if (proofEntry.tokenId) {
if (proofEntry.tokenId === token.id) {
// already associated with this token, nothing to do
return null;
}
// different token id, ensure the incoming token is newer
const existingTokenEntry = walletState.tokens.get(proofEntry.tokenId);
if (!existingTokenEntry) {
throw new Error(
`BUG: Token id ${proofEntry.tokenId} not found, was expected to be associated with proof ${proofC}`,
);
}
const existingToken = existingTokenEntry.token;
if (existingToken) {
// existing token didnt have a timestamp or the incoming token is newer
if (existingToken.created_at && (!token.created_at || token.created_at < existingToken.created_at)) {
// either the incoming token is older or it doesnt have a timestamp
return false;
}
}
// update the proof entry
walletState.updateProof(proof, { tokenId: token.id, state });
return true;
}
// not associated with any token
walletState.updateProof(proof, { tokenId: token.id, state });
return true;
}
export function removeTokenId(this: WalletState, tokenId: NDKEventId) {
const currentEntry = this.tokens.get(tokenId) || {};
this.tokens.set(tokenId, { ...currentEntry, state: "deleted" });
// remove all proofs associated with this token
for (const proofEntry of this.proofs.values()) {
const { proof } = proofEntry;
if (proofEntry.tokenId === tokenId) {
if (!proof) {
throw new Error("BUG: Proof entry has no proof");
}
this.updateProof(proof, { state: "deleted" });
}
}
}