Skip to content

Commit 13d3277

Browse files
authored
Fix bad computation wallet state (#301)
* Fix bad computation wallet state * remove unnused vars
1 parent b28da57 commit 13d3277

File tree

5 files changed

+58
-19
lines changed

5 files changed

+58
-19
lines changed

ndk-wallet/src/wallets/cashu/event-handlers/token.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,13 @@ export async function handleToken(this: NDKCashuWallet, event: NDKEvent) {
66
if (this.state.tokens.has(event.id)) return;
77

88
const token = await NDKCashuToken.from(event);
9-
if (!token) return;
9+
if (!token) {
10+
return;
11+
}
12+
13+
for (const deletedTokenId of token.deletedTokens) {
14+
this.state.removeTokenId(deletedTokenId);
15+
}
1016

1117
this.state.addToken(token);
12-
}
18+
}

ndk-wallet/src/wallets/cashu/token.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { type Proof } from "@cashu/cashu-ts";
2-
import type { NDKRelay, NDKRelaySet, NostrEvent } from "@nostr-dev-kit/ndk";
2+
import type { NDKEventId, NDKRelay, NDKRelaySet, NostrEvent } from "@nostr-dev-kit/ndk";
33
import type NDK from "@nostr-dev-kit/ndk";
44
import { NDKEvent, NDKKind, normalizeUrl } from "@nostr-dev-kit/ndk";
55
import type { NDKCashuWallet } from "./wallet/index.js";
@@ -24,6 +24,12 @@ export function proofsTotalBalance(proofs: Proof[]): number {
2424
export class NDKCashuToken extends NDKEvent {
2525
private _proofs: Proof[] = [];
2626
private _mint: string | undefined;
27+
28+
/**
29+
* Tokens that this token superseeds
30+
*/
31+
private _deletes: NDKEventId[] = [];
32+
2733
private original: NDKEvent | undefined;
2834

2935
constructor(ndk?: NDK, event?: NostrEvent | NDKEvent) {
@@ -45,6 +51,7 @@ export class NDKCashuToken extends NDKEvent {
4551
const content = JSON.parse(token.content);
4652
token.proofs = content.proofs;
4753
token.mint = content.mint ?? token.tagValue("mint");
54+
token.deletedTokens = content.del ?? [];
4855
if (!Array.isArray(token.proofs)) return;
4956
} catch (e) {
5057
return;
@@ -88,10 +95,12 @@ export class NDKCashuToken extends NDKEvent {
8895
}
8996

9097
async toNostrEvent(pubkey?: string): Promise<NostrEvent> {
91-
this.content = JSON.stringify({
98+
const payload = {
9299
proofs: this.proofs.map(this.cleanProof),
93100
mint: this.mint,
94-
});
101+
del: this.deletedTokens ?? []
102+
};
103+
this.content = JSON.stringify(payload);
95104

96105
const user = await this.ndk!.signer!.user();
97106
await this.encrypt(user, undefined, "nip44");
@@ -118,6 +127,20 @@ export class NDKCashuToken extends NDKEvent {
118127
return this._mint;
119128
}
120129

130+
/**
131+
* Tokens that were deleted by the creation of this token.
132+
*/
133+
get deletedTokens(): NDKEventId[] {
134+
return this._deletes;
135+
}
136+
137+
/**
138+
* Marks tokens that were deleted by the creation of this token.
139+
*/
140+
set deletedTokens(tokenIds: NDKEventId[]) {
141+
this._deletes = tokenIds;
142+
}
143+
121144
get amount(): number {
122145
return proofsTotalBalance(this.proofs);
123146
}

ndk-wallet/src/wallets/cashu/wallet/index.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -221,15 +221,12 @@ export class NDKCashuWallet extends EventEmitter<NDKWalletEvents & {
221221
// if we have an event add it to the filter
222222
if (this.event) {
223223
filters[0] = { ...filters[0], ...this.event.filter(), since: opts?.since }; // add to CashuToken filter
224-
filters[1] = { ...filters[1], ...this.event.filter(), since: opts?.since }; // add to WalletChange filter
225-
filters[2] = { ...filters[2], ...this.event.filter(), since: opts?.since }; // add to CashuQuote filter
224+
filters[1] = { ...filters[1], ...this.event.filter(), since: opts?.since }; // add to CashuQuote filter
226225
}
227226

228227
opts ??= {};
229228
opts.subId ??= "cashu-wallet-state";
230229

231-
console.log('Wallet filter', JSON.stringify(filters));
232-
233230
this.sub = this.ndk.subscribe(filters, opts, this.relaySet, false);
234231

235232
this.sub.on("event:dup", eventDupHandler.bind(this));
@@ -554,7 +551,8 @@ export class NDKCashuWallet extends EventEmitter<NDKWalletEvents & {
554551
this.event.tags = [["d", this.walletId], ["deleted"]];
555552
if (publish) this.event.publishReplaceable();
556553

557-
return this.event.delete(reason, publish);
554+
const deleteEvent = await this.event.delete(reason, publish);
555+
return deleteEvent;
558556
}
559557

560558

ndk-wallet/src/wallets/cashu/wallet/state/token.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ function maybeAssociateProofWithToken(
4747
timestamp: token.created_at!,
4848
proof: proof,
4949
});
50-
// console.log("\tAdding new proof", proof.C, "with state", state);
5150
return true;
5251
} else {
5352
// already associated
@@ -58,15 +57,18 @@ function maybeAssociateProofWithToken(
5857
}
5958

6059
// different token id, ensure the incoming token is newer
61-
const existingToken = walletState.tokens.get(proofEntry.tokenId) as NDKCashuToken | undefined;
62-
if (!existingToken) {
60+
const existingTokenEntry = walletState.tokens.get(proofEntry.tokenId);
61+
if (!existingTokenEntry) {
6362
throw new Error("BUG: Token id " + proofEntry.tokenId + " not found, was expected to be associated with proof " + proofC);
6463
}
64+
const existingToken = existingTokenEntry.token;
6565

66-
// existing token didnt have a timestamp or the incoming token is newer
67-
if (existingToken.created_at && (!token.created_at || token.created_at < existingToken.created_at)) {
68-
// either the incoming token is older or it doesnt have a timestamp
69-
return false;
66+
if (existingToken) {
67+
// existing token didnt have a timestamp or the incoming token is newer
68+
if (existingToken.created_at && (!token.created_at || token.created_at < existingToken.created_at)) {
69+
// either the incoming token is older or it doesnt have a timestamp
70+
return false;
71+
}
7072
}
7173

7274
// update the proof entry

ndk-wallet/src/wallets/cashu/wallet/state/update.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,11 @@ async function updateExternalState(
9494
// execute the state change
9595
const res: UpdateStateResult = {};
9696
if (newState.saveProofs.length > 0) {
97-
const newToken = await createToken(walletState, stateChange.mint, newState);
97+
const newToken = await createTokenEvent(
98+
walletState,
99+
stateChange.mint,
100+
newState,
101+
);
98102
res.created = newToken;
99103
}
100104

@@ -145,7 +149,10 @@ async function publishWithRetry(
145149
}, retryTimeout);
146150
}
147151

148-
async function createToken(walletState: WalletState, mint: MintUrl, newState: WalletTokenChange) {
152+
/**
153+
* Creates a token event as part of a state transition.
154+
*/
155+
async function createTokenEvent(walletState: WalletState, mint: MintUrl, newState: WalletTokenChange) {
149156
const newToken = new NDKCashuToken(walletState.wallet.ndk);
150157
newToken.mint = mint;
151158
newToken.proofs = newState.saveProofs;
@@ -157,6 +164,9 @@ async function createToken(walletState: WalletState, mint: MintUrl, newState: Wa
157164
// immediately add the token to the wallet before signing it
158165
walletState.addToken(newToken);
159166

167+
// add the deleted tokens to the new token
168+
newToken.deletedTokens = Array.from(newState.deletedTokenIds);
169+
160170
// sign it
161171
await newToken.sign();
162172

0 commit comments

Comments
 (0)