@routstr/sdk 0.1.7 → 0.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/client/index.js +140 -44
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +140 -44
- package/dist/client/index.mjs.map +1 -1
- package/dist/discovery/index.d.mts +2 -1
- package/dist/discovery/index.d.ts +2 -1
- package/dist/discovery/index.js +9 -1
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/index.mjs +9 -1
- package/dist/discovery/index.mjs.map +1 -1
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +344 -178
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +344 -178
- package/dist/index.mjs.map +1 -1
- package/dist/storage/index.d.mts +52 -1
- package/dist/storage/index.d.ts +52 -1
- package/dist/storage/index.js +192 -131
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/index.mjs +192 -131
- package/dist/storage/index.mjs.map +1 -1
- package/dist/wallet/index.d.mts +7 -1
- package/dist/wallet/index.d.ts +7 -1
- package/dist/wallet/index.js +110 -41
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +110 -41
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/wallet/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// core/errors.ts
|
|
2
2
|
var InsufficientBalanceError = class extends Error {
|
|
3
|
-
constructor(required, available, maxMintBalance = 0, maxMintUrl = "") {
|
|
3
|
+
constructor(required, available, maxMintBalance = 0, maxMintUrl = "", customMessage) {
|
|
4
4
|
super(
|
|
5
|
-
`Insufficient balance: need ${required} sats, have ${available} sats available. ` + (maxMintBalance > 0 ? `Largest mint balance: ${maxMintBalance} sats from ${maxMintUrl}` : "")
|
|
5
|
+
customMessage ?? `Insufficient balance: need ${required} sats, have ${available} sats available. ` + (maxMintBalance > 0 ? `Largest mint balance: ${maxMintBalance} sats from ${maxMintUrl}` : "")
|
|
6
6
|
);
|
|
7
7
|
this.required = required;
|
|
8
8
|
this.available = available;
|
|
@@ -106,6 +106,9 @@ var CashuSpender = class {
|
|
|
106
106
|
return result;
|
|
107
107
|
}
|
|
108
108
|
async _getBalanceState() {
|
|
109
|
+
if (this.balanceManager) {
|
|
110
|
+
return this.balanceManager.getBalanceState();
|
|
111
|
+
}
|
|
109
112
|
const mintBalances = await this.walletAdapter.getBalances();
|
|
110
113
|
const units = this.walletAdapter.getMintUnits();
|
|
111
114
|
let totalMintBalance = 0;
|
|
@@ -121,15 +124,16 @@ var CashuSpender = class {
|
|
|
121
124
|
const providerBalances = {};
|
|
122
125
|
let totalProviderBalance = 0;
|
|
123
126
|
for (const pending of pendingDistribution) {
|
|
124
|
-
providerBalances[pending.baseUrl] = pending.amount;
|
|
127
|
+
providerBalances[pending.baseUrl] = (providerBalances[pending.baseUrl] || 0) + pending.amount;
|
|
125
128
|
totalProviderBalance += pending.amount;
|
|
126
129
|
}
|
|
127
130
|
const apiKeys = this.storageAdapter.getAllApiKeys();
|
|
128
131
|
for (const apiKey of apiKeys) {
|
|
129
132
|
if (!providerBalances[apiKey.baseUrl]) {
|
|
130
|
-
providerBalances[apiKey.baseUrl] =
|
|
131
|
-
totalProviderBalance += apiKey.balance;
|
|
133
|
+
providerBalances[apiKey.baseUrl] = 0;
|
|
132
134
|
}
|
|
135
|
+
providerBalances[apiKey.baseUrl] += apiKey.balance;
|
|
136
|
+
totalProviderBalance += apiKey.balance;
|
|
133
137
|
}
|
|
134
138
|
return {
|
|
135
139
|
totalBalance: totalMintBalance + totalProviderBalance,
|
|
@@ -278,25 +282,12 @@ var CashuSpender = class {
|
|
|
278
282
|
`[CashuSpender] _spendInternal: Could not reuse token, will create new token`
|
|
279
283
|
);
|
|
280
284
|
}
|
|
281
|
-
const
|
|
282
|
-
const
|
|
283
|
-
let totalBalance = 0;
|
|
284
|
-
for (const url in balances) {
|
|
285
|
-
const balance = balances[url];
|
|
286
|
-
const unit = units[url];
|
|
287
|
-
const balanceInSats = getBalanceInSats(balance, unit);
|
|
288
|
-
totalBalance += balanceInSats;
|
|
289
|
-
}
|
|
290
|
-
const pendingDistribution = this.storageAdapter.getCachedTokenDistribution();
|
|
291
|
-
const totalPending = pendingDistribution.reduce(
|
|
292
|
-
(sum, item) => sum + item.amount,
|
|
293
|
-
0
|
|
294
|
-
);
|
|
285
|
+
const balanceState = await this._getBalanceState();
|
|
286
|
+
const totalAvailableBalance = balanceState.totalBalance;
|
|
295
287
|
this._log(
|
|
296
288
|
"DEBUG",
|
|
297
|
-
`[CashuSpender] _spendInternal:
|
|
289
|
+
`[CashuSpender] _spendInternal: totalAvailableBalance=${totalAvailableBalance}, adjustedAmount=${adjustedAmount}`
|
|
298
290
|
);
|
|
299
|
-
const totalAvailableBalance = totalBalance + totalPending;
|
|
300
291
|
if (totalAvailableBalance < adjustedAmount) {
|
|
301
292
|
this._log(
|
|
302
293
|
"ERROR",
|
|
@@ -304,8 +295,7 @@ var CashuSpender = class {
|
|
|
304
295
|
);
|
|
305
296
|
return this._createInsufficientBalanceError(
|
|
306
297
|
adjustedAmount,
|
|
307
|
-
|
|
308
|
-
units,
|
|
298
|
+
balanceState.mintBalances,
|
|
309
299
|
totalAvailableBalance
|
|
310
300
|
);
|
|
311
301
|
}
|
|
@@ -325,8 +315,7 @@ var CashuSpender = class {
|
|
|
325
315
|
if ((tokenResult.error || "").includes("Insufficient balance")) {
|
|
326
316
|
return this._createInsufficientBalanceError(
|
|
327
317
|
adjustedAmount,
|
|
328
|
-
|
|
329
|
-
units,
|
|
318
|
+
balanceState.mintBalances,
|
|
330
319
|
totalAvailableBalance
|
|
331
320
|
);
|
|
332
321
|
}
|
|
@@ -371,6 +360,7 @@ var CashuSpender = class {
|
|
|
371
360
|
"DEBUG",
|
|
372
361
|
`[CashuSpender] _spendInternal: Successfully spent ${spentAmount}, returning token with balance=${spentAmount}`
|
|
373
362
|
);
|
|
363
|
+
const units = this.walletAdapter.getMintUnits();
|
|
374
364
|
return {
|
|
375
365
|
token,
|
|
376
366
|
status: "success",
|
|
@@ -508,13 +498,11 @@ var CashuSpender = class {
|
|
|
508
498
|
/**
|
|
509
499
|
* Create an insufficient balance error result
|
|
510
500
|
*/
|
|
511
|
-
_createInsufficientBalanceError(required,
|
|
501
|
+
_createInsufficientBalanceError(required, normalizedBalances, availableBalance) {
|
|
512
502
|
let maxBalance = 0;
|
|
513
503
|
let maxMintUrl = "";
|
|
514
|
-
for (const mintUrl in
|
|
515
|
-
const
|
|
516
|
-
const unit = units[mintUrl];
|
|
517
|
-
const balanceInSats = getBalanceInSats(balance, unit);
|
|
504
|
+
for (const mintUrl in normalizedBalances) {
|
|
505
|
+
const balanceInSats = normalizedBalances[mintUrl];
|
|
518
506
|
if (balanceInSats > maxBalance) {
|
|
519
507
|
maxBalance = balanceInSats;
|
|
520
508
|
maxMintUrl = mintUrl;
|
|
@@ -575,6 +563,39 @@ var BalanceManager = class {
|
|
|
575
563
|
}
|
|
576
564
|
}
|
|
577
565
|
cashuSpender;
|
|
566
|
+
async getBalanceState() {
|
|
567
|
+
const mintBalances = await this.walletAdapter.getBalances();
|
|
568
|
+
const units = this.walletAdapter.getMintUnits();
|
|
569
|
+
let totalMintBalance = 0;
|
|
570
|
+
const normalizedMintBalances = {};
|
|
571
|
+
for (const url in mintBalances) {
|
|
572
|
+
const balance = mintBalances[url];
|
|
573
|
+
const unit = units[url];
|
|
574
|
+
const balanceInSats = getBalanceInSats(balance, unit);
|
|
575
|
+
normalizedMintBalances[url] = balanceInSats;
|
|
576
|
+
totalMintBalance += balanceInSats;
|
|
577
|
+
}
|
|
578
|
+
const pendingDistribution = this.storageAdapter.getCachedTokenDistribution();
|
|
579
|
+
const providerBalances = {};
|
|
580
|
+
let totalProviderBalance = 0;
|
|
581
|
+
for (const pending of pendingDistribution) {
|
|
582
|
+
providerBalances[pending.baseUrl] = (providerBalances[pending.baseUrl] || 0) + pending.amount;
|
|
583
|
+
totalProviderBalance += pending.amount;
|
|
584
|
+
}
|
|
585
|
+
const apiKeys = this.storageAdapter.getAllApiKeys();
|
|
586
|
+
for (const apiKey of apiKeys) {
|
|
587
|
+
if (!providerBalances[apiKey.baseUrl]) {
|
|
588
|
+
providerBalances[apiKey.baseUrl] = 0;
|
|
589
|
+
}
|
|
590
|
+
providerBalances[apiKey.baseUrl] += apiKey.balance;
|
|
591
|
+
totalProviderBalance += apiKey.balance;
|
|
592
|
+
}
|
|
593
|
+
return {
|
|
594
|
+
totalBalance: totalMintBalance + totalProviderBalance,
|
|
595
|
+
providerBalances,
|
|
596
|
+
mintBalances: normalizedMintBalances
|
|
597
|
+
};
|
|
598
|
+
}
|
|
578
599
|
/**
|
|
579
600
|
* Unified refund - handles both NIP-60 and legacy wallet refunds
|
|
580
601
|
*/
|
|
@@ -785,6 +806,10 @@ var BalanceManager = class {
|
|
|
785
806
|
requestId
|
|
786
807
|
};
|
|
787
808
|
} catch (error) {
|
|
809
|
+
console.log(
|
|
810
|
+
"DEBUG",
|
|
811
|
+
`[TopuPU] topup: Topup result for ${baseUrl}: error=${error}`
|
|
812
|
+
);
|
|
788
813
|
if (cashuToken) {
|
|
789
814
|
await this._recoverFailedTopUp(cashuToken);
|
|
790
815
|
}
|
|
@@ -804,23 +829,42 @@ var BalanceManager = class {
|
|
|
804
829
|
if (!adjustedAmount || isNaN(adjustedAmount)) {
|
|
805
830
|
return { success: false, error: "Invalid top up amount" };
|
|
806
831
|
}
|
|
832
|
+
const balanceState = await this.getBalanceState();
|
|
807
833
|
const balances = await this.walletAdapter.getBalances();
|
|
808
834
|
const units = this.walletAdapter.getMintUnits();
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
if (totalMintBalance < adjustedAmount && totalMintBalance +
|
|
835
|
+
const totalMintBalance = Object.values(balanceState.mintBalances).reduce(
|
|
836
|
+
(sum, value) => sum + value,
|
|
837
|
+
0
|
|
838
|
+
);
|
|
839
|
+
const targetProviderBalance = balanceState.providerBalances[baseUrl] || 0;
|
|
840
|
+
const refundableProviderBalance = Object.entries(
|
|
841
|
+
balanceState.providerBalances
|
|
842
|
+
).filter(([providerBaseUrl]) => providerBaseUrl !== baseUrl).reduce((sum, [, value]) => sum + value, 0);
|
|
843
|
+
if (totalMintBalance + targetProviderBalance < adjustedAmount && totalMintBalance + targetProviderBalance + refundableProviderBalance >= adjustedAmount && retryCount < 1) {
|
|
818
844
|
await this._refundOtherProvidersForTopUp(baseUrl, mintUrl);
|
|
819
845
|
return this.createProviderToken({
|
|
820
846
|
...options,
|
|
821
847
|
retryCount: retryCount + 1
|
|
822
848
|
});
|
|
823
849
|
}
|
|
850
|
+
if (totalMintBalance + targetProviderBalance < adjustedAmount) {
|
|
851
|
+
const error = new InsufficientBalanceError(
|
|
852
|
+
adjustedAmount,
|
|
853
|
+
totalMintBalance + targetProviderBalance,
|
|
854
|
+
totalMintBalance,
|
|
855
|
+
Object.entries(balanceState.mintBalances).reduce(
|
|
856
|
+
(max, [url, balance]) => balance > max.balance ? { url, balance } : max,
|
|
857
|
+
{ url: "", balance: 0 }
|
|
858
|
+
).url
|
|
859
|
+
);
|
|
860
|
+
return { success: false, error: error.message };
|
|
861
|
+
}
|
|
862
|
+
if (targetProviderBalance >= adjustedAmount) {
|
|
863
|
+
return {
|
|
864
|
+
success: true,
|
|
865
|
+
amountSpent: 0
|
|
866
|
+
};
|
|
867
|
+
}
|
|
824
868
|
const providerMints = baseUrl && this.providerRegistry ? this.providerRegistry.getProviderMints(baseUrl) : [];
|
|
825
869
|
let requiredAmount = adjustedAmount;
|
|
826
870
|
const supportedMintsOnly = providerMints.length > 0;
|
|
@@ -936,10 +980,14 @@ var BalanceManager = class {
|
|
|
936
980
|
}
|
|
937
981
|
async _refundOtherProvidersForTopUp(baseUrl, mintUrl) {
|
|
938
982
|
const pendingDistribution = this.storageAdapter.getCachedTokenDistribution();
|
|
983
|
+
const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
|
|
939
984
|
const toRefund = pendingDistribution.filter(
|
|
940
985
|
(pending) => pending.baseUrl !== baseUrl
|
|
941
986
|
);
|
|
942
|
-
const
|
|
987
|
+
const apiKeysToRefund = apiKeyDistribution.filter(
|
|
988
|
+
(apiKey) => apiKey.baseUrl !== baseUrl && apiKey.amount > 0
|
|
989
|
+
);
|
|
990
|
+
const tokenRefundResults = await Promise.allSettled(
|
|
943
991
|
toRefund.map(async (pending) => {
|
|
944
992
|
const token = this.storageAdapter.getToken(pending.baseUrl);
|
|
945
993
|
if (!token) {
|
|
@@ -957,11 +1005,32 @@ var BalanceManager = class {
|
|
|
957
1005
|
return { baseUrl: pending.baseUrl, success: result.success };
|
|
958
1006
|
})
|
|
959
1007
|
);
|
|
960
|
-
for (const result of
|
|
1008
|
+
for (const result of tokenRefundResults) {
|
|
961
1009
|
if (result.status === "fulfilled" && result.value.success) {
|
|
962
1010
|
this.storageAdapter.removeToken(result.value.baseUrl);
|
|
963
1011
|
}
|
|
964
1012
|
}
|
|
1013
|
+
const apiKeyRefundResults = await Promise.allSettled(
|
|
1014
|
+
apiKeysToRefund.map(async (apiKeyEntry) => {
|
|
1015
|
+
const fullApiKeyEntry = this.storageAdapter.getApiKey(
|
|
1016
|
+
apiKeyEntry.baseUrl
|
|
1017
|
+
);
|
|
1018
|
+
if (!fullApiKeyEntry) {
|
|
1019
|
+
return { baseUrl: apiKeyEntry.baseUrl, success: false };
|
|
1020
|
+
}
|
|
1021
|
+
const result = await this.refundApiKey({
|
|
1022
|
+
mintUrl,
|
|
1023
|
+
baseUrl: apiKeyEntry.baseUrl,
|
|
1024
|
+
apiKey: fullApiKeyEntry.key
|
|
1025
|
+
});
|
|
1026
|
+
return { baseUrl: apiKeyEntry.baseUrl, success: result.success };
|
|
1027
|
+
})
|
|
1028
|
+
);
|
|
1029
|
+
for (const result of apiKeyRefundResults) {
|
|
1030
|
+
if (result.status === "fulfilled" && result.value.success) {
|
|
1031
|
+
this.storageAdapter.updateApiKeyBalance(result.value.baseUrl, 0);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
965
1034
|
}
|
|
966
1035
|
/**
|
|
967
1036
|
* Fetch refund token from provider API
|