applesauce-wallet 6.1.0 → 6.2.0
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/actions/nutzaps.d.ts +6 -2
- package/dist/actions/nutzaps.js +29 -12
- package/dist/actions/tokens.d.ts +98 -11
- package/dist/actions/tokens.js +294 -92
- package/dist/casts/wallet-token.d.ts +4 -13
- package/dist/casts/wallet-token.js +9 -5
- package/dist/casts/wallet.d.ts +2 -0
- package/dist/casts/wallet.js +4 -0
- package/dist/factories/tokens.d.ts +3 -3
- package/dist/helpers/animated-qr.js +2 -2
- package/dist/helpers/cashu.d.ts +18 -4
- package/dist/helpers/cashu.js +11 -3
- package/dist/helpers/couch.d.ts +2 -0
- package/dist/helpers/indexed-db-couch.d.ts +12 -0
- package/dist/helpers/indexed-db-couch.js +41 -14
- package/dist/helpers/local-storage-couch.d.ts +4 -0
- package/dist/helpers/local-storage-couch.js +14 -3
- package/dist/helpers/nutzap.js +5 -5
- package/dist/helpers/tokens.d.ts +17 -10
- package/dist/helpers/tokens.js +10 -0
- package/dist/models/tokens.d.ts +14 -0
- package/dist/models/tokens.js +59 -28
- package/dist/operations/nutzap.js +3 -2
- package/dist/operations/tokens.d.ts +14 -3
- package/dist/operations/tokens.js +12 -3
- package/dist/wallet/index.d.ts +3 -0
- package/dist/wallet/index.js +3 -0
- package/dist/wallet/loading.d.ts +50 -0
- package/dist/wallet/loading.js +62 -0
- package/dist/wallet/nut-wallet.d.ts +296 -0
- package/dist/wallet/nut-wallet.js +906 -0
- package/dist/wallet/types.d.ts +141 -0
- package/dist/wallet/types.js +12 -0
- package/package.json +23 -11
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { Token } from "@cashu/cashu-ts";
|
|
1
|
+
import { Token, Wallet } from "@cashu/cashu-ts";
|
|
2
2
|
import { Action } from "applesauce-actions";
|
|
3
3
|
import { NostrEvent } from "applesauce-core/helpers/event";
|
|
4
4
|
import { ProfilePointer } from "applesauce-core/helpers/pointers";
|
|
5
5
|
import { Couch } from "../helpers/couch.js";
|
|
6
6
|
import "../casts/__register__.js";
|
|
7
|
+
/** A function that returns a loaded cashu {@link Wallet} for a mint url */
|
|
8
|
+
type CashuWalletProvider = (mint: string) => Promise<Wallet>;
|
|
7
9
|
/** Creates a NIP-61 nutzap event for an event with a token */
|
|
8
10
|
export declare function NutzapEvent(event: NostrEvent, token: Token, options?: {
|
|
9
11
|
comment?: string;
|
|
@@ -20,5 +22,7 @@ export declare function NutzapProfile(user: string | ProfilePointer, token: Toke
|
|
|
20
22
|
* Supports nutzaps with different mints by grouping them by mint and redeeming each group separately
|
|
21
23
|
* @param nutzaps single nutzap event or array of nutzap events
|
|
22
24
|
* @param couch optional couch interface for temporarily storing tokens during the operation
|
|
25
|
+
* @param getCashuWallet optional provider returning a cached cashu Wallet for a mint
|
|
23
26
|
*/
|
|
24
|
-
export declare function ReceiveNutzaps(nutzaps: NostrEvent | NostrEvent[], couch?: Couch): Action;
|
|
27
|
+
export declare function ReceiveNutzaps(nutzaps: NostrEvent | NostrEvent[], couch?: Couch, getCashuWallet?: CashuWalletProvider): Action;
|
|
28
|
+
export {};
|
package/dist/actions/nutzaps.js
CHANGED
|
@@ -4,11 +4,22 @@ import { bytesToHex } from "applesauce-core/helpers/event";
|
|
|
4
4
|
import { WalletHistoryFactory } from "../factories/history.js";
|
|
5
5
|
import { WalletTokenFactory } from "../factories/tokens.js";
|
|
6
6
|
import { NutzapFactory } from "../factories/nutzap.js";
|
|
7
|
-
import { verifyProofsLocked } from "../helpers/nutzap-info.js";
|
|
7
|
+
import { getNutzapInfoMints, verifyProofsLocked } from "../helpers/nutzap-info.js";
|
|
8
8
|
import { getNutzapMint, getNutzapProofs, isValidNutzap } from "../helpers/nutzap.js";
|
|
9
9
|
import { getUnlockedWallet } from "./common.js";
|
|
10
10
|
// Make sure the nutzap$ is registered on the user class
|
|
11
11
|
import "../casts/__register__.js";
|
|
12
|
+
/**
|
|
13
|
+
* Returns a loaded cashu {@link Wallet} for a mint url. Uses the `getCashuWallet` provider when given
|
|
14
|
+
* (so a caller can supply a cached, wallet-specific instance), otherwise creates and loads a fresh wallet.
|
|
15
|
+
*/
|
|
16
|
+
async function loadCashuWallet(mint, options) {
|
|
17
|
+
if (options?.getCashuWallet)
|
|
18
|
+
return options.getCashuWallet(mint);
|
|
19
|
+
const wallet = new Wallet(mint);
|
|
20
|
+
await wallet.loadMint();
|
|
21
|
+
return wallet;
|
|
22
|
+
}
|
|
12
23
|
/** Creates a NIP-61 nutzap event for an event with a token */
|
|
13
24
|
export function NutzapEvent(event, token, options) {
|
|
14
25
|
return async ({ events, signer, user, publish }) => {
|
|
@@ -22,17 +33,20 @@ export function NutzapEvent(event, token, options) {
|
|
|
22
33
|
const info = await recipient.nutzap$.$first(5000, undefined);
|
|
23
34
|
if (!info)
|
|
24
35
|
throw new Error("Nutzap info not found");
|
|
25
|
-
//
|
|
26
|
-
|
|
36
|
+
// Ensure the user's wallet exists and is unlocked
|
|
37
|
+
await getUnlockedWallet(user, signer);
|
|
38
|
+
if (!getNutzapInfoMints(info.event).some(({ mint }) => mint === token.mint))
|
|
39
|
+
throw new Error("Token mint is not listed in the recipient's nutzap info");
|
|
27
40
|
// Verify all tokens are p2pk locked
|
|
28
41
|
verifyProofsLocked(token.proofs, info.event);
|
|
29
42
|
// Create the nutzap event
|
|
30
43
|
const nutzap = await NutzapFactory.forEvent(event, token, comment || token.memo).sign(signer);
|
|
31
44
|
// Publish the nutzap event
|
|
32
|
-
await publish(nutzap,
|
|
45
|
+
await publish(nutzap, info.relays);
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
await clearStoredToken?.();
|
|
33
49
|
}
|
|
34
|
-
catch { }
|
|
35
|
-
await clearStoredToken?.();
|
|
36
50
|
};
|
|
37
51
|
}
|
|
38
52
|
/** Creates a NIP-61 nutzap event to a users profile */
|
|
@@ -48,6 +62,8 @@ export function NutzapProfile(user, token, options) {
|
|
|
48
62
|
const info = await recipient.nutzap$.$first(5000, undefined);
|
|
49
63
|
if (!info)
|
|
50
64
|
throw new Error("Nutzap info not found");
|
|
65
|
+
if (!getNutzapInfoMints(info.event).some(({ mint }) => mint === token.mint))
|
|
66
|
+
throw new Error("Token mint is not listed in the recipient's nutzap info");
|
|
51
67
|
// Verify all tokens are p2pk locked
|
|
52
68
|
verifyProofsLocked(token.proofs, info.event);
|
|
53
69
|
// Create the nutzap event
|
|
@@ -55,8 +71,9 @@ export function NutzapProfile(user, token, options) {
|
|
|
55
71
|
// Publish the nutzap event
|
|
56
72
|
await publish(nutzap, info.relays);
|
|
57
73
|
}
|
|
58
|
-
|
|
59
|
-
|
|
74
|
+
finally {
|
|
75
|
+
await clearStoredToken?.();
|
|
76
|
+
}
|
|
60
77
|
};
|
|
61
78
|
}
|
|
62
79
|
/**
|
|
@@ -65,8 +82,9 @@ export function NutzapProfile(user, token, options) {
|
|
|
65
82
|
* Supports nutzaps with different mints by grouping them by mint and redeeming each group separately
|
|
66
83
|
* @param nutzaps single nutzap event or array of nutzap events
|
|
67
84
|
* @param couch optional couch interface for temporarily storing tokens during the operation
|
|
85
|
+
* @param getCashuWallet optional provider returning a cached cashu Wallet for a mint
|
|
68
86
|
*/
|
|
69
|
-
export function ReceiveNutzaps(nutzaps, couch) {
|
|
87
|
+
export function ReceiveNutzaps(nutzaps, couch, getCashuWallet) {
|
|
70
88
|
return async ({ signer, user, publish }) => {
|
|
71
89
|
if (!signer)
|
|
72
90
|
throw new Error("Missing signer");
|
|
@@ -113,8 +131,7 @@ export function ReceiveNutzaps(nutzaps, couch) {
|
|
|
113
131
|
unit: "sat",
|
|
114
132
|
};
|
|
115
133
|
// Use cashu-ts to receive/unlock the P2PK-locked token
|
|
116
|
-
const cashuWallet =
|
|
117
|
-
await cashuWallet.loadMint();
|
|
134
|
+
const cashuWallet = await loadCashuWallet(mint, { getCashuWallet });
|
|
118
135
|
// Receive the token using the new wallet.ops API
|
|
119
136
|
// This will swap P2PK-locked proofs with unlocked proofs
|
|
120
137
|
let receivedProofs;
|
|
@@ -125,7 +142,7 @@ export function ReceiveNutzaps(nutzaps, couch) {
|
|
|
125
142
|
throw new Error(`Failed to receive token for mint ${mint}: ${error instanceof Error ? error.message : String(error)}`);
|
|
126
143
|
}
|
|
127
144
|
// Calculate total amount
|
|
128
|
-
const amount = sumProofs(receivedProofs);
|
|
145
|
+
const amount = sumProofs(receivedProofs).toNumber();
|
|
129
146
|
// Create token event with received unlocked proofs
|
|
130
147
|
const receivedToken = {
|
|
131
148
|
mint,
|
package/dist/actions/tokens.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { Proof, Token, Wallet } from "@cashu/cashu-ts";
|
|
1
|
+
import { MintQuoteBolt11Response, Proof, ProofLike, Token, Wallet } from "@cashu/cashu-ts";
|
|
2
2
|
import { Action } from "applesauce-actions";
|
|
3
3
|
import { NostrEvent } from "applesauce-core/helpers/event";
|
|
4
4
|
import { Couch } from "../helpers/couch.js";
|
|
5
5
|
import "../casts/__register__.js";
|
|
6
|
+
/** A function that returns a loaded cashu {@link Wallet} for a mint url */
|
|
7
|
+
type CashuWalletProvider = (mint: string) => Promise<Wallet>;
|
|
6
8
|
/**
|
|
7
9
|
* Adds a cashu token to the wallet and creates a history event
|
|
8
10
|
* @param token the cashu token to add
|
|
@@ -17,21 +19,102 @@ export declare function AddToken(token: Token, options?: {
|
|
|
17
19
|
export declare function ReceiveToken(token: Token, options?: {
|
|
18
20
|
addHistory?: boolean;
|
|
19
21
|
couch?: Couch;
|
|
22
|
+
wallet?: Wallet;
|
|
23
|
+
getCashuWallet?: CashuWalletProvider;
|
|
20
24
|
}): Action;
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
/**
|
|
26
|
+
* A method-agnostic action that mints new proofs from a paid mint quote and adds them to the wallet.
|
|
27
|
+
* The `mintProofs` callback performs the payment-method-specific mint call (bolt11, bolt12, onchain, …)
|
|
28
|
+
* against the loaded cashu {@link Wallet}; everything else (couch safety + token/history bookkeeping) is
|
|
29
|
+
* shared. {@link MintTokens} is the bolt11 wrapper over this action.
|
|
30
|
+
* @param mint the mint url to mint the proofs from
|
|
31
|
+
* @param mintProofs a callback that mints and returns the new proofs for the paid quote
|
|
32
|
+
* @param options.couch optional couch interface for temporarily storing the minted token
|
|
33
|
+
* @param options.wallet optional pre-loaded cashu Wallet for the mint
|
|
34
|
+
* @param options.getCashuWallet optional provider returning a cached cashu Wallet for a mint
|
|
35
|
+
*/
|
|
36
|
+
export declare function MintProofs(mint: string, mintProofs: (cashuWallet: Wallet) => Promise<Proof[]>, options?: {
|
|
37
|
+
couch?: Couch;
|
|
38
|
+
wallet?: Wallet;
|
|
39
|
+
getCashuWallet?: CashuWalletProvider;
|
|
40
|
+
}): Action;
|
|
41
|
+
/**
|
|
42
|
+
* Mints new proofs from an already-paid bolt11 mint quote and adds them to the wallet.
|
|
43
|
+
* A thin bolt11 wrapper over {@link MintProofs}.
|
|
44
|
+
* @param mint the mint url to mint the proofs from
|
|
45
|
+
* @param amount the amount of the paid mint quote in sats
|
|
46
|
+
* @param quote the paid mint quote id or response
|
|
47
|
+
* @param options.couch optional couch interface for temporarily storing the minted token
|
|
48
|
+
* @param options.wallet optional pre-loaded cashu Wallet for the mint
|
|
49
|
+
* @param options.getCashuWallet optional provider returning a cached cashu Wallet for a mint
|
|
50
|
+
*/
|
|
51
|
+
export declare function MintTokens(mint: string, amount: number, quote: string | MintQuoteBolt11Response, options?: {
|
|
52
|
+
couch?: Couch;
|
|
53
|
+
wallet?: Wallet;
|
|
54
|
+
getCashuWallet?: CashuWalletProvider;
|
|
55
|
+
}): Action;
|
|
56
|
+
/**
|
|
57
|
+
* An action that deletes old token events and adds a spend history item
|
|
58
|
+
* @param options.createDeleteEvents whether to publish a NIP-09 delete event for the spent token events
|
|
59
|
+
* (default true). The change token event always references the spent ids in its `del` field, so the
|
|
60
|
+
* wallet can reconcile its balance without the delete event; skipping it saves a signing operation at
|
|
61
|
+
* the cost of leaving the spent token events on relays until {@link CleanupDeletedTokens}.
|
|
62
|
+
* @param options.couch optional couch interface for temporarily storing the change token
|
|
63
|
+
*/
|
|
64
|
+
export declare function CompleteSpend(spent: NostrEvent[], change: Token, options?: {
|
|
65
|
+
couch?: Couch;
|
|
66
|
+
createDeleteEvents?: boolean;
|
|
67
|
+
}): Action;
|
|
68
|
+
/**
|
|
69
|
+
* Combines all unlocked token events into a single event per mint
|
|
70
|
+
* @param options.createDeleteEvents whether to publish a single batched NIP-09 delete event for the old
|
|
71
|
+
* token events (default true). The new token events always reference the old ids in their `del` field.
|
|
72
|
+
*/
|
|
26
73
|
export declare function ConsolidateTokens(options?: {
|
|
27
74
|
unlockTokens?: boolean;
|
|
75
|
+
getCashuWallet?: CashuWalletProvider;
|
|
76
|
+
createDeleteEvents?: boolean;
|
|
77
|
+
}): Action;
|
|
78
|
+
/**
|
|
79
|
+
* Rolls every unlocked token over to a fresh cashu token. For each mint the proofs are swapped at the mint
|
|
80
|
+
* (rotating the secrets) and a single new token event is created whose `del` field references the
|
|
81
|
+
* rolled-over token events. Token events that another token has already marked as deleted are skipped so a
|
|
82
|
+
* repeated rollover does not try to swap already-spent proofs.
|
|
83
|
+
*
|
|
84
|
+
* To keep signer operations to a minimum, every new token event is published together with a *single*
|
|
85
|
+
* batched NIP-09 delete event covering the rolled-over token events across *all* mints — never one delete
|
|
86
|
+
* per mint.
|
|
87
|
+
*
|
|
88
|
+
* @param options.createDeleteEvents whether to publish the single batched NIP-09 delete event (default true).
|
|
89
|
+
* The new token events always reference the old ids in their `del` field, so the wallet can reconcile its
|
|
90
|
+
* balance without the delete event; skipping it leaves the spent token events on relays until
|
|
91
|
+
* {@link CleanupDeletedTokens} removes them.
|
|
92
|
+
* @param options.couch optional couch used to keep each fresh token safe until its token event is published
|
|
93
|
+
*/
|
|
94
|
+
export declare function RolloverTokens(options?: {
|
|
95
|
+
unlockTokens?: boolean;
|
|
96
|
+
couch?: Couch;
|
|
97
|
+
getCashuWallet?: CashuWalletProvider;
|
|
98
|
+
createDeleteEvents?: boolean;
|
|
28
99
|
}): Action;
|
|
29
100
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
101
|
+
* Detects token events that have been marked as deleted by a newer token event's `del` field but are
|
|
102
|
+
* still present, and publishes a single NIP-09 delete event for them. Use this to clean up the old
|
|
103
|
+
* token events left behind when operations run with `createDeleteEvents: false`, batching what would
|
|
104
|
+
* otherwise be many per-operation delete events into a single signing operation.
|
|
105
|
+
*/
|
|
106
|
+
export declare function CleanupDeletedTokens(): Action;
|
|
107
|
+
/**
|
|
108
|
+
* Recovers tokens from a couch by checking if they exist in the wallet, verifying they are unspent, and
|
|
109
|
+
* creating token events for any recoverable proofs. Once every token has been processed the couch is
|
|
110
|
+
* cleared, so tokens that are already in the wallet or have been spent are cleaned out too. Any token
|
|
111
|
+
* whose recovered token event failed to publish is left in the couch so it can be retried on a later run.
|
|
32
112
|
* @param couch the couch interface to recover tokens from
|
|
113
|
+
* @param options.getCashuWallet optional provider returning a cached cashu Wallet for a mint
|
|
33
114
|
*/
|
|
34
|
-
export declare function RecoverFromCouch(couch: Couch
|
|
115
|
+
export declare function RecoverFromCouch(couch: Couch, options?: {
|
|
116
|
+
getCashuWallet?: CashuWalletProvider;
|
|
117
|
+
}): Action;
|
|
35
118
|
/**
|
|
36
119
|
* Token selection function type that matches dumbTokenSelection signature.
|
|
37
120
|
* Must return tokens from a single mint and ensure all selected tokens are from that mint.
|
|
@@ -39,7 +122,7 @@ export declare function RecoverFromCouch(couch: Couch): Action;
|
|
|
39
122
|
*/
|
|
40
123
|
export type TokenSelectionFunction = (tokens: NostrEvent[], minAmount: number, mint?: string) => {
|
|
41
124
|
events: NostrEvent[];
|
|
42
|
-
proofs:
|
|
125
|
+
proofs: ProofLike[];
|
|
43
126
|
};
|
|
44
127
|
/**
|
|
45
128
|
* A generic action that safely selects tokens, performs an async operation, and handles change.
|
|
@@ -75,7 +158,7 @@ export type TokenSelectionFunction = (tokens: NostrEvent[], minAmount: number, m
|
|
|
75
158
|
* }, { couch, tokenSelection: myCustomSelectionFunction });
|
|
76
159
|
*/
|
|
77
160
|
export declare function TokensOperation(minAmount: number, operation: (params: {
|
|
78
|
-
selectedProofs:
|
|
161
|
+
selectedProofs: ProofLike[];
|
|
79
162
|
mint: string;
|
|
80
163
|
cashuWallet: Wallet;
|
|
81
164
|
}) => Promise<{
|
|
@@ -84,4 +167,8 @@ export declare function TokensOperation(minAmount: number, operation: (params: {
|
|
|
84
167
|
mint?: string;
|
|
85
168
|
couch: Couch;
|
|
86
169
|
tokenSelection?: TokenSelectionFunction;
|
|
170
|
+
wallet?: Wallet;
|
|
171
|
+
getCashuWallet?: CashuWalletProvider;
|
|
172
|
+
createDeleteEvents?: boolean;
|
|
87
173
|
}): Action;
|
|
174
|
+
export {};
|