applesauce-wallet 0.0.0-next-20250522030625 → 0.0.0-next-20250606170247
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/README.md +1 -1
- package/dist/__tests__/exports.test.js +1 -1
- package/dist/actions/tokens.js +1 -1
- package/dist/blueprints/history.d.ts +1 -2
- package/dist/blueprints/history.js +2 -2
- package/dist/blueprints/tokens.d.ts +1 -2
- package/dist/blueprints/tokens.js +2 -2
- package/dist/blueprints/wallet.d.ts +2 -3
- package/dist/blueprints/wallet.js +3 -3
- package/dist/helpers/__tests__/tokens.test.js +2 -2
- package/dist/helpers/history.js +3 -1
- package/dist/helpers/tokens.d.ts +1 -1
- package/dist/helpers/tokens.js +4 -2
- package/dist/helpers/wallet.js +4 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/models/__tests__/exports.test.d.ts +1 -0
- package/dist/models/__tests__/exports.test.js +15 -0
- package/dist/models/__tests__/wallet.test.d.ts +1 -0
- package/dist/models/__tests__/wallet.test.js +28 -0
- package/dist/models/history.d.ts +6 -0
- package/dist/models/history.js +21 -0
- package/dist/models/index.d.ts +3 -0
- package/dist/models/index.js +3 -0
- package/dist/models/tokens.d.ts +6 -0
- package/dist/models/tokens.js +58 -0
- package/dist/models/wallet.d.ts +13 -0
- package/dist/models/wallet.js +18 -0
- package/package.json +13 -13
package/README.md
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
# Applesauce Wallet
|
|
2
2
|
|
|
3
|
-
The `applesauce-wallet` package is a package of helpers,
|
|
3
|
+
The `applesauce-wallet` package is a package of helpers, models, blueprints and other useful stuff for [NIP-60](https://github.com/nostr-protocol/nips/blob/master/60.md) wallets and [NIP-61](https://github.com/nostr-protocol/nips/blob/master/61.md) nutzaps
|
package/dist/actions/tokens.js
CHANGED
|
@@ -66,7 +66,7 @@ export function CompleteSpend(spent, change) {
|
|
|
66
66
|
/** Combines all unlocked token events into a single event per mint */
|
|
67
67
|
export function ConsolidateTokens(opts) {
|
|
68
68
|
return async function* ({ events, factory, self }) {
|
|
69
|
-
const tokens = Array.from(events.
|
|
69
|
+
const tokens = Array.from(events.getByFilters({ kinds: [WALLET_TOKEN_KIND], authors: [self] })).filter((token) => {
|
|
70
70
|
if (isTokenContentLocked(token)) {
|
|
71
71
|
if (opts?.ignoreLocked)
|
|
72
72
|
return false;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { EventPointer } from "nostr-tools/nip19";
|
|
2
2
|
import { HistoryContent } from "../helpers/history.js";
|
|
3
|
-
import { EventBlueprint } from "applesauce-factory";
|
|
4
3
|
/** A blueprint that creates a wallet history event */
|
|
5
|
-
export declare function WalletHistoryBlueprint(content: HistoryContent, redeemed: (string | EventPointer)[]): EventBlueprint;
|
|
4
|
+
export declare function WalletHistoryBlueprint(content: HistoryContent, redeemed: (string | EventPointer)[]): import("applesauce-factory").EventBlueprint;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { blueprint } from "applesauce-factory";
|
|
1
2
|
import { WALLET_HISTORY_KIND } from "../helpers/history.js";
|
|
2
|
-
import { EventFactory } from "applesauce-factory";
|
|
3
3
|
import { setHistoryContent, setHistoryRedeemed } from "../operations/event/history.js";
|
|
4
4
|
/** A blueprint that creates a wallet history event */
|
|
5
5
|
export function WalletHistoryBlueprint(content, redeemed) {
|
|
6
|
-
return (
|
|
6
|
+
return blueprint(WALLET_HISTORY_KIND,
|
|
7
7
|
// set the encrypted tags on the event
|
|
8
8
|
setHistoryContent(content),
|
|
9
9
|
// set the public redeemed tags
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Token } from "@cashu/cashu-ts";
|
|
2
|
-
import { EventBlueprint } from "applesauce-factory";
|
|
3
2
|
/**
|
|
4
3
|
* A blueprint for a wallet token event, takes a cashu token and previous deleted token event ids
|
|
5
4
|
* @param token the cashu token to store
|
|
6
5
|
* @param [del=[]] an array of previous token event ids that are deleted
|
|
7
6
|
*/
|
|
8
|
-
export declare function WalletTokenBlueprint(token: Token, del?: string[]): EventBlueprint;
|
|
7
|
+
export declare function WalletTokenBlueprint(token: Token, del?: string[]): import("applesauce-factory").EventBlueprint;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { blueprint } from "applesauce-factory";
|
|
2
2
|
import { WALLET_TOKEN_KIND } from "../helpers/tokens.js";
|
|
3
3
|
import { setTokenContent } from "../operations/event/tokens.js";
|
|
4
4
|
/**
|
|
@@ -7,5 +7,5 @@ import { setTokenContent } from "../operations/event/tokens.js";
|
|
|
7
7
|
* @param [del=[]] an array of previous token event ids that are deleted
|
|
8
8
|
*/
|
|
9
9
|
export function WalletTokenBlueprint(token, del = []) {
|
|
10
|
-
return (
|
|
10
|
+
return blueprint(WALLET_TOKEN_KIND, setTokenContent(token, del));
|
|
11
11
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { EventBlueprint } from "applesauce-factory";
|
|
2
1
|
import { NostrEvent } from "nostr-tools";
|
|
3
2
|
/** A blueprint to create a new 17375 wallet */
|
|
4
|
-
export declare function WalletBlueprint(mints: string[], privateKey?: Uint8Array): EventBlueprint;
|
|
3
|
+
export declare function WalletBlueprint(mints: string[], privateKey?: Uint8Array): import("applesauce-factory").EventBlueprint;
|
|
5
4
|
/** A blueprint that creates a new 375 wallet backup event */
|
|
6
|
-
export declare function WalletBackupBlueprint(wallet: NostrEvent): EventBlueprint;
|
|
5
|
+
export declare function WalletBackupBlueprint(wallet: NostrEvent): import("applesauce-factory").EventBlueprint;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { blueprint } from "applesauce-factory";
|
|
2
2
|
import { modifyHiddenTags } from "applesauce-factory/operations/event";
|
|
3
3
|
import { WALLET_BACKUP_KIND, WALLET_KIND } from "../helpers/wallet.js";
|
|
4
4
|
import { setWalletBackupContent } from "../operations/event/wallet.js";
|
|
5
5
|
import { setMintTags, setPrivateKeyTag } from "../operations/tag/wallet.js";
|
|
6
6
|
/** A blueprint to create a new 17375 wallet */
|
|
7
7
|
export function WalletBlueprint(mints, privateKey) {
|
|
8
|
-
return (
|
|
8
|
+
return blueprint(WALLET_KIND, modifyHiddenTags(privateKey ? setPrivateKeyTag(privateKey) : undefined, setMintTags(mints)));
|
|
9
9
|
}
|
|
10
10
|
/** A blueprint that creates a new 375 wallet backup event */
|
|
11
11
|
export function WalletBackupBlueprint(wallet) {
|
|
12
|
-
return (
|
|
12
|
+
return blueprint(WALLET_BACKUP_KIND, setWalletBackupContent(wallet));
|
|
13
13
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { EventFactory } from "applesauce-factory";
|
|
3
|
+
import { EncryptedContentSymbol, unixNow } from "applesauce-core/helpers";
|
|
3
4
|
import { FakeUser } from "../../__tests__/fake-user.js";
|
|
4
5
|
import { WalletTokenBlueprint } from "../../blueprints/tokens.js";
|
|
5
6
|
import { decodeTokenFromEmojiString, dumbTokenSelection, encodeTokenToEmoji, unlockTokenContent } from "../tokens.js";
|
|
6
|
-
import { HiddenContentSymbol, unixNow } from "applesauce-core/helpers";
|
|
7
7
|
const user = new FakeUser();
|
|
8
8
|
const factory = new EventFactory({ signer: user });
|
|
9
9
|
describe("dumbTokenSelection", () => {
|
|
@@ -58,7 +58,7 @@ describe("dumbTokenSelection", () => {
|
|
|
58
58
|
bDraft.created_at -= 60 * 60 * 7;
|
|
59
59
|
const b = await user.signEvent(bDraft);
|
|
60
60
|
// manually remove the hidden content to lock it again
|
|
61
|
-
Reflect.deleteProperty(b,
|
|
61
|
+
Reflect.deleteProperty(b, EncryptedContentSymbol);
|
|
62
62
|
expect(dumbTokenSelection([a, b], 20).events).toEqual([a]);
|
|
63
63
|
});
|
|
64
64
|
it("should ignore duplicate proofs", async () => {
|
package/dist/helpers/history.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { getHiddenTags, getOrComputeCachedValue, isETag, isHiddenContentLocked, isHiddenTagsLocked, lockHiddenTags, unlockHiddenTags, } from "applesauce-core/helpers";
|
|
1
|
+
import { getHiddenTags, getOrComputeCachedValue, isETag, isHiddenContentLocked, isHiddenTagsLocked, lockHiddenTags, setHiddenTagsEncryptionMethod, unlockHiddenTags, } from "applesauce-core/helpers";
|
|
2
2
|
export const WALLET_HISTORY_KIND = 7376;
|
|
3
|
+
// Enable hidden content for wallet history kind
|
|
4
|
+
setHiddenTagsEncryptionMethod(WALLET_HISTORY_KIND, "nip44");
|
|
3
5
|
export const HistoryContentSymbol = Symbol.for("history-content");
|
|
4
6
|
/** returns an array of redeemed event ids in a history event */
|
|
5
7
|
export function getHistoryRedeemed(history) {
|
package/dist/helpers/tokens.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Proof, Token } from "@cashu/cashu-ts";
|
|
2
2
|
import { HiddenContentSigner } from "applesauce-core/helpers";
|
|
3
3
|
import { NostrEvent } from "nostr-tools";
|
|
4
|
+
export declare const WALLET_TOKEN_KIND = 7375;
|
|
4
5
|
/** Internal method for creating a unique id for each proof */
|
|
5
6
|
export declare function getProofUID(proof: Proof): string;
|
|
6
7
|
/** Internal method to filter out duplicate proofs */
|
|
7
8
|
export declare function ignoreDuplicateProofs(seen?: Set<string>): (proof: Proof) => boolean;
|
|
8
|
-
export declare const WALLET_TOKEN_KIND = 7375;
|
|
9
9
|
export type TokenContent = {
|
|
10
10
|
/** Cashu mint for the proofs */
|
|
11
11
|
mint: string;
|
package/dist/helpers/tokens.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { getDecodedToken, getEncodedToken } from "@cashu/cashu-ts";
|
|
2
|
-
import { getHiddenContent, getOrComputeCachedValue, isHiddenContentLocked, isHiddenTagsLocked, lockHiddenContent, unlockHiddenContent, } from "applesauce-core/helpers";
|
|
2
|
+
import { getHiddenContent, getOrComputeCachedValue, isHiddenContentLocked, isHiddenTagsLocked, lockHiddenContent, setHiddenContentEncryptionMethod, unlockHiddenContent, } from "applesauce-core/helpers";
|
|
3
|
+
export const WALLET_TOKEN_KIND = 7375;
|
|
4
|
+
// Enable hidden content for wallet token kind
|
|
5
|
+
setHiddenContentEncryptionMethod(WALLET_TOKEN_KIND, "nip44");
|
|
3
6
|
/** Internal method for creating a unique id for each proof */
|
|
4
7
|
export function getProofUID(proof) {
|
|
5
8
|
return proof.id + proof.amount + proof.C + proof.secret;
|
|
@@ -16,7 +19,6 @@ export function ignoreDuplicateProofs(seen = new Set()) {
|
|
|
16
19
|
}
|
|
17
20
|
};
|
|
18
21
|
}
|
|
19
|
-
export const WALLET_TOKEN_KIND = 7375;
|
|
20
22
|
export const TokenContentSymbol = Symbol.for("token-content");
|
|
21
23
|
/**
|
|
22
24
|
* Returns the decrypted and parsed details of a 7375 token event
|
package/dist/helpers/wallet.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { hexToBytes } from "@noble/hashes/utils";
|
|
2
|
-
import { getHiddenTags, getOrComputeCachedValue, isHiddenTagsLocked, lockHiddenTags, unlockHiddenTags, } from "applesauce-core/helpers";
|
|
2
|
+
import { getHiddenTags, getOrComputeCachedValue, isHiddenTagsLocked, lockHiddenTags, setHiddenTagsEncryptionMethod, unlockHiddenTags, } from "applesauce-core/helpers";
|
|
3
3
|
export const WALLET_KIND = 17375;
|
|
4
4
|
export const WALLET_BACKUP_KIND = 375;
|
|
5
|
+
// Enable hidden content for wallet kinds
|
|
6
|
+
setHiddenTagsEncryptionMethod(WALLET_KIND, "nip44");
|
|
7
|
+
setHiddenTagsEncryptionMethod(WALLET_BACKUP_KIND, "nip44");
|
|
5
8
|
export const WalletPrivateKeySymbol = Symbol.for("wallet-private-key");
|
|
6
9
|
export const WalletMintsSymbol = Symbol.for("wallet-mints");
|
|
7
10
|
/** Returns if a wallet is locked */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export * as Actions from "./actions/index.js";
|
|
2
2
|
export * as Blueprints from "./blueprints/index.js";
|
|
3
3
|
export * as Helpers from "./helpers/index.js";
|
|
4
|
-
export * as
|
|
4
|
+
export * as Models from "./models/index.js";
|
|
5
5
|
export * from "./operations/index.js";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export * as Actions from "./actions/index.js";
|
|
2
2
|
export * as Blueprints from "./blueprints/index.js";
|
|
3
3
|
export * as Helpers from "./helpers/index.js";
|
|
4
|
-
export * as
|
|
4
|
+
export * as Models from "./models/index.js";
|
|
5
5
|
export * from "./operations/index.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import * as exports from "../index.js";
|
|
3
|
+
describe("exports", () => {
|
|
4
|
+
it("should export the expected functions", () => {
|
|
5
|
+
expect(Object.keys(exports).sort()).toMatchInlineSnapshot(`
|
|
6
|
+
[
|
|
7
|
+
"WalletBalanceModel",
|
|
8
|
+
"WalletHistoryModel",
|
|
9
|
+
"WalletModel",
|
|
10
|
+
"WalletRedeemedModel",
|
|
11
|
+
"WalletTokensModel",
|
|
12
|
+
]
|
|
13
|
+
`);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { subscribeSpyTo } from "@hirez_io/observer-spy";
|
|
2
|
+
import { EventStore } from "applesauce-core";
|
|
3
|
+
import { EventFactory } from "applesauce-factory";
|
|
4
|
+
import { generateSecretKey } from "nostr-tools";
|
|
5
|
+
import { beforeEach, describe, expect, it } from "vitest";
|
|
6
|
+
import { FakeUser } from "../../__tests__/fake-user.js";
|
|
7
|
+
import { WalletBlueprint } from "../../blueprints/wallet.js";
|
|
8
|
+
import { lockWallet, unlockWallet } from "../../helpers/wallet.js";
|
|
9
|
+
import { WalletModel } from "../wallet.js";
|
|
10
|
+
const user = new FakeUser();
|
|
11
|
+
const factory = new EventFactory({ signer: user });
|
|
12
|
+
let eventStore;
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
eventStore = new EventStore();
|
|
15
|
+
});
|
|
16
|
+
describe("WalletModel", () => {
|
|
17
|
+
it("it should update when event is unlocked", async () => {
|
|
18
|
+
const wallet = await user.signEvent(await factory.create(WalletBlueprint, [], generateSecretKey()));
|
|
19
|
+
lockWallet(wallet);
|
|
20
|
+
eventStore.add(wallet);
|
|
21
|
+
const spy = subscribeSpyTo(eventStore.model(WalletModel, await user.getPublicKey()));
|
|
22
|
+
await unlockWallet(wallet, user);
|
|
23
|
+
expect(spy.getValues()).toEqual([
|
|
24
|
+
expect.objectContaining({ locked: true }),
|
|
25
|
+
expect.objectContaining({ locked: false }),
|
|
26
|
+
]);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Model } from "applesauce-core";
|
|
2
|
+
import { NostrEvent } from "nostr-tools";
|
|
3
|
+
/** A model that returns an array of redeemed event ids for a wallet */
|
|
4
|
+
export declare function WalletRedeemedModel(pubkey: string): Model<string[]>;
|
|
5
|
+
/** A model that returns a timeline of wallet history events */
|
|
6
|
+
export declare function WalletHistoryModel(pubkey: string, locked?: boolean | undefined): Model<NostrEvent[]>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { combineLatest, filter, map, scan, startWith } from "rxjs";
|
|
2
|
+
import { getHistoryRedeemed, isHistoryContentLocked, WALLET_HISTORY_KIND } from "../helpers/history.js";
|
|
3
|
+
/** A model that returns an array of redeemed event ids for a wallet */
|
|
4
|
+
export function WalletRedeemedModel(pubkey) {
|
|
5
|
+
return (events) => events
|
|
6
|
+
.filters({ kinds: [WALLET_HISTORY_KIND], authors: [pubkey] })
|
|
7
|
+
.pipe(scan((ids, history) => [...ids, ...getHistoryRedeemed(history)], []));
|
|
8
|
+
}
|
|
9
|
+
/** A model that returns a timeline of wallet history events */
|
|
10
|
+
export function WalletHistoryModel(pubkey, locked) {
|
|
11
|
+
return (events) => {
|
|
12
|
+
const updates = events.update$.pipe(filter((e) => e.kind === WALLET_HISTORY_KIND && e.pubkey === pubkey), startWith(undefined));
|
|
13
|
+
const timeline = events.timeline({ kinds: [WALLET_HISTORY_KIND], authors: [pubkey] });
|
|
14
|
+
return combineLatest([updates, timeline]).pipe(map(([_, history]) => {
|
|
15
|
+
if (locked === undefined)
|
|
16
|
+
return history;
|
|
17
|
+
else
|
|
18
|
+
return history.filter((entry) => isHistoryContentLocked(entry) === locked);
|
|
19
|
+
}));
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Model } from "applesauce-core";
|
|
2
|
+
import { NostrEvent } from "nostr-tools";
|
|
3
|
+
/** A model that subscribes to all token events for a wallet, passing locked will filter by token locked status */
|
|
4
|
+
export declare function WalletTokensModel(pubkey: string, locked?: boolean | undefined): Model<NostrEvent[]>;
|
|
5
|
+
/** A model that returns the visible balance of a wallet for each mint */
|
|
6
|
+
export declare function WalletBalanceModel(pubkey: string): Model<Record<string, number>>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { combineLatest, filter, map, startWith } from "rxjs";
|
|
2
|
+
import { getTokenContent, ignoreDuplicateProofs, isTokenContentLocked, WALLET_TOKEN_KIND } from "../helpers/tokens.js";
|
|
3
|
+
/** removes deleted events from sorted array */
|
|
4
|
+
function filterDeleted(tokens) {
|
|
5
|
+
const deleted = new Set();
|
|
6
|
+
return Array.from(tokens)
|
|
7
|
+
.reverse()
|
|
8
|
+
.filter((token) => {
|
|
9
|
+
// skip this event if it a newer event says its deleted
|
|
10
|
+
if (deleted.has(token.id))
|
|
11
|
+
return false;
|
|
12
|
+
// add ids to deleted array
|
|
13
|
+
if (!isTokenContentLocked(token)) {
|
|
14
|
+
const details = getTokenContent(token);
|
|
15
|
+
for (const id of details.del)
|
|
16
|
+
deleted.add(id);
|
|
17
|
+
}
|
|
18
|
+
return true;
|
|
19
|
+
})
|
|
20
|
+
.reverse();
|
|
21
|
+
}
|
|
22
|
+
/** A model that subscribes to all token events for a wallet, passing locked will filter by token locked status */
|
|
23
|
+
export function WalletTokensModel(pubkey, locked) {
|
|
24
|
+
return (events) => {
|
|
25
|
+
const updates = events.update$.pipe(filter((e) => e.kind === WALLET_TOKEN_KIND && e.pubkey === pubkey), startWith(undefined));
|
|
26
|
+
const timeline = events.timeline({ kinds: [WALLET_TOKEN_KIND], authors: [pubkey] });
|
|
27
|
+
return combineLatest([updates, timeline]).pipe(
|
|
28
|
+
// filter out locked tokens
|
|
29
|
+
map(([_, tokens]) => {
|
|
30
|
+
if (locked === undefined)
|
|
31
|
+
return tokens;
|
|
32
|
+
else
|
|
33
|
+
return tokens.filter((t) => isTokenContentLocked(t) === locked);
|
|
34
|
+
}),
|
|
35
|
+
// remove deleted events
|
|
36
|
+
map(filterDeleted));
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/** A model that returns the visible balance of a wallet for each mint */
|
|
40
|
+
export function WalletBalanceModel(pubkey) {
|
|
41
|
+
return (events) => {
|
|
42
|
+
const updates = events.update$.pipe(filter((e) => e.kind === WALLET_TOKEN_KIND && e.pubkey === pubkey), startWith(undefined));
|
|
43
|
+
const timeline = events.timeline({ kinds: [WALLET_TOKEN_KIND], authors: [pubkey] });
|
|
44
|
+
return combineLatest([updates, timeline]).pipe(map(([_, tokens]) => tokens.filter((t) => !isTokenContentLocked(t))),
|
|
45
|
+
// filter out deleted tokens
|
|
46
|
+
map(filterDeleted),
|
|
47
|
+
// map tokens to totals
|
|
48
|
+
map((tokens) => {
|
|
49
|
+
// ignore duplicate proofs
|
|
50
|
+
const seen = new Set();
|
|
51
|
+
return tokens.reduce((totals, token) => {
|
|
52
|
+
const details = getTokenContent(token);
|
|
53
|
+
const total = details.proofs.filter(ignoreDuplicateProofs(seen)).reduce((t, p) => t + p.amount, 0);
|
|
54
|
+
return { ...totals, [details.mint]: (totals[details.mint] ?? 0) + total };
|
|
55
|
+
}, {});
|
|
56
|
+
}));
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Model } from "applesauce-core";
|
|
2
|
+
import { NostrEvent } from "nostr-tools";
|
|
3
|
+
export type WalletInfo = {
|
|
4
|
+
locked: true;
|
|
5
|
+
event: NostrEvent;
|
|
6
|
+
} | {
|
|
7
|
+
locked: false;
|
|
8
|
+
event: NostrEvent;
|
|
9
|
+
privateKey?: Uint8Array;
|
|
10
|
+
mints: string[];
|
|
11
|
+
};
|
|
12
|
+
/** A model to get the state of a NIP-60 wallet */
|
|
13
|
+
export declare function WalletModel(pubkey: string): Model<WalletInfo | undefined>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { filter, map, merge } from "rxjs";
|
|
2
|
+
import { getWalletMints, getWalletPrivateKey, isWalletLocked, WALLET_KIND } from "../helpers/wallet.js";
|
|
3
|
+
/** A model to get the state of a NIP-60 wallet */
|
|
4
|
+
export function WalletModel(pubkey) {
|
|
5
|
+
return (events) => merge(
|
|
6
|
+
// get the latest replaceable event
|
|
7
|
+
events.replaceable(WALLET_KIND, pubkey),
|
|
8
|
+
// and listen for any updates to matching events
|
|
9
|
+
events.update$.pipe(filter((e) => e.kind === WALLET_KIND && e.pubkey === pubkey))).pipe(map((wallet) => {
|
|
10
|
+
if (!wallet)
|
|
11
|
+
return;
|
|
12
|
+
if (isWalletLocked(wallet))
|
|
13
|
+
return { locked: true, event: wallet };
|
|
14
|
+
const mints = getWalletMints(wallet);
|
|
15
|
+
const privateKey = getWalletPrivateKey(wallet);
|
|
16
|
+
return { locked: false, mints, privateKey, event: wallet };
|
|
17
|
+
}));
|
|
18
|
+
}
|
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-20250606170247",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -30,15 +30,15 @@
|
|
|
30
30
|
"require": "./dist/helpers/*.js",
|
|
31
31
|
"types": "./dist/helpers/*.d.ts"
|
|
32
32
|
},
|
|
33
|
-
"./
|
|
34
|
-
"import": "./dist/
|
|
35
|
-
"require": "./dist/
|
|
36
|
-
"types": "./dist/
|
|
33
|
+
"./models": {
|
|
34
|
+
"import": "./dist/models/index.js",
|
|
35
|
+
"require": "./dist/models/index.js",
|
|
36
|
+
"types": "./dist/models/index.d.ts"
|
|
37
37
|
},
|
|
38
|
-
"./
|
|
39
|
-
"import": "./dist/
|
|
40
|
-
"require": "./dist/
|
|
41
|
-
"types": "./dist/
|
|
38
|
+
"./models/*": {
|
|
39
|
+
"import": "./dist/models/*.js",
|
|
40
|
+
"require": "./dist/models/*.js",
|
|
41
|
+
"types": "./dist/models/*.d.ts"
|
|
42
42
|
},
|
|
43
43
|
"./blueprints": {
|
|
44
44
|
"import": "./dist/blueprints/index.js",
|
|
@@ -80,16 +80,16 @@
|
|
|
80
80
|
"@cashu/cashu-ts": "2.0.0-rc1",
|
|
81
81
|
"@gandlaf21/bc-ur": "^1.1.12",
|
|
82
82
|
"@noble/hashes": "^1.7.1",
|
|
83
|
-
"applesauce-actions": "0.0.0-next-
|
|
84
|
-
"applesauce-core": "0.0.0-next-
|
|
85
|
-
"applesauce-factory": "0.0.0-next-
|
|
83
|
+
"applesauce-actions": "0.0.0-next-20250606170247",
|
|
84
|
+
"applesauce-core": "0.0.0-next-20250606170247",
|
|
85
|
+
"applesauce-factory": "0.0.0-next-20250606170247",
|
|
86
86
|
"nostr-tools": "^2.13",
|
|
87
87
|
"rxjs": "^7.8.1"
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|
|
90
90
|
"@hirez_io/observer-spy": "^2.2.0",
|
|
91
91
|
"@types/debug": "^4.1.12",
|
|
92
|
-
"applesauce-signers": "0.0.0-next-
|
|
92
|
+
"applesauce-signers": "0.0.0-next-20250606170247",
|
|
93
93
|
"typescript": "^5.8.3",
|
|
94
94
|
"vitest": "^3.1.1"
|
|
95
95
|
},
|