applesauce-wallet 5.0.0 → 6.1.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.
Files changed (56) hide show
  1. package/dist/actions/mint-recomendation.js +15 -16
  2. package/dist/actions/nutzap-info.js +38 -46
  3. package/dist/actions/nutzaps.js +21 -12
  4. package/dist/actions/tokens.js +51 -39
  5. package/dist/actions/wallet.js +18 -25
  6. package/dist/casts/__register__.d.ts +1 -1
  7. package/dist/casts/__register__.js +1 -1
  8. package/dist/casts/mint-info.d.ts +1 -0
  9. package/dist/casts/mint-info.js +3 -1
  10. package/dist/casts/mint-recommendation.d.ts +1 -0
  11. package/dist/casts/mint-recommendation.js +1 -0
  12. package/dist/casts/nutzap-info.d.ts +1 -0
  13. package/dist/casts/nutzap-info.js +1 -0
  14. package/dist/casts/nutzap.d.ts +5 -4
  15. package/dist/casts/nutzap.js +3 -2
  16. package/dist/casts/wallet-history.d.ts +3 -2
  17. package/dist/casts/wallet-history.js +1 -0
  18. package/dist/casts/wallet-token.d.ts +6 -5
  19. package/dist/casts/wallet-token.js +1 -0
  20. package/dist/casts/wallet.d.ts +1 -0
  21. package/dist/casts/wallet.js +5 -1
  22. package/dist/factories/history.d.ts +10 -0
  23. package/dist/factories/history.js +16 -0
  24. package/dist/{blueprints → factories}/index.d.ts +4 -3
  25. package/dist/{blueprints → factories}/index.js +4 -3
  26. package/dist/factories/mint-recommendation.d.ts +14 -0
  27. package/dist/factories/mint-recommendation.js +29 -0
  28. package/dist/factories/nutzap-info.d.ts +31 -0
  29. package/dist/factories/nutzap-info.js +44 -0
  30. package/dist/factories/nutzap.d.ts +15 -0
  31. package/dist/factories/nutzap.js +35 -0
  32. package/dist/factories/tokens.d.ts +9 -0
  33. package/dist/factories/tokens.js +13 -0
  34. package/dist/factories/wallet.d.ts +17 -0
  35. package/dist/factories/wallet.js +40 -0
  36. package/dist/index.d.ts +1 -1
  37. package/dist/index.js +1 -1
  38. package/dist/operations/history.d.ts +2 -2
  39. package/dist/operations/history.js +2 -2
  40. package/dist/operations/mint-recommendation.js +1 -1
  41. package/dist/operations/nutzap.js +1 -1
  42. package/dist/operations/tokens.d.ts +1 -1
  43. package/dist/operations/tokens.js +5 -5
  44. package/dist/operations/wallet.d.ts +12 -8
  45. package/dist/operations/wallet.js +18 -14
  46. package/package.json +13 -13
  47. package/dist/blueprints/history.d.ts +0 -4
  48. package/dist/blueprints/history.js +0 -11
  49. package/dist/blueprints/mint-recommendation.d.ts +0 -16
  50. package/dist/blueprints/mint-recommendation.js +0 -11
  51. package/dist/blueprints/tokens.d.ts +0 -7
  52. package/dist/blueprints/tokens.js +0 -11
  53. package/dist/blueprints/wallet.d.ts +0 -9
  54. package/dist/blueprints/wallet.js +0 -14
  55. package/dist/blueprints/zaps.d.ts +0 -8
  56. package/dist/blueprints/zaps.js +0 -12
@@ -1,8 +1,7 @@
1
1
  import { Wallet } from "@cashu/cashu-ts";
2
- import { MintRecommendationBlueprint } from "../blueprints/mint-recommendation.js";
2
+ import { MintRecommendationFactory } from "../factories/mint-recommendation.js";
3
3
  import { getCashuMintPubkey, getCashuMintURL, isValidCashuMintInfo } from "../helpers/mint-info.js";
4
4
  import { MINT_RECOMMENDATION_KIND, getRecommendationMintPubkey, isValidMintRecommendation, } from "../helpers/mint-recommendation.js";
5
- import { setComment } from "../operations/mint-recommendation.js";
6
5
  // Helper function to fetch mint pubkey from URL
