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