@routstr/sdk 0.1.7 → 0.1.8
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 +114 -41
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +114 -41
- package/dist/client/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +126 -44
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +126 -44
- package/dist/index.mjs.map +1 -1
- package/dist/storage/index.d.mts +31 -0
- package/dist/storage/index.d.ts +31 -0
- package/dist/storage/index.js +12 -3
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/index.mjs +12 -3
- 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 +85 -39
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +85 -39
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/client/index.js
CHANGED
|
@@ -129,6 +129,9 @@ var CashuSpender = class {
|
|
|
129
129
|
return result;
|
|
130
130
|
}
|
|
131
131
|
async _getBalanceState() {
|
|
132
|
+
if (this.balanceManager) {
|
|
133
|
+
return this.balanceManager.getBalanceState();
|
|
134
|
+
}
|
|
132
135
|
const mintBalances = await this.walletAdapter.getBalances();
|
|
133
136
|
const units = this.walletAdapter.getMintUnits();
|
|
134
137
|
let totalMintBalance = 0;
|
|
@@ -144,15 +147,16 @@ var CashuSpender = class {
|
|
|
144
147
|
const providerBalances = {};
|
|
145
148
|
let totalProviderBalance = 0;
|
|
146
149
|
for (const pending of pendingDistribution) {
|
|
147
|
-
providerBalances[pending.baseUrl] = pending.amount;
|
|
150
|
+
providerBalances[pending.baseUrl] = (providerBalances[pending.baseUrl] || 0) + pending.amount;
|
|
148
151
|
totalProviderBalance += pending.amount;
|
|
149
152
|
}
|
|
150
153
|
const apiKeys = this.storageAdapter.getAllApiKeys();
|
|
151
154
|
for (const apiKey of apiKeys) {
|
|
152
155
|
if (!providerBalances[apiKey.baseUrl]) {
|
|
153
|
-
providerBalances[apiKey.baseUrl] =
|
|
154
|
-
totalProviderBalance += apiKey.balance;
|
|
156
|
+
providerBalances[apiKey.baseUrl] = 0;
|
|
155
157
|
}
|
|
158
|
+
providerBalances[apiKey.baseUrl] += apiKey.balance;
|
|
159
|
+
totalProviderBalance += apiKey.balance;
|
|
156
160
|
}
|
|
157
161
|
return {
|
|
158
162
|
totalBalance: totalMintBalance + totalProviderBalance,
|
|
@@ -301,25 +305,12 @@ var CashuSpender = class {
|
|
|
301
305
|
`[CashuSpender] _spendInternal: Could not reuse token, will create new token`
|
|
302
306
|
);
|
|
303
307
|
}
|
|
304
|
-
const
|
|
305
|
-
const
|
|
306
|
-
let totalBalance = 0;
|
|
307
|
-
for (const url in balances) {
|
|
308
|
-
const balance = balances[url];
|
|
309
|
-
const unit = units[url];
|
|
310
|
-
const balanceInSats = getBalanceInSats(balance, unit);
|
|
311
|
-
totalBalance += balanceInSats;
|
|
312
|
-
}
|
|
313
|
-
const pendingDistribution = this.storageAdapter.getCachedTokenDistribution();
|
|
314
|
-
const totalPending = pendingDistribution.reduce(
|
|
315
|
-
(sum, item) => sum + item.amount,
|
|
316
|
-
0
|
|
317
|
-
);
|
|
308
|
+
const balanceState = await this._getBalanceState();
|
|
309
|
+
const totalAvailableBalance = balanceState.totalBalance;
|
|
318
310
|
this._log(
|
|
319
311
|
"DEBUG",
|
|
320
|
-
`[CashuSpender] _spendInternal:
|
|
312
|
+
`[CashuSpender] _spendInternal: totalAvailableBalance=${totalAvailableBalance}, adjustedAmount=${adjustedAmount}`
|
|
321
313
|
);
|
|
322
|
-
const totalAvailableBalance = totalBalance + totalPending;
|
|
323
314
|
if (totalAvailableBalance < adjustedAmount) {
|
|
324
315
|
this._log(
|
|
325
316
|
"ERROR",
|
|
@@ -327,8 +318,7 @@ var CashuSpender = class {
|
|
|
327
318
|
);
|
|
328
319
|
return this._createInsufficientBalanceError(
|
|
329
320
|
adjustedAmount,
|
|
330
|
-
|
|
331
|
-
units,
|
|
321
|
+
balanceState.mintBalances,
|
|
332
322
|
totalAvailableBalance
|
|
333
323
|
);
|
|
334
324
|
}
|
|
@@ -348,8 +338,7 @@ var CashuSpender = class {
|
|
|
348
338
|
if ((tokenResult.error || "").includes("Insufficient balance")) {
|
|
349
339
|
return this._createInsufficientBalanceError(
|
|
350
340
|
adjustedAmount,
|
|
351
|
-
|
|
352
|
-
units,
|
|
341
|
+
balanceState.mintBalances,
|
|
353
342
|
totalAvailableBalance
|
|
354
343
|
);
|
|
355
344
|
}
|
|
@@ -394,6 +383,7 @@ var CashuSpender = class {
|
|
|
394
383
|
"DEBUG",
|
|
395
384
|
`[CashuSpender] _spendInternal: Successfully spent ${spentAmount}, returning token with balance=${spentAmount}`
|
|
396
385
|
);
|
|
386
|
+
const units = this.walletAdapter.getMintUnits();
|
|
397
387
|
return {
|
|
398
388
|
token,
|
|
399
389
|
status: "success",
|
|
@@ -531,13 +521,11 @@ var CashuSpender = class {
|
|
|
531
521
|
/**
|
|
532
522
|
* Create an insufficient balance error result
|
|
533
523
|
*/
|
|
534
|
-
_createInsufficientBalanceError(required,
|
|
524
|
+
_createInsufficientBalanceError(required, normalizedBalances, availableBalance) {
|
|
535
525
|
let maxBalance = 0;
|
|
536
526
|
let maxMintUrl = "";
|
|
537
|
-
for (const mintUrl in
|
|
538
|
-
const
|
|
539
|
-
const unit = units[mintUrl];
|
|
540
|
-
const balanceInSats = getBalanceInSats(balance, unit);
|
|
527
|
+
for (const mintUrl in normalizedBalances) {
|
|
528
|
+
const balanceInSats = normalizedBalances[mintUrl];
|
|
541
529
|
if (balanceInSats > maxBalance) {
|
|
542
530
|
maxBalance = balanceInSats;
|
|
543
531
|
maxMintUrl = mintUrl;
|
|
@@ -598,6 +586,39 @@ var BalanceManager = class {
|
|
|
598
586
|
}
|
|
599
587
|
}
|
|
600
588
|
cashuSpender;
|
|
589
|
+
async getBalanceState() {
|
|
590
|
+
const mintBalances = await this.walletAdapter.getBalances();
|
|
591
|
+
const units = this.walletAdapter.getMintUnits();
|
|
592
|
+
let totalMintBalance = 0;
|
|
593
|
+
const normalizedMintBalances = {};
|
|
594
|
+
for (const url in mintBalances) {
|
|
595
|
+
const balance = mintBalances[url];
|
|
596
|
+
const unit = units[url];
|
|
597
|
+
const balanceInSats = getBalanceInSats(balance, unit);
|
|
598
|
+
normalizedMintBalances[url] = balanceInSats;
|
|
599
|
+
totalMintBalance += balanceInSats;
|
|
600
|
+
}
|
|
601
|
+
const pendingDistribution = this.storageAdapter.getCachedTokenDistribution();
|
|
602
|
+
const providerBalances = {};
|
|
603
|
+
let totalProviderBalance = 0;
|
|
604
|
+
for (const pending of pendingDistribution) {
|
|
605
|
+
providerBalances[pending.baseUrl] = (providerBalances[pending.baseUrl] || 0) + pending.amount;
|
|
606
|
+
totalProviderBalance += pending.amount;
|
|
607
|
+
}
|
|
608
|
+
const apiKeys = this.storageAdapter.getAllApiKeys();
|
|
609
|
+
for (const apiKey of apiKeys) {
|
|
610
|
+
if (!providerBalances[apiKey.baseUrl]) {
|
|
611
|
+
providerBalances[apiKey.baseUrl] = 0;
|
|
612
|
+
}
|
|
613
|
+
providerBalances[apiKey.baseUrl] += apiKey.balance;
|
|
614
|
+
totalProviderBalance += apiKey.balance;
|
|
615
|
+
}
|
|
616
|
+
return {
|
|
617
|
+
totalBalance: totalMintBalance + totalProviderBalance,
|
|
618
|
+
providerBalances,
|
|
619
|
+
mintBalances: normalizedMintBalances
|
|
620
|
+
};
|
|
621
|
+
}
|
|
601
622
|
/**
|
|
602
623
|
* Unified refund - handles both NIP-60 and legacy wallet refunds
|
|
603
624
|
*/
|
|
@@ -827,17 +848,17 @@ var BalanceManager = class {
|
|
|
827
848
|
if (!adjustedAmount || isNaN(adjustedAmount)) {
|
|
828
849
|
return { success: false, error: "Invalid top up amount" };
|
|
829
850
|
}
|
|
851
|
+
const balanceState = await this.getBalanceState();
|
|
830
852
|
const balances = await this.walletAdapter.getBalances();
|
|
831
853
|
const units = this.walletAdapter.getMintUnits();
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
if (totalMintBalance < adjustedAmount && totalMintBalance + refundablePending >= adjustedAmount && retryCount < 1) {
|
|
854
|
+
const totalMintBalance = Object.values(balanceState.mintBalances).reduce(
|
|
855
|
+
(sum, value) => sum + value,
|
|
856
|
+
0
|
|
857
|
+
);
|
|
858
|
+
const refundableProviderBalance = Object.entries(
|
|
859
|
+
balanceState.providerBalances
|
|
860
|
+
).filter(([providerBaseUrl]) => providerBaseUrl !== baseUrl).reduce((sum, [, value]) => sum + value, 0);
|
|
861
|
+
if (totalMintBalance < adjustedAmount && totalMintBalance + refundableProviderBalance >= adjustedAmount && retryCount < 1) {
|
|
841
862
|
await this._refundOtherProvidersForTopUp(baseUrl, mintUrl);
|
|
842
863
|
return this.createProviderToken({
|
|
843
864
|
...options,
|
|
@@ -959,10 +980,14 @@ var BalanceManager = class {
|
|
|
959
980
|
}
|
|
960
981
|
async _refundOtherProvidersForTopUp(baseUrl, mintUrl) {
|
|
961
982
|
const pendingDistribution = this.storageAdapter.getCachedTokenDistribution();
|
|
983
|
+
const apiKeyDistribution = this.storageAdapter.getApiKeyDistribution();
|
|
962
984
|
const toRefund = pendingDistribution.filter(
|
|
963
985
|
(pending) => pending.baseUrl !== baseUrl
|
|
964
986
|
);
|
|
965
|
-
const
|
|
987
|
+
const apiKeysToRefund = apiKeyDistribution.filter(
|
|
988
|
+
(apiKey) => apiKey.baseUrl !== baseUrl && apiKey.amount > 0
|
|
989
|
+
);
|
|
990
|
+
const tokenRefundResults = await Promise.allSettled(
|
|
966
991
|
toRefund.map(async (pending) => {
|
|
967
992
|
const token = this.storageAdapter.getToken(pending.baseUrl);
|
|
968
993
|
if (!token) {
|
|
@@ -980,11 +1005,32 @@ var BalanceManager = class {
|
|
|
980
1005
|
return { baseUrl: pending.baseUrl, success: result.success };
|
|
981
1006
|
})
|
|
982
1007
|
);
|
|
983
|
-
for (const result of
|
|
1008
|
+
for (const result of tokenRefundResults) {
|
|
984
1009
|
if (result.status === "fulfilled" && result.value.success) {
|
|
985
1010
|
this.storageAdapter.removeToken(result.value.baseUrl);
|
|
986
1011
|
}
|
|
987
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
|
+
}
|
|
988
1034
|
}
|
|
989
1035
|
/**
|
|
990
1036
|
* Fetch refund token from provider API
|
|
@@ -2179,10 +2225,34 @@ var RoutstrClient = class {
|
|
|
2179
2225
|
}
|
|
2180
2226
|
}
|
|
2181
2227
|
if (status === 402 && !tryNextProvider && (this.mode === "apikeys" || this.mode === "lazyrefund")) {
|
|
2228
|
+
this.storageAdapter.getApiKey(baseUrl);
|
|
2229
|
+
let topupAmount = params.requiredSats;
|
|
2230
|
+
try {
|
|
2231
|
+
let currentBalance = 0;
|
|
2232
|
+
if (this.mode === "apikeys") {
|
|
2233
|
+
const currentBalanceInfo = await this.balanceManager.getTokenBalance(
|
|
2234
|
+
params.token,
|
|
2235
|
+
baseUrl
|
|
2236
|
+
);
|
|
2237
|
+
currentBalance = currentBalanceInfo.unit === "msat" ? currentBalanceInfo.amount / 1e3 : currentBalanceInfo.amount;
|
|
2238
|
+
} else if (this.mode === "lazyrefund") {
|
|
2239
|
+
const distribution = this.storageAdapter.getCachedTokenDistribution();
|
|
2240
|
+
const tokenEntry = distribution.find((t) => t.baseUrl === baseUrl);
|
|
2241
|
+
currentBalance = tokenEntry?.amount ?? 0;
|
|
2242
|
+
}
|
|
2243
|
+
const shortfall = Math.max(0, params.requiredSats - currentBalance);
|
|
2244
|
+
topupAmount = shortfall > 0 ? shortfall : params.requiredSats;
|
|
2245
|
+
} catch (e) {
|
|
2246
|
+
this._log(
|
|
2247
|
+
"WARN",
|
|
2248
|
+
"Could not get current token balance for topup calculation:",
|
|
2249
|
+
e
|
|
2250
|
+
);
|
|
2251
|
+
}
|
|
2182
2252
|
const topupResult = await this.balanceManager.topUp({
|
|
2183
2253
|
mintUrl,
|
|
2184
2254
|
baseUrl,
|
|
2185
|
-
amount:
|
|
2255
|
+
amount: topupAmount * TOPUP_MARGIN,
|
|
2186
2256
|
token: params.token
|
|
2187
2257
|
});
|
|
2188
2258
|
this._log(
|
|
@@ -2263,7 +2333,10 @@ var RoutstrClient = class {
|
|
|
2263
2333
|
retryToken = latestBalanceInfo.apiKey;
|
|
2264
2334
|
}
|
|
2265
2335
|
if (latestTokenBalance >= 0) {
|
|
2266
|
-
this.storageAdapter.updateApiKeyBalance(
|
|
2336
|
+
this.storageAdapter.updateApiKeyBalance(
|
|
2337
|
+
baseUrl,
|
|
2338
|
+
latestTokenBalance
|
|
2339
|
+
);
|
|
2267
2340
|
}
|
|
2268
2341
|
}
|
|
2269
2342
|
} catch (error) {
|