7
6
  async function fetchMintPubkey(mintUrl) {
8
7
  // Fetch mint info directly from the /v1/info endpoint
@@ -21,10 +20,12 @@ import "../casts/__register__.js";
21
20
  * Can accept a mint URL, Wallet instance, or MintInfo event.
22
21
  */
23
22
  export function RecommendMint(input, options) {
24
- return async ({ factory, sign, publish }) => {
23
+ return async ({ signer, publish }) => {
24
+ if (!signer)
25
+ throw new Error("Missing signer");
25
26
  let mintPubkey;
26
27
  let url;
27
- let addressPointer = undefined;
28
+ let mintInfoEvent = undefined;
28
29
  // Handle different input types
29
30
  if (typeof input === "string") {
30
31
  if (!URL.canParse(input))
@@ -43,18 +44,16 @@ export function RecommendMint(input, options) {
43
44
  throw new Error("Invalid mint info event. Expected kind:38172 with required `d` and `u` tags.");
44
45
  mintPubkey = getCashuMintPubkey(input);
45
46
  url = getCashuMintURL(input);
46
- // Use the event itself as address pointer (blueprint will convert it)
47
- addressPointer = input;
47
+ // Use the event itself as address pointer (factory will convert it)
48
+ mintInfoEvent = input;
48
49
  }
49
50
  // Create the mint recommendation event
50
- const recommendation = await factory
51
- .create(MintRecommendationBlueprint, {
52
- mintPubkey,
53
- url,
54
- addressPointer,
55
- comment: options?.comment,
56
- })
57
- .then(sign);
51
+ let recommendationFactory = MintRecommendationFactory.create(url || "", mintPubkey);
52
+ if (mintInfoEvent)
53
+ recommendationFactory = recommendationFactory.mintInfo(mintInfoEvent);
54
+ if (options?.comment)
55
+ recommendationFactory = recommendationFactory.comment(options.comment);
56
+ const recommendation = await recommendationFactory.sign(signer);
58
57
  // Publish the event
59
58
  await publish(recommendation, options?.relays);
60
59
  };
@@ -64,7 +63,7 @@ export function RecommendMint(input, options) {
64
63
  * Can accept a mint pubkey (to find the recommendation) or the recommendation event directly.
65
64
  */
66
65
  export function UpdateMintRecommendation(input, comment, options) {
67
- return async ({ events, factory, self, sign, publish }) => {
66
+ return async ({ events, signer, self, publish }) => {
68
67
  let recommendation;
69
68
  // Handle different input types
70
69
  if (typeof input === "string") {
@@ -89,7 +88,7 @@ export function UpdateMintRecommendation(input, comment, options) {
89
88
  recommendation = input;
90
89
  }
91
90
  // Update the comment
92
- const updated = await factory.modify(recommendation, setComment(comment)).then(sign);
91
+ const updated = await MintRecommendationFactory.modify(recommendation).comment(comment).sign(signer);
93
92
  // Publish the updated event
94
93
  await publish(updated, options?.relays);
95
94
  };
@@ -1,74 +1,70 @@
1
1
  import { getNutzapInfoRelays, NUTZAP_INFO_KIND } from "../helpers/nutzap-info.js";
2
- import { addNutzapInfoMint, addNutzapInfoRelay, removeNutzapInfoMint, removeNutzapInfoRelay, setNutzapInfoMints, setNutzapInfoPubkey, setNutzapInfoRelays, } from "../operations/nutzap-info.js";
2
+ import { NutzapInfoFactory } from "../factories/nutzap-info.js";
3
3
  // Make sure the nutzap$ is registered on the user class
4
4
  import "../casts/__register__.js";
5
5
  /** An action to add a relay to the kind 10019 nutzap info event */
6
6
  export function AddNutzapInfoRelay(relay) {
7
- return async ({ events, factory, self, sign, publish }) => {
7
+ return async ({ events, signer, self, publish }) => {
8
8
  if (typeof relay === "string")
9
9
  relay = [relay];
10
- const operations = relay.map((r) => addNutzapInfoRelay(r));
11
10
  const nutzapInfo = events.getReplaceable(NUTZAP_INFO_KIND, self);
12
- const signed = nutzapInfo
13
- ? await factory.modify(nutzapInfo, ...operations).then(sign)
14
- : await factory.build({ kind: NUTZAP_INFO_KIND }, ...operations).then(sign);
15
- // Use relays from the updated event
16
- const relays = getNutzapInfoRelays(signed);
17
- await publish(signed, relays);
11
+ let factory = nutzapInfo ? NutzapInfoFactory.modify(nutzapInfo) : NutzapInfoFactory.create();
12
+ for (const r of relay)
13
+ factory = factory.addRelay(r);
14
+ const signed = await factory.sign(signer);
15
+ await publish(signed, getNutzapInfoRelays(signed));
18
16
  };
19
17
  }
20
18
  /** An action to remove a relay from the kind 10019 nutzap info event */
21
19
  export function RemoveNutzapInfoRelay(relay) {
22
- return async ({ events, factory, self, sign, publish }) => {
20
+ return async ({ events, signer, self, publish }) => {
23
21
  if (typeof relay === "string")
24
22
  relay = [relay];
25
23
  const nutzapInfo = events.getReplaceable(NUTZAP_INFO_KIND, self);
26
24
  if (!nutzapInfo)
27
25
  return;
28
- const operations = relay.map((r) => removeNutzapInfoRelay(r));
29
- const signed = await factory.modify(nutzapInfo, ...operations).then(sign);
30
- // Use relays from the updated event
31
- const relays = getNutzapInfoRelays(signed);
32
- await publish(signed, relays);
26
+ let factory = NutzapInfoFactory.modify(nutzapInfo);
27
+ for (const r of relay)
28
+ factory = factory.removeRelay(r);
29
+ const signed = await factory.sign(signer);
30
+ await publish(signed, getNutzapInfoRelays(signed));
33
31
  };
34
32
  }
35
33
  /** An action to add a mint to the kind 10019 nutzap info event */
36
34
  export function AddNutzapInfoMint(mint) {
37
- return async ({ events, factory, self, sign, publish }) => {
35
+ return async ({ events, signer, self, publish }) => {
38
36
  const mints = Array.isArray(mint) ? mint : [mint];
39
- const operations = mints.map((m) => addNutzapInfoMint(m));
40
37
  const nutzapInfo = events.getReplaceable(NUTZAP_INFO_KIND, self);
41
- const signed = nutzapInfo
42
- ? await factory.modify(nutzapInfo, ...operations).then(sign)
43
- : await factory.build({ kind: NUTZAP_INFO_KIND }, ...operations).then(sign);
44
- // Use relays from the updated event
45
- const relays = getNutzapInfoRelays(signed);
46
- await publish(signed, relays);
38
+ let factory = nutzapInfo ? NutzapInfoFactory.modify(nutzapInfo) : NutzapInfoFactory.create();
39
+ for (const m of mints)
40
+ factory = factory.addMint(m);
41
+ const signed = await factory.sign(signer);
42
+ await publish(signed, getNutzapInfoRelays(signed));
47
43
  };
48
44
  }
49
45
  /** An action to remove a mint from the kind 10019 nutzap info event */
50
46
  export function RemoveNutzapInfoMint(mint) {
51
- return async ({ events, factory, self, sign, publish }) => {
47
+ return async ({ events, signer, self, publish }) => {
52
48
  if (typeof mint === "string")
53
49
  mint = [mint];
54
50
  const nutzapInfo = events.getReplaceable(NUTZAP_INFO_KIND, self);
55
51
  if (!nutzapInfo)
56
52
  return;
57
- const operations = mint.map((m) => removeNutzapInfoMint(m));
58
- const signed = await factory.modify(nutzapInfo, ...operations).then(sign);
59
- // Use relays from the updated event
60
- const relays = getNutzapInfoRelays(signed);
61
- await publish(signed, relays);
53
+ let factory = NutzapInfoFactory.modify(nutzapInfo);
54
+ for (const m of mint)
55
+ factory = factory.removeMint(m);
56
+ const signed = await factory.sign(signer);
57
+ await publish(signed, getNutzapInfoRelays(signed));
62
58
  };
63
59
  }
64
60
  /** An action to update the entire nutzap info event */
65
61
  export function UpdateNutzapInfo(relays, mints) {
66
- return async ({ events, factory, self, sign, publish }) => {
67
- const operations = [setNutzapInfoRelays(relays), setNutzapInfoMints(mints)];
62
+ return async ({ events, signer, self, publish }) => {
68
63
  const nutzapInfo = events.getReplaceable(NUTZAP_INFO_KIND, self);
69
- const signed = nutzapInfo
70
- ? await factory.modify(nutzapInfo, ...operations).then(sign)
71
- : await factory.build({ kind: NUTZAP_INFO_KIND }, ...operations).then(sign);
64
+ const signed = await (nutzapInfo ? NutzapInfoFactory.modify(nutzapInfo) : NutzapInfoFactory.create())
65
+ .setRelays(relays)
66
+ .setMints(mints)
67
+ .sign(signer);
72
68
  await publish(signed, relays);
73
69
  };
74
70
  }
@@ -77,14 +73,12 @@ export function UpdateNutzapInfo(relays, mints) {
77
73
  * @throws if the nutzap info does not exist
78
74
  */
79
75
  export function SetNutzapInfoMints(mints) {
80
- return async ({ events, self, factory, sign, publish }) => {
76
+ return async ({ events, self, signer, publish }) => {
81
77
  const nutzapInfo = events.getReplaceable(NUTZAP_INFO_KIND, self);
82
78
  if (!nutzapInfo)
83
79
  throw new Error("Nutzap info does not exist");
84
- const signed = await factory.modify(nutzapInfo, setNutzapInfoMints(mints)).then(sign);
85
- // Use relays from the updated event
86
- const relays = getNutzapInfoRelays(signed);
87
- await publish(signed, relays);
80
+ const signed = await NutzapInfoFactory.modify(nutzapInfo).setMints(mints).sign(signer);
81
+ await publish(signed, getNutzapInfoRelays(signed));
88
82
  };
89
83
  }
90
84
  /**
@@ -92,11 +86,11 @@ export function SetNutzapInfoMints(mints) {
92
86
  * @throws if the nutzap info does not exist
93
87
  */
94
88
  export function SetNutzapInfoRelays(relays) {
95
- return async ({ events, self, factory, sign, publish }) => {
89
+ return async ({ events, self, signer, publish }) => {
96
90
  const nutzapInfo = events.getReplaceable(NUTZAP_INFO_KIND, self);
97
91
  if (!nutzapInfo)
98
92
  throw new Error("Nutzap info does not exist");
99
- const signed = await factory.modify(nutzapInfo, setNutzapInfoRelays(relays)).then(sign);
93
+ const signed = await NutzapInfoFactory.modify(nutzapInfo).setRelays(relays).sign(signer);
100
94
  await publish(signed, relays);
101
95
  };
102
96
  }
@@ -105,13 +99,11 @@ export function SetNutzapInfoRelays(relays) {
105
99
  * @throws if the nutzap info does not exist
106
100
  */
107
101
  export function SetNutzapInfoPubkey(privateKey) {
108
- return async ({ events, self, factory, sign, publish }) => {
102
+ return async ({ events, self, signer, publish }) => {
109
103
  const nutzapInfo = events.getReplaceable(NUTZAP_INFO_KIND, self);
110
104
  if (!nutzapInfo)
111
105
  throw new Error("Nutzap info does not exist");
112
- const signed = await factory.modify(nutzapInfo, setNutzapInfoPubkey(privateKey)).then(sign);
113
- // Use relays from the updated event
114
- const relays = getNutzapInfoRelays(signed);
115
- await publish(signed, relays);
106
+ const signed = await NutzapInfoFactory.modify(nutzapInfo).setPubkey(privateKey).sign(signer);
107
+ await publish(signed, getNutzapInfoRelays(signed));
116
108
  };
117
109
  }
@@ -1,9 +1,9 @@
1
1
  import { sumProofs, Wallet } from "@cashu/cashu-ts";
2
2
  import { castUser } from "applesauce-common/casts";
3
3
  import { bytesToHex } from "applesauce-core/helpers/event";
4
- import { WalletHistoryBlueprint } from "../blueprints/history.js";
5
- import { WalletTokenBlueprint } from "../blueprints/tokens.js";
6
- import { NutzapBlueprint, ProfileNutzapBlueprint } from "../blueprints/zaps.js";
4
+ import { WalletHistoryFactory } from "../factories/history.js";
5
+ import { WalletTokenFactory } from "../factories/tokens.js";
6
+ import { NutzapFactory } from "../factories/nutzap.js";
7
7
  import { verifyProofsLocked } from "../helpers/nutzap-info.js";
8
8
  import { getNutzapMint, getNutzapProofs, isValidNutzap } from "../helpers/nutzap.js";
9
9
  import { getUnlockedWallet } from "./common.js";
@@ -11,7 +11,9 @@ import { getUnlockedWallet } from "./common.js";
11
11
  import "../casts/__register__.js";
12
12
  /** Creates a NIP-61 nutzap event for an event with a token */
13
13
  export function NutzapEvent(event, token, options) {
14
- return async ({ events, factory, user, signer, sign, publish }) => {
14
+ return async ({ events, signer, user, publish }) => {
15
+ if (!signer)
16
+ throw new Error("Missing signer");
15
17
  const { comment, couch } = options ?? {};
16
18
  const clearStoredToken = await couch?.store(token);
17
19
  try {
@@ -25,7 +27,7 @@ export function NutzapEvent(event, token, options) {
25
27
  // Verify all tokens are p2pk locked
26
28
  verifyProofsLocked(token.proofs, info.event);
27
29
  // Create the nutzap event
28
- const nutzap = await factory.create(NutzapBlueprint, event, token, comment || token.memo).then(sign);
30
+ const nutzap = await NutzapFactory.forEvent(event, token, comment || token.memo).sign(signer);
29
31
  // Publish the nutzap event
30
32
  await publish(nutzap, wallet.relays);
31
33
  }
@@ -35,7 +37,9 @@ export function NutzapEvent(event, token, options) {
35
37
  }
36
38
  /** Creates a NIP-61 nutzap event to a users profile */
37
39
  export function NutzapProfile(user, token, options) {
38
- return async ({ events, factory, sign, publish }) => {
40
+ return async ({ events, signer, publish }) => {
41
+ if (!signer)
42
+ throw new Error("Missing signer");
39
43
  const { comment, couch } = options ?? {};
40
44
  const clearStoredToken = await couch?.store(token);
41
45
  try {
@@ -47,7 +51,7 @@ export function NutzapProfile(user, token, options) {
47
51
  // Verify all tokens are p2pk locked
48
52
  verifyProofsLocked(token.proofs, info.event);
49
53
  // Create the nutzap event
50
- const nutzap = await factory.create(ProfileNutzapBlueprint, recipient, token, comment || token.memo).then(sign);
54
+ const nutzap = await NutzapFactory.forProfile(recipient, token, comment || token.memo).sign(signer);
51
55
  // Publish the nutzap event
52
56
  await publish(nutzap, info.relays);
53
57
  }
@@ -63,7 +67,7 @@ export function NutzapProfile(user, token, options) {
63
67
  * @param couch optional couch interface for temporarily storing tokens during the operation
64
68
  */
65
69
  export function ReceiveNutzaps(nutzaps, couch) {
66
- return async ({ factory, user, signer, sign, publish }) => {
70
+ return async ({ signer, user, publish }) => {
67
71
  if (!signer)
68
72
  throw new Error("Missing signer");
69
73
  // Normalize to array
@@ -133,12 +137,17 @@ export function ReceiveNutzaps(nutzaps, couch) {
133
137
  if (clearStoredToken) {
134
138
  clearMethods.push(clearStoredToken);
135
139
  }
136
- const tokenEvent = await factory.create(WalletTokenBlueprint, receivedToken, []).then(sign);
140
+ const tokenEvent = await WalletTokenFactory.create(receivedToken, []).sign(signer);
137
141
  // Create history event marking nutzap events as redeemed
138
142
  const nutzapIds = mintNutzaps.map((n) => n.id);
139
- const history = await factory
140
- .create(WalletHistoryBlueprint, { direction: "in", amount, mint, created: [tokenEvent.id] }, nutzapIds)
141
- .then(sign);
143
+ const history = await WalletHistoryFactory.create({
144
+ direction: "in",
145
+ amount,
146
+ mint,
147
+ created: [tokenEvent.id],
148
+ })
149
+ .redeemed(nutzapIds)
150
+ .sign(signer);
142
151
  // Publish events
143
152
  await publish(tokenEvent, wallet.relays);
144
153
  await publish(history, wallet.relays);
@@ -1,7 +1,7 @@
1
1
  import { CheckStateEnum, sumProofs, Wallet } from "@cashu/cashu-ts";
2
- import { DeleteBlueprint } from "applesauce-common/blueprints/delete";
3
- import { WalletHistoryBlueprint } from "../blueprints/history.js";
4
- import { WalletTokenBlueprint } from "../blueprints/tokens.js";
2
+ import { DeleteFactory } from "applesauce-core/factories";
3
+ import { WalletHistoryFactory } from "../factories/history.js";
4
+ import { WalletTokenFactory } from "../factories/tokens.js";
5
5
  import { getProofUID, ignoreDuplicateProofs } from "../helpers/cashu.js";
6
6
  import { dumbTokenSelection, getTokenContent, isTokenContentUnlocked, unlockTokenContent, WALLET_TOKEN_KIND, } from "../helpers/tokens.js";
7
7
  import { getUnlockedWallet } from "./common.js";
@@ -14,16 +14,25 @@ import "../casts/__register__.js";
14
14
  */
15
15
  export function AddToken(token, options) {
16
16
  const { redeemed, fee, addHistory = true } = options ?? {};
17
- return async ({ factory, user, publish, signer, sign }) => {
17
+ return async ({ signer, user, publish }) => {
18
+ if (!signer)
19
+ throw new Error("Missing signer");
18
20
  const wallet = await getUnlockedWallet(user, signer);
19
21
  const amount = sumProofs(token.proofs);
20
22
  // Create the token and history events
21
- const tokenEvent = await factory.create(WalletTokenBlueprint, token).then(sign);
23
+ const tokenEvent = await WalletTokenFactory.create(token).sign(signer);
22
24
  let history;
23
25
  if (addHistory || redeemed?.length) {
24
- history = await factory
25
- .create(WalletHistoryBlueprint, { direction: "in", amount, mint: token.mint, created: [tokenEvent.id], fee }, redeemed)
26
- .then(sign);
26
+ let historyFactory = WalletHistoryFactory.create({
27
+ direction: "in",
28
+ amount,
29
+ mint: token.mint,
30
+ created: [tokenEvent.id],
31
+ fee,
32
+ });
33
+ if (redeemed?.length)
34
+ historyFactory = historyFactory.redeemed(redeemed);
35
+ history = await historyFactory.sign(signer);
27
36
  }
28
37
  // Publish the events
29
38
  await publish([tokenEvent, history].filter((e) => !!e), wallet.relays);
@@ -61,21 +70,23 @@ export function ReceiveToken(token, options) {
61
70
  }
62
71
  /** An action that deletes old tokens and creates a new one but does not add a history event */
63
72
  export function RolloverTokens(tokens, token) {
64
- return async ({ factory, user, publish, signer, sign }) => {
73
+ return async ({ signer, user, publish }) => {
74
+ if (!signer)
75
+ throw new Error("Missing signer");
65
76
  const wallet = await getUnlockedWallet(user, signer);
66
77
  // create a new token event
67
- const tokenEvent = await factory
68
- .create(WalletTokenBlueprint, token, tokens.map((e) => e.id))
69
- .then(sign);
78
+ const tokenEvent = await WalletTokenFactory.create(token, tokens.map((e) => e.id)).sign(signer);
70
79
  // create a delete event for old tokens
71
- const deleteDraft = await factory.create(DeleteBlueprint, tokens).then(sign);
80
+ const deleteEvent = await DeleteFactory.fromEvents(tokens).sign(signer);
72
81
  // publish events
73
- await publish([tokenEvent, deleteDraft], wallet.relays);
82
+ await publish([tokenEvent, deleteEvent], wallet.relays);
74
83
  };
75
84
  }
76
85
  /** An action that deletes old token events and adds a spend history item */
77
86
  export function CompleteSpend(spent, change, couch) {
78
- return async ({ factory, user, publish, signer, sign }) => {
87
+ return async ({ signer, user, publish }) => {
88
+ if (!signer)
89
+ throw new Error("Missing signer");
79
90
  if (spent.length === 0)
80
91
  throw new Error("Cant complete spent with no token events");
81
92
  const unlocked = spent.filter(isTokenContentUnlocked);
@@ -91,20 +102,23 @@ export function CompleteSpend(spent, change, couch) {
91
102
  try {
92
103
  // create a new token event if needed
93
104
  const tokenEvent = changeAmount > 0
94
- ? await factory
95
- .create(WalletTokenBlueprint, change, spent.map((e) => e.id))
96
- .then(sign)
105
+ ? await WalletTokenFactory.create(change, spent.map((e) => e.id)).sign(signer)
97
106
  : undefined;
98
107
  // Get tokens total amount
99
108
  const total = sumProofs(unlocked.map((s) => getTokenContent(s).proofs).flat());
100
109
  // calculate the amount that was spent
101
110
  const diff = total - changeAmount;
102
111
  // sign delete and token
103
- const deleteEvent = await factory.create(DeleteBlueprint, spent).then(sign);
112
+ const deleteEvent = await DeleteFactory.fromEvents(spent).sign(signer);
104
113
  // create a history entry
105
- const history = await factory
106
- .create(WalletHistoryBlueprint, { direction: "out", mint: change.mint, amount: diff, created: tokenEvent ? [tokenEvent.id] : [] }, [])
107
- .then(sign);
114
+ const history = await WalletHistoryFactory.create({
115
+ direction: "out",
116
+ mint: change.mint,
117
+ amount: diff,
118
+ created: tokenEvent ? [tokenEvent.id] : [],
119
+ })
120
+ .redeemed([])
121
+ .sign(signer);
108
122
  // publish events
109
123
  await publish([tokenEvent, deleteEvent, history].filter((e) => !!e), wallet.relays);
110
124
  // Clear the stored token from the couch after successful completion
@@ -118,13 +132,13 @@ export function CompleteSpend(spent, change, couch) {
118
132
  }
119
133
  /** Combines all unlocked token events into a single event per mint */
120
134
  export function ConsolidateTokens(options) {
121
- return async ({ events, factory, self, sign, user, signer, publish }) => {
135
+ return async ({ events, signer, self, user, publish }) => {
136
+ if (!signer)
137
+ throw new Error("Missing signer");
122
138
  const wallet = await getUnlockedWallet(user, signer);
123
139
  const tokens = Array.from(events.getByFilters({ kinds: [WALLET_TOKEN_KIND], authors: [self] }));
124
140
  // Unlock tokens if requested
125
141
  if (options?.unlockTokens) {
126
- if (!signer)
127
- throw new Error("Missing signer");
128
142
  for (const token of tokens) {
129
143
  if (!isTokenContentUnlocked(token)) {
130
144
  try {
@@ -154,7 +168,7 @@ export function ConsolidateTokens(options) {
154
168
  .filter(ignoreDuplicateProofs());
155
169
  // If there are no proofs, just delete the old tokens without interacting with the mint
156
170
  if (proofs.length === 0) {
157
- const deleteEvent = await factory.create(DeleteBlueprint, tokens).then(sign);
171
+ const deleteEvent = await DeleteFactory.fromEvents(tokens).sign(signer);
158
172
  await publish(deleteEvent, wallet.relays);
159
173
  continue;
160
174
  }
@@ -166,12 +180,10 @@ export function ConsolidateTokens(options) {
166
180
  const notSpent = proofs.filter((_, i) => states[i].state !== CheckStateEnum.SPENT);
167
181
  // Only create a token event if there are unspent proofs
168
182
  const tokenEvent = notSpent.length > 0
169
- ? await factory
170
- .create(WalletTokenBlueprint, { mint, proofs: notSpent }, tokens.map((t) => t.id))
171
- .then(sign)
183
+ ? await WalletTokenFactory.create({ mint, proofs: notSpent }, tokens.map((t) => t.id)).sign(signer)
172
184
  : undefined;
173
185
  // create delete event
174
- const deleteEvent = await factory.create(DeleteBlueprint, tokens).then(sign);
186
+ const deleteEvent = await DeleteFactory.fromEvents(tokens).sign(signer);
175
187
  // Publish events
176
188
  await publish([tokenEvent, deleteEvent].filter((e) => !!e), wallet.relays);
177
189
  }
@@ -183,7 +195,9 @@ export function ConsolidateTokens(options) {
183
195
  * @param couch the couch interface to recover tokens from
184
196
  */
185
197
  export function RecoverFromCouch(couch) {
186
- return async ({ events, factory, self, sign, user, signer, publish }) => {
198
+ return async ({ events, signer, self, user, publish }) => {
199
+ if (!signer)
200
+ throw new Error("Missing signer");
187
201
  const wallet = await getUnlockedWallet(user, signer);
188
202
  // Get all tokens from the couch
189
203
  const couchTokens = await couch.getAll();
@@ -192,14 +206,12 @@ export function RecoverFromCouch(couch) {
192
206
  // Get all token events from the wallet
193
207
  const walletTokens = Array.from(events.getByFilters({ kinds: [WALLET_TOKEN_KIND], authors: [self] }));
194
208
  // Unlock wallet tokens if needed
195
- if (signer) {
196
- for (const token of walletTokens) {
197
- if (!isTokenContentUnlocked(token)) {
198
- try {
199
- await unlockTokenContent(token, signer);
200
- }
201
- catch { }
209
+ for (const token of walletTokens) {
210
+ if (!isTokenContentUnlocked(token)) {
211
+ try {
212
+ await unlockTokenContent(token, signer);
202
213
  }
214
+ catch { }
203
215
  }
204
216
  }
205
217
  // Collect all proofs from wallet tokens
@@ -247,7 +259,7 @@ export function RecoverFromCouch(couch) {
247
259
  proofs: unspentProofs,
248
260
  unit: tokens[0]?.unit,
249
261
  };
250
- const tokenEvent = await factory.create(WalletTokenBlueprint, recoveredToken).then(sign);
262
+ const tokenEvent = await WalletTokenFactory.create(recoveredToken).sign(signer);
251
263
  // Publish the token event
252
264
  await publish(tokenEvent, wallet.relays);
253
265
  // Clear the token from the couch
@@ -1,33 +1,31 @@
1
- import { WalletBackupBlueprint, WalletBlueprint } from "../blueprints/wallet.js";
1
+ import { WalletBackupFactory, WalletFactory } from "../factories/wallet.js";
2
+ import { NutzapInfoFactory } from "../factories/nutzap-info.js";
2
3
  import { unlockHistoryContent, WALLET_HISTORY_KIND } from "../helpers/history.js";
3
4
  import { NUTZAP_INFO_KIND } from "../helpers/nutzap-info.js";
4
5
  import { unlockTokenContent, WALLET_TOKEN_KIND } from "../helpers/tokens.js";
5
6
  import { getWalletMints, unlockWallet, WALLET_KIND } from "../helpers/wallet.js";
6
- import { setNutzapInfoPubkey } from "../operations/nutzap-info.js";
7
- import { setMints, setRelays } from "../operations/wallet.js";
8
7
  import { getUnlockedWallet } from "./common.js";
9
8
  // Make sure the wallet$ is registered on the user class
10
9
  import "../casts/__register__.js";
11
10
  /** An action that creates a new 17375 wallet event and 375 wallet backup */
12
11
  export function CreateWallet({ mints, privateKey, relays, }) {
13
- return async ({ events, factory, self, publish }) => {
12
+ return async ({ events, signer, self, publish }) => {
14
13
  if (mints.length === 0)
15
14
  throw new Error("At least one mint is required");
16
15
  const existing = events.getReplaceable(WALLET_KIND, self);
17
16
  if (existing)
18
17
  throw new Error("Wallet already exists");
19
18
  // Create new wallet event
20
- const wallet = await factory.sign(await factory.create(WalletBlueprint, { mints, privateKey, relays }));
19
+ const wallet = await WalletFactory.create(mints, privateKey, relays).sign(signer);
21
20
  // Setup nutzap info event
22
21
  if (privateKey) {
23
22
  // Create a backup event if a private key is provided
24
- const backup = await factory.sign(await factory.create(WalletBackupBlueprint, wallet));
23
+ const backup = await WalletBackupFactory.create(wallet).sign(signer);
25
24
  const nutzapInfo = events.getReplaceable(NUTZAP_INFO_KIND, self);
26
25
  // Always set pubkey if private key is provided (create or update)
27
- const nutzapInfoDraft = nutzapInfo
28
- ? await factory.modify(nutzapInfo, setNutzapInfoPubkey(privateKey))
29
- : await factory.build({ kind: NUTZAP_INFO_KIND }, setNutzapInfoPubkey(privateKey));
30
- const info = await factory.sign(nutzapInfoDraft);
26
+ const info = nutzapInfo
27
+ ? await NutzapInfoFactory.modify(nutzapInfo).setPubkey(privateKey).sign(signer)
28
+ : await NutzapInfoFactory.create().setPubkey(privateKey).sign(signer);
31
29
  // Publish all events at the same time
32
30
  await publish([wallet, backup, info], relays);
33
31
  }
@@ -42,30 +40,25 @@ export function CreateWallet({ mints, privateKey, relays, }) {
42
40
  * @throws if the wallet does not exist or cannot be unlocked
43
41
  */
44
42
  export function WalletAddPrivateKey(privateKey, override = false) {
45
- return async ({ events, self, factory, user, signer, sign, publish }) => {
43
+ return async ({ events, self, signer, user, publish }) => {
46
44
  const wallet = await getUnlockedWallet(user, signer);
47
45
  if (wallet.privateKey && override !== true)
48
46
  throw new Error("Wallet already has a private key");
49
- const signed = await factory
50
- .create(WalletBlueprint, { mints: getWalletMints(wallet.event), privateKey })
51
- .then(sign);
47
+ const signed = await WalletFactory.create(getWalletMints(wallet.event), privateKey).as(signer).sign();
52
48
  // create backup event for wallet
53
- const backup = await factory.create(WalletBackupBlueprint, signed).then(sign);
49
+ const backup = await WalletBackupFactory.create(signed).sign(signer);
54
50
  // set nutzap info pubkey for receiving nutzaps
55
51
  const nutzapInfo = events.getReplaceable(NUTZAP_INFO_KIND, self);
56
52
  const info = nutzapInfo
57
- ? await factory.modify(nutzapInfo, setNutzapInfoPubkey(privateKey)).then(sign)
58
- : await factory.build({ kind: NUTZAP_INFO_KIND }, setNutzapInfoPubkey(privateKey)).then(sign);
53
+ ? await NutzapInfoFactory.modify(nutzapInfo).setPubkey(privateKey).sign(signer)
54
+ : await NutzapInfoFactory.create().setPubkey(privateKey).sign(signer);
59
55
  // publish all events at the same time
60
56
  await publish([signed, backup, info], wallet.relays);
61
57
  };
62
58
  }
63
59
  /** Unlocks the wallet event and optionally the tokens and history events */
64
60
  export function UnlockWallet(unlock) {
65
- return async ({ events, self, factory }) => {
66
- const signer = factory.context.signer;
67
- if (!signer)
68
- throw new Error("Missing signer");
61
+ return async ({ events, self, signer }) => {
69
62
  const wallet = events.getReplaceable(WALLET_KIND, self);
70
63
  if (!wallet)
71
64
  throw new Error("Wallet does not exist");
@@ -87,9 +80,9 @@ export function UnlockWallet(unlock) {
87
80
  * @throws if the wallet does not exist or cannot be unlocked
88
81
  */
89
82
  export function SetWalletMints(mints) {
90
- return async ({ user, signer, factory, sign, publish }) => {
83
+ return async ({ user, signer, publish }) => {
91
84
  const wallet = await getUnlockedWallet(user, signer);
92
- const signed = await factory.modify(wallet.event, setMints(mints)).then(sign);
85
+ const signed = await WalletFactory.modify(wallet.event).mints(mints).sign(signer);
93
86
  await publish(signed, wallet.relays);
94
87
  };
95
88
  }
@@ -98,9 +91,9 @@ export function SetWalletMints(mints) {
98
91
  * @throws if the wallet does not exist or cannot be unlocked
99
92
  */
100
93
  export function SetWalletRelays(relays) {
101
- return async ({ user, signer, factory, sign, publish }) => {
94
+ return async ({ user, signer, publish }) => {
102
95
  const wallet = await getUnlockedWallet(user, signer);
103
- const signed = await factory.modify(wallet.event, setRelays(relays)).then(sign);
96
+ const signed = await WalletFactory.modify(wallet.event).relays(relays.map(String)).sign(signer);
104
97
  await publish(signed, relays.map(String));
105
98
  };
106
99
  }
@@ -3,7 +3,7 @@ import { NutzapInfo } from "./nutzap-info.js";
3
3
  import { Nutzap } from "./nutzap.js";
4
4
  import { Wallet } from "./wallet.js";
5
5
  import { MintRecommendation } from "./mint-recommendation.js";
6
- declare module "applesauce-common/casts/user" {
6
+ declare module "applesauce-core/casts" {
7
7
  interface User {
8
8
  readonly wallet$: ChainableObservable<Wallet | undefined>;
9
9
  readonly nutzap$: ChainableObservable<NutzapInfo | undefined>;
@@ -1,5 +1,5 @@
1
1
  import { Note, Stream } from "applesauce-common/casts";
2
- import { User } from "applesauce-common/casts/user";
2
+ import { User } from "applesauce-core/casts";
3
3
  import { castEventStream, castTimelineStream } from "applesauce-common/observable";
4
4
  import { buildCommonEventRelationFilters } from "applesauce-core/helpers";
5
5
  import { switchMap } from "rxjs";
@@ -2,6 +2,7 @@ import { CastRefEventStore, EventCast } from "applesauce-common/casts";
2
2
  import { NostrEvent } from "applesauce-core/helpers/event";
3
3
  import { CashuMintInfoEvent } from "../helpers/mint-info.js";
4
4
  import { MintRecommendation } from "./mint-recommendation.js";
5
+ /** A cast for a NIP-87 cashu mint info event */
5
6
  export declare class MintInfo extends EventCast<CashuMintInfoEvent> {
6
7
  constructor(event: NostrEvent, store: CastRefEventStore);
7
8
  /** The mint's pubkey (from the `d` tag) */
@@ -3,10 +3,12 @@ import { castTimelineStream } from "applesauce-common/observable";
3
3
  import { getCashuMintMetadata, getCashuMintNetwork, getCashuMintNuts, getCashuMintPubkey, getCashuMintURL, isValidCashuMintInfo, } from "../helpers/mint-info.js";
4
4
  import { MINT_RECOMMENDATION_KIND } from "../helpers/mint-recommendation.js";
5
5
  import { MintRecommendation } from "./mint-recommendation.js";
6
+ /** A cast for a NIP-87 cashu mint info event */
6
7
  export class MintInfo extends EventCast {
7
8
  constructor(event, store) {
8
- if (!isValidCashuMintInfo(event))
9
+ if (!isValidCashuMintInfo(event)) {
9
10
  throw new Error("Invalid cashu mint info event");
11
+ }
10
12
  super(event, store);
11
13
  }
12
14
  /** The mint's pubkey (from the `d` tag) */