applesauce-wallet 0.0.0-next-20250309231023 → 0.0.0-next-20250310121307
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/helpers/history.d.ts +18 -0
- package/dist/helpers/history.js +31 -0
- package/dist/helpers/index.d.ts +2 -0
- package/dist/helpers/index.js +2 -0
- package/dist/helpers/tokens.d.ts +23 -0
- package/dist/helpers/tokens.js +29 -0
- package/dist/queries/history.d.ts +3 -0
- package/dist/queries/history.js +11 -0
- package/dist/queries/index.d.ts +2 -0
- package/dist/queries/index.js +2 -0
- package/dist/queries/tokens.d.ts +6 -0
- package/dist/queries/tokens.js +50 -0
- package/package.json +2 -2
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { HiddenContentSigner } from "applesauce-core/helpers";
|
|
2
|
+
import { NostrEvent } from "nostr-tools";
|
|
3
|
+
export declare const WALLET_HISTORY_KIND = 7376;
|
|
4
|
+
export type HistoryDetails = {
|
|
5
|
+
/** The direction of the transaction, in = received, out = sent */
|
|
6
|
+
direction: "in" | "out";
|
|
7
|
+
/** The amount of the transaction */
|
|
8
|
+
amount: number;
|
|
9
|
+
/** An array of token event ids created */
|
|
10
|
+
created: string[];
|
|
11
|
+
};
|
|
12
|
+
export declare const HistoryDetailsSymbol: unique symbol;
|
|
13
|
+
/** returns an array of redeemed event ids in a history event */
|
|
14
|
+
export declare function getHistoryRedeemed(history: NostrEvent): string[];
|
|
15
|
+
/** Returns the parsed details of a 7376 history event */
|
|
16
|
+
export declare function getHistoryDetails(history: NostrEvent): HistoryDetails;
|
|
17
|
+
/** Decrypts a wallet history event */
|
|
18
|
+
export declare function unlockHistoryDetails(history: NostrEvent, signer: HiddenContentSigner): Promise<HistoryDetails>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { getHiddenTags, getOrComputeCachedValue, isETag, unlockHiddenTags, } from "applesauce-core/helpers";
|
|
2
|
+
export const WALLET_HISTORY_KIND = 7376;
|
|
3
|
+
export const HistoryDetailsSymbol = Symbol.for("history-details");
|
|
4
|
+
/** returns an array of redeemed event ids in a history event */
|
|
5
|
+
export function getHistoryRedeemed(history) {
|
|
6
|
+
return history.tags.filter((t) => isETag(t) && t[3] === "redeemed").map((t) => t[1]);
|
|
7
|
+
}
|
|
8
|
+
/** Returns the parsed details of a 7376 history event */
|
|
9
|
+
export function getHistoryDetails(history) {
|
|
10
|
+
return getOrComputeCachedValue(history, HistoryDetailsSymbol, () => {
|
|
11
|
+
const tags = getHiddenTags(history);
|
|
12
|
+
if (!tags)
|
|
13
|
+
throw new Error("History event is locked");
|
|
14
|
+
const direction = tags.find((t) => t[0] === "direction")?.[1];
|
|
15
|
+
if (!direction)
|
|
16
|
+
throw new Error("History event missing direction");
|
|
17
|
+
const amountStr = tags.find((t) => t[0] === "amount")?.[1];
|
|
18
|
+
if (!amountStr)
|
|
19
|
+
throw new Error("History event missing amount");
|
|
20
|
+
const amount = parseInt(amountStr);
|
|
21
|
+
if (!Number.isFinite(amount))
|
|
22
|
+
throw new Error("Failed to parse amount");
|
|
23
|
+
const created = tags.filter((t) => isETag(t) && t[3] === "created").map((t) => t[1]);
|
|
24
|
+
return { direction, amount, created };
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/** Decrypts a wallet history event */
|
|
28
|
+
export async function unlockHistoryDetails(history, signer) {
|
|
29
|
+
await unlockHiddenTags(history, signer);
|
|
30
|
+
return getHistoryDetails(history);
|
|
31
|
+
}
|
package/dist/helpers/index.d.ts
CHANGED
package/dist/helpers/index.js
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { HiddenContentSigner } from "applesauce-core/helpers";
|
|
2
|
+
import { NostrEvent } from "nostr-tools";
|
|
3
|
+
export declare const WALLET_TOKEN_KIND = 7375;
|
|
4
|
+
export type TokenDetails = {
|
|
5
|
+
/** Cashu mint for the proofs */
|
|
6
|
+
mint: string;
|
|
7
|
+
/** Cashu proofs */
|
|
8
|
+
proofs: {
|
|
9
|
+
amount: number;
|
|
10
|
+
secret: string;
|
|
11
|
+
C: string;
|
|
12
|
+
id: string;
|
|
13
|
+
}[];
|
|
14
|
+
/** tokens that were destroyed in the creation of this token (helps on wallet state transitions) */
|
|
15
|
+
del: string[];
|
|
16
|
+
};
|
|
17
|
+
export declare const TokenDetailsSymbol: unique symbol;
|
|
18
|
+
/** Returns the decrypted and parsed details of a 7375 token event */
|
|
19
|
+
export declare function getTokenDetails(token: NostrEvent): TokenDetails;
|
|
20
|
+
/** Returns if token details are locked */
|
|
21
|
+
export declare function isTokenDetailsLocked(token: NostrEvent): boolean;
|
|
22
|
+
/** Decrypts a k:7375 token event */
|
|
23
|
+
export declare function unlockTokenDetails(token: NostrEvent, signer: HiddenContentSigner): Promise<TokenDetails>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getHiddenContent, getOrComputeCachedValue, isHiddenContentLocked, unlockHiddenContent, } from "applesauce-core/helpers";
|
|
2
|
+
export const WALLET_TOKEN_KIND = 7375;
|
|
3
|
+
export const TokenDetailsSymbol = Symbol.for("token-details");
|
|
4
|
+
/** Returns the decrypted and parsed details of a 7375 token event */
|
|
5
|
+
export function getTokenDetails(token) {
|
|
6
|
+
return getOrComputeCachedValue(token, TokenDetailsSymbol, () => {
|
|
7
|
+
const plaintext = getHiddenContent(token);
|
|
8
|
+
if (!plaintext)
|
|
9
|
+
throw new Error("Token is locked");
|
|
10
|
+
const details = JSON.parse(plaintext);
|
|
11
|
+
if (!details.mint)
|
|
12
|
+
throw new Error("Token missing mint");
|
|
13
|
+
if (!details.proofs)
|
|
14
|
+
details.proofs = [];
|
|
15
|
+
if (!details.del)
|
|
16
|
+
details.del = [];
|
|
17
|
+
return details;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/** Returns if token details are locked */
|
|
21
|
+
export function isTokenDetailsLocked(token) {
|
|
22
|
+
return isHiddenContentLocked(token);
|
|
23
|
+
}
|
|
24
|
+
/** Decrypts a k:7375 token event */
|
|
25
|
+
export async function unlockTokenDetails(token, signer) {
|
|
26
|
+
if (isHiddenContentLocked(token))
|
|
27
|
+
await unlockHiddenContent(token, signer);
|
|
28
|
+
return getTokenDetails(token);
|
|
29
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { getHistoryRedeemed, WALLET_HISTORY_KIND } from "../helpers/history.js";
|
|
2
|
+
import { scan } from "rxjs";
|
|
3
|
+
/** Query that returns an array of redeemed event ids for a wallet */
|
|
4
|
+
export function WalletRedeemedQuery(pubkey) {
|
|
5
|
+
return {
|
|
6
|
+
key: pubkey,
|
|
7
|
+
run: (events) => events
|
|
8
|
+
.filters({ kinds: [WALLET_HISTORY_KIND], authors: [pubkey] })
|
|
9
|
+
.pipe(scan((ids, history) => [...ids, ...getHistoryRedeemed(history)], [])),
|
|
10
|
+
};
|
|
11
|
+
}
|
package/dist/queries/index.d.ts
CHANGED
package/dist/queries/index.js
CHANGED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Query } from "applesauce-core";
|
|
2
|
+
import { NostrEvent } from "nostr-tools";
|
|
3
|
+
/** A query that subscribes to all token events for a wallet, passing locked will filter by token locked status */
|
|
4
|
+
export declare function WalletTokensQuery(pubkey: string, locked: boolean | undefined): Query<NostrEvent[]>;
|
|
5
|
+
/** A query that returns the visible balance of a wallet for each mint */
|
|
6
|
+
export declare function WalletBalanceQuery(pubkey: string): Query<Record<string, number>>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { combineLatest, filter, map } from "rxjs";
|
|
2
|
+
import { getTokenDetails, isTokenDetailsLocked, WALLET_TOKEN_KIND } from "../helpers/tokens.js";
|
|
3
|
+
/** A query that subscribes to all token events for a wallet, passing locked will filter by token locked status */
|
|
4
|
+
export function WalletTokensQuery(pubkey, locked) {
|
|
5
|
+
return {
|
|
6
|
+
key: pubkey + locked,
|
|
7
|
+
run: (events) => {
|
|
8
|
+
const updates = events.updates.pipe(filter((e) => e.kind === WALLET_TOKEN_KIND && e.pubkey === pubkey));
|
|
9
|
+
const timeline = events.timeline({ kinds: [WALLET_TOKEN_KIND], authors: [pubkey] });
|
|
10
|
+
return combineLatest([updates, timeline]).pipe(map(([_, tokens]) => {
|
|
11
|
+
if (locked !== undefined)
|
|
12
|
+
return tokens.filter((t) => isTokenDetailsLocked(t) === locked);
|
|
13
|
+
else
|
|
14
|
+
return tokens;
|
|
15
|
+
}));
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/** A query that returns the visible balance of a wallet for each mint */
|
|
20
|
+
export function WalletBalanceQuery(pubkey) {
|
|
21
|
+
return {
|
|
22
|
+
key: pubkey,
|
|
23
|
+
run: (events) => {
|
|
24
|
+
const updates = events.updates.pipe(filter((e) => e.kind === WALLET_TOKEN_KIND && e.pubkey === pubkey));
|
|
25
|
+
const timeline = events.timeline({ kinds: [WALLET_TOKEN_KIND], authors: [pubkey] });
|
|
26
|
+
return combineLatest([updates, timeline]).pipe(map(([_, tokens]) => {
|
|
27
|
+
const deleted = new Set();
|
|
28
|
+
return (tokens
|
|
29
|
+
// count the tokens from newest to oldest (so del gets applied correctly)
|
|
30
|
+
.reverse()
|
|
31
|
+
.reduce((totals, token) => {
|
|
32
|
+
// skip this event if it a newer event says its deleted
|
|
33
|
+
if (deleted.has(token.id))
|
|
34
|
+
return totals;
|
|
35
|
+
// skip if token is locked
|
|
36
|
+
if (isTokenDetailsLocked(token))
|
|
37
|
+
return totals;
|
|
38
|
+
const details = getTokenDetails(token);
|
|
39
|
+
if (!details)
|
|
40
|
+
return totals;
|
|
41
|
+
// add deleted ids
|
|
42
|
+
for (const id of details.del)
|
|
43
|
+
deleted.add(id);
|
|
44
|
+
const total = details.proofs.reduce((t, p) => t + p.amount, 0);
|
|
45
|
+
return { ...totals, [details.mint]: (totals[details.mint] ?? 0) + total };
|
|
46
|
+
}, {}));
|
|
47
|
+
}));
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "applesauce-wallet",
|
|
3
|
-
"version": "0.0.0-next-
|
|
3
|
+
"version": "0.0.0-next-20250310121307",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"applesauce-core": "0.0.0-next-
|
|
45
|
+
"applesauce-core": "0.0.0-next-20250310121307",
|
|
46
46
|
"nostr-tools": "^2.10.4",
|
|
47
47
|
"rxjs": "^7.8.1"
|
|
48
48
|
},
|