@unicitylabs/sphere-sdk 0.4.8 → 0.5.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/core/index.cjs +183 -80
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +222 -194
- package/dist/core/index.d.ts +222 -194
- package/dist/core/index.js +183 -80
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/index.cjs +64 -2
- package/dist/impl/browser/index.cjs.map +1 -1
- package/dist/impl/browser/index.js +64 -2
- package/dist/impl/browser/index.js.map +1 -1
- package/dist/impl/nodejs/index.cjs +61 -4
- package/dist/impl/nodejs/index.cjs.map +1 -1
- package/dist/impl/nodejs/index.d.cts +668 -628
- package/dist/impl/nodejs/index.d.ts +668 -628
- package/dist/impl/nodejs/index.js +61 -4
- package/dist/impl/nodejs/index.js.map +1 -1
- package/dist/index.cjs +183 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +222 -194
- package/dist/index.d.ts +222 -194
- package/dist/index.js +183 -80
- package/dist/index.js.map +1 -1
- package/dist/l1/index.cjs +2 -0
- package/dist/l1/index.cjs.map +1 -1
- package/dist/l1/index.js +2 -0
- package/dist/l1/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -663,6 +663,8 @@ function disconnect() {
|
|
|
663
663
|
if (cb.timeoutId) clearTimeout(cb.timeoutId);
|
|
664
664
|
});
|
|
665
665
|
connectionCallbacks.length = 0;
|
|
666
|
+
blockSubscribers.length = 0;
|
|
667
|
+
lastBlockHeader = null;
|
|
666
668
|
}
|
|
667
669
|
var DEFAULT_ENDPOINT, ws, isConnected, isConnecting, requestId, intentionalClose, reconnectAttempts, isBlockSubscribed, lastBlockHeader, pending, blockSubscribers, connectionCallbacks, MAX_RECONNECT_ATTEMPTS, BASE_DELAY, MAX_DELAY, RPC_TIMEOUT, CONNECTION_TIMEOUT;
|
|
668
670
|
var init_network = __esm({
|
|
@@ -3872,7 +3874,7 @@ var InstantSplitExecutor = class {
|
|
|
3872
3874
|
token: JSON.stringify(bundle),
|
|
3873
3875
|
proof: null,
|
|
3874
3876
|
// Proof is included in the bundle
|
|
3875
|
-
memo:
|
|
3877
|
+
memo: options?.memo,
|
|
3876
3878
|
sender: {
|
|
3877
3879
|
transportPubkey: senderPubkey
|
|
3878
3880
|
}
|
|
@@ -4431,6 +4433,11 @@ var import_MintCommitment3 = require("@unicitylabs/state-transition-sdk/lib/tran
|
|
|
4431
4433
|
var import_MintTransactionData3 = require("@unicitylabs/state-transition-sdk/lib/transaction/MintTransactionData");
|
|
4432
4434
|
var import_InclusionProofUtils5 = require("@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils");
|
|
4433
4435
|
var import_InclusionProof = require("@unicitylabs/state-transition-sdk/lib/transaction/InclusionProof");
|
|
4436
|
+
function computeHistoryDedupKey(type, tokenId, transferId) {
|
|
4437
|
+
if (type === "SENT" && transferId) return `${type}_transfer_${transferId}`;
|
|
4438
|
+
if (tokenId) return `${type}_${tokenId}`;
|
|
4439
|
+
return `${type}_${crypto.randomUUID()}`;
|
|
4440
|
+
}
|
|
4434
4441
|
function enrichWithRegistry(info) {
|
|
4435
4442
|
const registry = TokenRegistry.getInstance();
|
|
4436
4443
|
const def = registry.getDefinition(info.coinId);
|
|
@@ -4729,7 +4736,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4729
4736
|
tombstones = [];
|
|
4730
4737
|
archivedTokens = /* @__PURE__ */ new Map();
|
|
4731
4738
|
forkedTokens = /* @__PURE__ */ new Map();
|
|
4732
|
-
|
|
4739
|
+
_historyCache = [];
|
|
4733
4740
|
nametags = [];
|
|
4734
4741
|
// Payment Requests State (Incoming)
|
|
4735
4742
|
paymentRequests = [];
|
|
@@ -4798,7 +4805,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4798
4805
|
this.tombstones = [];
|
|
4799
4806
|
this.archivedTokens.clear();
|
|
4800
4807
|
this.forkedTokens.clear();
|
|
4801
|
-
this.
|
|
4808
|
+
this._historyCache = [];
|
|
4802
4809
|
this.nametags = [];
|
|
4803
4810
|
this.deps = deps;
|
|
4804
4811
|
this.priceProvider = deps.price ?? null;
|
|
@@ -4849,14 +4856,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4849
4856
|
}
|
|
4850
4857
|
}
|
|
4851
4858
|
await this.loadPendingV5Tokens();
|
|
4852
|
-
|
|
4853
|
-
if (historyData) {
|
|
4854
|
-
try {
|
|
4855
|
-
this.transactionHistory = JSON.parse(historyData);
|
|
4856
|
-
} catch {
|
|
4857
|
-
this.transactionHistory = [];
|
|
4858
|
-
}
|
|
4859
|
-
}
|
|
4859
|
+
await this.loadHistory();
|
|
4860
4860
|
const pending2 = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.PENDING_TRANSFERS);
|
|
4861
4861
|
if (pending2) {
|
|
4862
4862
|
const transfers = JSON.parse(pending2);
|
|
@@ -4943,7 +4943,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4943
4943
|
}
|
|
4944
4944
|
await this.saveToOutbox(result, recipientPubkey);
|
|
4945
4945
|
result.status = "submitted";
|
|
4946
|
-
const recipientNametag = request.recipient.startsWith("@") ? request.recipient.slice(1) : void 0;
|
|
4946
|
+
const recipientNametag = peerInfo?.nametag || (request.recipient.startsWith("@") ? request.recipient.slice(1) : void 0);
|
|
4947
4947
|
const transferMode = request.transferMode ?? "instant";
|
|
4948
4948
|
if (splitPlan.requiresSplit && splitPlan.tokenToSplit) {
|
|
4949
4949
|
if (transferMode === "conservative") {
|
|
@@ -4974,7 +4974,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4974
4974
|
updatedAt: Date.now(),
|
|
4975
4975
|
sdkData: JSON.stringify(changeTokenData)
|
|
4976
4976
|
};
|
|
4977
|
-
await this.addToken(changeUiToken
|
|
4977
|
+
await this.addToken(changeUiToken);
|
|
4978
4978
|
this.log(`Conservative split: change token saved: ${changeUiToken.id}`);
|
|
4979
4979
|
await this.deps.transport.sendTokenTransfer(recipientPubkey, {
|
|
4980
4980
|
sourceToken: JSON.stringify(splitResult.tokenForRecipient.toJSON()),
|
|
@@ -4983,7 +4983,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4983
4983
|
});
|
|
4984
4984
|
const splitCommitmentRequestId = splitResult.recipientTransferTx?.data?.requestId ?? splitResult.recipientTransferTx?.requestId;
|
|
4985
4985
|
const splitRequestIdHex = splitCommitmentRequestId instanceof Uint8Array ? Array.from(splitCommitmentRequestId).map((b) => b.toString(16).padStart(2, "0")).join("") : splitCommitmentRequestId ? String(splitCommitmentRequestId) : void 0;
|
|
4986
|
-
await this.removeToken(splitPlan.tokenToSplit.uiToken.id
|
|
4986
|
+
await this.removeToken(splitPlan.tokenToSplit.uiToken.id);
|
|
4987
4987
|
result.tokenTransfers.push({
|
|
4988
4988
|
sourceTokenId: splitPlan.tokenToSplit.uiToken.id,
|
|
4989
4989
|
method: "split",
|
|
@@ -5008,6 +5008,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5008
5008
|
this.deps.transport,
|
|
5009
5009
|
recipientPubkey,
|
|
5010
5010
|
{
|
|
5011
|
+
memo: request.memo,
|
|
5011
5012
|
onChangeTokenCreated: async (changeToken) => {
|
|
5012
5013
|
const changeTokenData = changeToken.toJSON();
|
|
5013
5014
|
const uiToken = {
|
|
@@ -5023,7 +5024,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5023
5024
|
updatedAt: Date.now(),
|
|
5024
5025
|
sdkData: JSON.stringify(changeTokenData)
|
|
5025
5026
|
};
|
|
5026
|
-
await this.addToken(uiToken
|
|
5027
|
+
await this.addToken(uiToken);
|
|
5027
5028
|
this.log(`Change token saved via background: ${uiToken.id}`);
|
|
5028
5029
|
},
|
|
5029
5030
|
onStorageSync: async () => {
|
|
@@ -5038,7 +5039,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5038
5039
|
if (instantResult.backgroundPromise) {
|
|
5039
5040
|
this.pendingBackgroundTasks.push(instantResult.backgroundPromise);
|
|
5040
5041
|
}
|
|
5041
|
-
await this.removeToken(splitPlan.tokenToSplit.uiToken.id
|
|
5042
|
+
await this.removeToken(splitPlan.tokenToSplit.uiToken.id);
|
|
5042
5043
|
result.tokenTransfers.push({
|
|
5043
5044
|
sourceTokenId: splitPlan.tokenToSplit.uiToken.id,
|
|
5044
5045
|
method: "split",
|
|
@@ -5085,20 +5086,25 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5085
5086
|
requestIdHex
|
|
5086
5087
|
});
|
|
5087
5088
|
this.log(`Token ${token.id} sent via ${transferMode.toUpperCase()}, requestId: ${requestIdHex}`);
|
|
5088
|
-
await this.removeToken(token.id
|
|
5089
|
+
await this.removeToken(token.id);
|
|
5089
5090
|
}
|
|
5090
5091
|
result.status = "delivered";
|
|
5091
5092
|
await this.save();
|
|
5092
5093
|
await this.removeFromOutbox(result.id);
|
|
5093
5094
|
result.status = "completed";
|
|
5095
|
+
const sentTokenId = result.tokens[0] ? extractTokenIdFromSdkData(result.tokens[0].sdkData) : void 0;
|
|
5094
5096
|
await this.addToHistory({
|
|
5095
5097
|
type: "SENT",
|
|
5096
5098
|
amount: request.amount,
|
|
5097
5099
|
coinId: request.coinId,
|
|
5098
5100
|
symbol: this.getCoinSymbol(request.coinId),
|
|
5099
5101
|
timestamp: Date.now(),
|
|
5102
|
+
recipientPubkey,
|
|
5100
5103
|
recipientNametag,
|
|
5101
|
-
|
|
5104
|
+
recipientAddress: peerInfo?.directAddress || recipientAddress?.toString() || recipientPubkey,
|
|
5105
|
+
memo: request.memo,
|
|
5106
|
+
transferId: result.id,
|
|
5107
|
+
tokenId: sentTokenId || void 0
|
|
5102
5108
|
});
|
|
5103
5109
|
this.deps.emitEvent("transfer:confirmed", result);
|
|
5104
5110
|
return result;
|
|
@@ -5209,6 +5215,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5209
5215
|
recipientPubkey,
|
|
5210
5216
|
{
|
|
5211
5217
|
...options,
|
|
5218
|
+
memo: request.memo,
|
|
5212
5219
|
onChangeTokenCreated: async (changeToken) => {
|
|
5213
5220
|
const changeTokenData = changeToken.toJSON();
|
|
5214
5221
|
const uiToken = {
|
|
@@ -5224,7 +5231,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5224
5231
|
updatedAt: Date.now(),
|
|
5225
5232
|
sdkData: JSON.stringify(changeTokenData)
|
|
5226
5233
|
};
|
|
5227
|
-
await this.addToken(uiToken
|
|
5234
|
+
await this.addToken(uiToken);
|
|
5228
5235
|
this.log(`Change token saved via background: ${uiToken.id}`);
|
|
5229
5236
|
},
|
|
5230
5237
|
onStorageSync: async () => {
|
|
@@ -5237,15 +5244,20 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5237
5244
|
if (result.backgroundPromise) {
|
|
5238
5245
|
this.pendingBackgroundTasks.push(result.backgroundPromise);
|
|
5239
5246
|
}
|
|
5240
|
-
|
|
5241
|
-
|
|
5247
|
+
await this.removeToken(tokenToSplit.id);
|
|
5248
|
+
const recipientNametag = peerInfo?.nametag || (request.recipient.startsWith("@") ? request.recipient.slice(1) : void 0);
|
|
5249
|
+
const splitTokenId = extractTokenIdFromSdkData(tokenToSplit.sdkData);
|
|
5242
5250
|
await this.addToHistory({
|
|
5243
5251
|
type: "SENT",
|
|
5244
5252
|
amount: request.amount,
|
|
5245
5253
|
coinId: request.coinId,
|
|
5246
5254
|
symbol: this.getCoinSymbol(request.coinId),
|
|
5247
5255
|
timestamp: Date.now(),
|
|
5248
|
-
|
|
5256
|
+
recipientPubkey,
|
|
5257
|
+
recipientNametag,
|
|
5258
|
+
recipientAddress: peerInfo?.directAddress || recipientAddress?.toString() || recipientPubkey,
|
|
5259
|
+
memo: request.memo,
|
|
5260
|
+
tokenId: splitTokenId || void 0
|
|
5249
5261
|
});
|
|
5250
5262
|
await this.save();
|
|
5251
5263
|
} else {
|
|
@@ -5276,10 +5288,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5276
5288
|
* @param senderPubkey - Sender's public key for verification
|
|
5277
5289
|
* @returns Processing result with finalized token
|
|
5278
5290
|
*/
|
|
5279
|
-
async processInstantSplitBundle(bundle, senderPubkey) {
|
|
5291
|
+
async processInstantSplitBundle(bundle, senderPubkey, memo) {
|
|
5280
5292
|
this.ensureInitialized();
|
|
5281
5293
|
if (!isInstantSplitBundleV5(bundle)) {
|
|
5282
|
-
return this.processInstantSplitBundleSync(bundle, senderPubkey);
|
|
5294
|
+
return this.processInstantSplitBundleSync(bundle, senderPubkey, memo);
|
|
5283
5295
|
}
|
|
5284
5296
|
try {
|
|
5285
5297
|
const deterministicId = `v5split_${bundle.splitGroupId}`;
|
|
@@ -5309,12 +5321,26 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5309
5321
|
updatedAt: Date.now(),
|
|
5310
5322
|
sdkData: JSON.stringify({ _pendingFinalization: pendingData })
|
|
5311
5323
|
};
|
|
5312
|
-
await this.addToken(uiToken
|
|
5324
|
+
await this.addToken(uiToken);
|
|
5313
5325
|
this.log(`V5 bundle saved as unconfirmed: ${uiToken.id.slice(0, 8)}...`);
|
|
5326
|
+
const senderInfo = await this.resolveSenderInfo(senderPubkey);
|
|
5327
|
+
await this.addToHistory({
|
|
5328
|
+
type: "RECEIVED",
|
|
5329
|
+
amount: bundle.amount,
|
|
5330
|
+
coinId: bundle.coinId,
|
|
5331
|
+
symbol: uiToken.symbol,
|
|
5332
|
+
timestamp: Date.now(),
|
|
5333
|
+
senderPubkey,
|
|
5334
|
+
...senderInfo,
|
|
5335
|
+
memo,
|
|
5336
|
+
tokenId: deterministicId
|
|
5337
|
+
});
|
|
5314
5338
|
this.deps.emitEvent("transfer:incoming", {
|
|
5315
5339
|
id: bundle.splitGroupId,
|
|
5316
5340
|
senderPubkey,
|
|
5341
|
+
senderNametag: senderInfo.senderNametag,
|
|
5317
5342
|
tokens: [uiToken],
|
|
5343
|
+
memo,
|
|
5318
5344
|
receivedAt: Date.now()
|
|
5319
5345
|
});
|
|
5320
5346
|
await this.save();
|
|
@@ -5334,7 +5360,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5334
5360
|
* Synchronous V4 bundle processing (dev mode only).
|
|
5335
5361
|
* Kept for backward compatibility with V4 bundles.
|
|
5336
5362
|
*/
|
|
5337
|
-
async processInstantSplitBundleSync(bundle, senderPubkey) {
|
|
5363
|
+
async processInstantSplitBundleSync(bundle, senderPubkey, memo) {
|
|
5338
5364
|
try {
|
|
5339
5365
|
const signingService = await this.createSigningService();
|
|
5340
5366
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
@@ -5394,19 +5420,26 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5394
5420
|
sdkData: JSON.stringify(tokenData)
|
|
5395
5421
|
};
|
|
5396
5422
|
await this.addToken(uiToken);
|
|
5423
|
+
const receivedTokenId = extractTokenIdFromSdkData(uiToken.sdkData);
|
|
5424
|
+
const senderInfo = await this.resolveSenderInfo(senderPubkey);
|
|
5397
5425
|
await this.addToHistory({
|
|
5398
5426
|
type: "RECEIVED",
|
|
5399
5427
|
amount: bundle.amount,
|
|
5400
5428
|
coinId: info.coinId,
|
|
5401
5429
|
symbol: info.symbol,
|
|
5402
5430
|
timestamp: Date.now(),
|
|
5403
|
-
senderPubkey
|
|
5431
|
+
senderPubkey,
|
|
5432
|
+
...senderInfo,
|
|
5433
|
+
memo,
|
|
5434
|
+
tokenId: receivedTokenId || uiToken.id
|
|
5404
5435
|
});
|
|
5405
5436
|
await this.save();
|
|
5406
5437
|
this.deps.emitEvent("transfer:incoming", {
|
|
5407
5438
|
id: bundle.splitGroupId,
|
|
5408
5439
|
senderPubkey,
|
|
5440
|
+
senderNametag: senderInfo.senderNametag,
|
|
5409
5441
|
tokens: [uiToken],
|
|
5442
|
+
memo,
|
|
5410
5443
|
receivedAt: Date.now()
|
|
5411
5444
|
});
|
|
5412
5445
|
}
|
|
@@ -6149,14 +6182,6 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6149
6182
|
sdkData: JSON.stringify(finalizedToken.toJSON())
|
|
6150
6183
|
};
|
|
6151
6184
|
this.tokens.set(tokenId, confirmedToken);
|
|
6152
|
-
await this.addToHistory({
|
|
6153
|
-
type: "RECEIVED",
|
|
6154
|
-
amount: confirmedToken.amount,
|
|
6155
|
-
coinId: confirmedToken.coinId,
|
|
6156
|
-
symbol: confirmedToken.symbol || "UNK",
|
|
6157
|
-
timestamp: Date.now(),
|
|
6158
|
-
senderPubkey: pending2.senderPubkey
|
|
6159
|
-
});
|
|
6160
6185
|
this.log(`V5 token resolved: ${tokenId.slice(0, 8)}...`);
|
|
6161
6186
|
return "resolved";
|
|
6162
6187
|
}
|
|
@@ -6340,10 +6365,9 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6340
6365
|
* the old state is archived and replaced with the incoming one.
|
|
6341
6366
|
*
|
|
6342
6367
|
* @param token - The token to add.
|
|
6343
|
-
* @param skipHistory - When `true`, do not create a `RECEIVED` transaction history entry (default `false`).
|
|
6344
6368
|
* @returns `true` if the token was added, `false` if rejected as duplicate or tombstoned.
|
|
6345
6369
|
*/
|
|
6346
|
-
async addToken(token
|
|
6370
|
+
async addToken(token) {
|
|
6347
6371
|
this.ensureInitialized();
|
|
6348
6372
|
const incomingTokenId = extractTokenIdFromSdkData(token.sdkData);
|
|
6349
6373
|
const incomingStateHash = extractStateHashFromSdkData(token.sdkData);
|
|
@@ -6389,15 +6413,6 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6389
6413
|
}
|
|
6390
6414
|
this.tokens.set(token.id, token);
|
|
6391
6415
|
await this.archiveToken(token);
|
|
6392
|
-
if (!skipHistory && token.coinId && token.amount) {
|
|
6393
|
-
await this.addToHistory({
|
|
6394
|
-
type: "RECEIVED",
|
|
6395
|
-
amount: token.amount,
|
|
6396
|
-
coinId: token.coinId,
|
|
6397
|
-
symbol: token.symbol || "UNK",
|
|
6398
|
-
timestamp: token.createdAt || Date.now()
|
|
6399
|
-
});
|
|
6400
|
-
}
|
|
6401
6416
|
await this.save();
|
|
6402
6417
|
this.log(`Added token ${token.id}, total: ${this.tokens.size}`);
|
|
6403
6418
|
return true;
|
|
@@ -6424,7 +6439,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6424
6439
|
}
|
|
6425
6440
|
}
|
|
6426
6441
|
if (!found) {
|
|
6427
|
-
await this.addToken(token
|
|
6442
|
+
await this.addToken(token);
|
|
6428
6443
|
return;
|
|
6429
6444
|
}
|
|
6430
6445
|
await this.archiveToken(token);
|
|
@@ -6439,10 +6454,8 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6439
6454
|
* entry is created unless `skipHistory` is `true`.
|
|
6440
6455
|
*
|
|
6441
6456
|
* @param tokenId - Local UUID of the token to remove.
|
|
6442
|
-
* @param recipientNametag - Optional nametag of the transfer recipient (for history).
|
|
6443
|
-
* @param skipHistory - When `true`, skip creating a transaction history entry (default `false`).
|
|
6444
6457
|
*/
|
|
6445
|
-
async removeToken(tokenId
|
|
6458
|
+
async removeToken(tokenId) {
|
|
6446
6459
|
this.ensureInitialized();
|
|
6447
6460
|
const token = this.tokens.get(tokenId);
|
|
6448
6461
|
if (!token) return;
|
|
@@ -6460,16 +6473,6 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6460
6473
|
this.log(`Warning: Could not create tombstone for token ${tokenId.slice(0, 8)}... (missing tokenId or stateHash)`);
|
|
6461
6474
|
}
|
|
6462
6475
|
this.tokens.delete(tokenId);
|
|
6463
|
-
if (!skipHistory && token.coinId && token.amount) {
|
|
6464
|
-
await this.addToHistory({
|
|
6465
|
-
type: "SENT",
|
|
6466
|
-
amount: token.amount,
|
|
6467
|
-
coinId: token.coinId,
|
|
6468
|
-
symbol: token.symbol || "UNK",
|
|
6469
|
-
timestamp: Date.now(),
|
|
6470
|
-
recipientNametag
|
|
6471
|
-
});
|
|
6472
|
-
}
|
|
6473
6476
|
await this.save();
|
|
6474
6477
|
}
|
|
6475
6478
|
// ===========================================================================
|
|
@@ -6694,26 +6697,104 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6694
6697
|
* @returns Array of {@link TransactionHistoryEntry} objects in descending timestamp order.
|
|
6695
6698
|
*/
|
|
6696
6699
|
getHistory() {
|
|
6697
|
-
return [...this.
|
|
6700
|
+
return [...this._historyCache].sort((a, b) => b.timestamp - a.timestamp);
|
|
6701
|
+
}
|
|
6702
|
+
/**
|
|
6703
|
+
* Best-effort resolve sender's DIRECT address and nametag from their transport pubkey.
|
|
6704
|
+
* Returns empty object if transport doesn't support resolution or lookup fails.
|
|
6705
|
+
*/
|
|
6706
|
+
async resolveSenderInfo(senderTransportPubkey) {
|
|
6707
|
+
try {
|
|
6708
|
+
if (this.deps?.transport?.resolveTransportPubkeyInfo) {
|
|
6709
|
+
const peerInfo = await this.deps.transport.resolveTransportPubkeyInfo(senderTransportPubkey);
|
|
6710
|
+
if (peerInfo) {
|
|
6711
|
+
return {
|
|
6712
|
+
senderAddress: peerInfo.directAddress || void 0,
|
|
6713
|
+
senderNametag: peerInfo.nametag || void 0
|
|
6714
|
+
};
|
|
6715
|
+
}
|
|
6716
|
+
}
|
|
6717
|
+
} catch {
|
|
6718
|
+
}
|
|
6719
|
+
return {};
|
|
6698
6720
|
}
|
|
6699
6721
|
/**
|
|
6700
6722
|
* Append an entry to the transaction history.
|
|
6701
6723
|
*
|
|
6702
|
-
* A unique `id`
|
|
6724
|
+
* A unique `id` and `dedupKey` are auto-generated. The entry is persisted to
|
|
6725
|
+
* the local token storage provider's `history` store (IndexedDB / file).
|
|
6726
|
+
* Duplicate entries with the same `dedupKey` are silently ignored (upsert).
|
|
6703
6727
|
*
|
|
6704
|
-
* @param entry - History entry fields (without `id`).
|
|
6728
|
+
* @param entry - History entry fields (without `id` and `dedupKey`).
|
|
6705
6729
|
*/
|
|
6706
6730
|
async addToHistory(entry) {
|
|
6707
6731
|
this.ensureInitialized();
|
|
6732
|
+
const dedupKey = computeHistoryDedupKey(entry.type, entry.tokenId, entry.transferId);
|
|
6708
6733
|
const historyEntry = {
|
|
6709
6734
|
id: crypto.randomUUID(),
|
|
6735
|
+
dedupKey,
|
|
6710
6736
|
...entry
|
|
6711
6737
|
};
|
|
6712
|
-
this.
|
|
6713
|
-
|
|
6714
|
-
|
|
6715
|
-
|
|
6716
|
-
);
|
|
6738
|
+
const provider = this.getLocalTokenStorageProvider();
|
|
6739
|
+
if (provider?.addHistoryEntry) {
|
|
6740
|
+
await provider.addHistoryEntry(historyEntry);
|
|
6741
|
+
}
|
|
6742
|
+
const existingIdx = this._historyCache.findIndex((e) => e.dedupKey === dedupKey);
|
|
6743
|
+
if (existingIdx >= 0) {
|
|
6744
|
+
this._historyCache[existingIdx] = historyEntry;
|
|
6745
|
+
} else {
|
|
6746
|
+
this._historyCache.push(historyEntry);
|
|
6747
|
+
}
|
|
6748
|
+
this.deps.emitEvent("history:updated", historyEntry);
|
|
6749
|
+
}
|
|
6750
|
+
/**
|
|
6751
|
+
* Load history from the local token storage provider into the in-memory cache.
|
|
6752
|
+
* Also performs one-time migration from legacy KV storage.
|
|
6753
|
+
*/
|
|
6754
|
+
async loadHistory() {
|
|
6755
|
+
const provider = this.getLocalTokenStorageProvider();
|
|
6756
|
+
if (provider?.getHistoryEntries) {
|
|
6757
|
+
this._historyCache = await provider.getHistoryEntries();
|
|
6758
|
+
const legacyData = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.TRANSACTION_HISTORY);
|
|
6759
|
+
if (legacyData) {
|
|
6760
|
+
try {
|
|
6761
|
+
const legacyEntries = JSON.parse(legacyData);
|
|
6762
|
+
const records = legacyEntries.map((e) => ({
|
|
6763
|
+
...e,
|
|
6764
|
+
dedupKey: e.dedupKey || computeHistoryDedupKey(e.type, e.tokenId, e.transferId)
|
|
6765
|
+
}));
|
|
6766
|
+
const imported = await provider.importHistoryEntries?.(records) ?? 0;
|
|
6767
|
+
if (imported > 0) {
|
|
6768
|
+
this._historyCache = await provider.getHistoryEntries();
|
|
6769
|
+
this.log(`Migrated ${imported} history entries from KV to history store`);
|
|
6770
|
+
}
|
|
6771
|
+
await this.deps.storage.remove(STORAGE_KEYS_ADDRESS.TRANSACTION_HISTORY);
|
|
6772
|
+
} catch {
|
|
6773
|
+
}
|
|
6774
|
+
}
|
|
6775
|
+
} else {
|
|
6776
|
+
const historyData = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.TRANSACTION_HISTORY);
|
|
6777
|
+
if (historyData) {
|
|
6778
|
+
try {
|
|
6779
|
+
this._historyCache = JSON.parse(historyData);
|
|
6780
|
+
} catch {
|
|
6781
|
+
this._historyCache = [];
|
|
6782
|
+
}
|
|
6783
|
+
}
|
|
6784
|
+
}
|
|
6785
|
+
}
|
|
6786
|
+
/**
|
|
6787
|
+
* Get the first local token storage provider (for history operations).
|
|
6788
|
+
*/
|
|
6789
|
+
getLocalTokenStorageProvider() {
|
|
6790
|
+
const providers = this.getTokenStorageProviders();
|
|
6791
|
+
for (const [, provider] of providers) {
|
|
6792
|
+
if (provider.type === "local") return provider;
|
|
6793
|
+
}
|
|
6794
|
+
for (const [, provider] of providers) {
|
|
6795
|
+
return provider;
|
|
6796
|
+
}
|
|
6797
|
+
return null;
|
|
6717
6798
|
}
|
|
6718
6799
|
// ===========================================================================
|
|
6719
6800
|
// Public API - Nametag
|
|
@@ -7256,14 +7337,27 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7256
7337
|
this.tokens.set(token.id, token);
|
|
7257
7338
|
await this.save();
|
|
7258
7339
|
this.log(`NOSTR-FIRST: Token ${token.id.slice(0, 8)}... added as submitted (unconfirmed)`);
|
|
7340
|
+
const senderInfo = await this.resolveSenderInfo(transfer.senderTransportPubkey);
|
|
7259
7341
|
const incomingTransfer = {
|
|
7260
7342
|
id: transfer.id,
|
|
7261
7343
|
senderPubkey: transfer.senderTransportPubkey,
|
|
7344
|
+
senderNametag: senderInfo.senderNametag,
|
|
7262
7345
|
tokens: [token],
|
|
7263
7346
|
memo: payload.memo,
|
|
7264
7347
|
receivedAt: transfer.timestamp
|
|
7265
7348
|
};
|
|
7266
7349
|
this.deps.emitEvent("transfer:incoming", incomingTransfer);
|
|
7350
|
+
await this.addToHistory({
|
|
7351
|
+
type: "RECEIVED",
|
|
7352
|
+
amount: token.amount,
|
|
7353
|
+
coinId: token.coinId,
|
|
7354
|
+
symbol: token.symbol,
|
|
7355
|
+
timestamp: Date.now(),
|
|
7356
|
+
senderPubkey: transfer.senderTransportPubkey,
|
|
7357
|
+
...senderInfo,
|
|
7358
|
+
memo: payload.memo,
|
|
7359
|
+
tokenId: nostrTokenId || token.id
|
|
7360
|
+
});
|
|
7267
7361
|
try {
|
|
7268
7362
|
const commitment = await import_TransferCommitment4.TransferCommitment.fromJSON(commitmentInput);
|
|
7269
7363
|
const requestIdBytes = commitment.requestId;
|
|
@@ -7281,7 +7375,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7281
7375
|
attemptCount: 0,
|
|
7282
7376
|
lastAttemptAt: 0,
|
|
7283
7377
|
onProofReceived: async (tokenId) => {
|
|
7284
|
-
await this.finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput
|
|
7378
|
+
await this.finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput);
|
|
7285
7379
|
}
|
|
7286
7380
|
});
|
|
7287
7381
|
} catch (err) {
|
|
@@ -7340,7 +7434,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7340
7434
|
/**
|
|
7341
7435
|
* Finalize a received token after proof is available
|
|
7342
7436
|
*/
|
|
7343
|
-
async finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput
|
|
7437
|
+
async finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput) {
|
|
7344
7438
|
try {
|
|
7345
7439
|
const token = this.tokens.get(tokenId);
|
|
7346
7440
|
if (!token) {
|
|
@@ -7388,14 +7482,6 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7388
7482
|
tokens: [finalizedToken],
|
|
7389
7483
|
tokenTransfers: []
|
|
7390
7484
|
});
|
|
7391
|
-
await this.addToHistory({
|
|
7392
|
-
type: "RECEIVED",
|
|
7393
|
-
amount: finalizedToken.amount,
|
|
7394
|
-
coinId: finalizedToken.coinId,
|
|
7395
|
-
symbol: finalizedToken.symbol,
|
|
7396
|
-
timestamp: Date.now(),
|
|
7397
|
-
senderPubkey
|
|
7398
|
-
});
|
|
7399
7485
|
} catch (error) {
|
|
7400
7486
|
console.error("[Payments] Failed to finalize received token:", error);
|
|
7401
7487
|
const token = this.tokens.get(tokenId);
|
|
@@ -7426,7 +7512,8 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7426
7512
|
try {
|
|
7427
7513
|
const result = await this.processInstantSplitBundle(
|
|
7428
7514
|
instantBundle,
|
|
7429
|
-
transfer.senderTransportPubkey
|
|
7515
|
+
transfer.senderTransportPubkey,
|
|
7516
|
+
payload.memo
|
|
7430
7517
|
);
|
|
7431
7518
|
if (result.success) {
|
|
7432
7519
|
this.log("INSTANT_SPLIT processed successfully");
|
|
@@ -7544,10 +7631,26 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7544
7631
|
updatedAt: Date.now(),
|
|
7545
7632
|
sdkData: typeof tokenData === "string" ? tokenData : JSON.stringify(tokenData)
|
|
7546
7633
|
};
|
|
7547
|
-
await this.addToken(token);
|
|
7634
|
+
const added = await this.addToken(token);
|
|
7635
|
+
const senderInfo = await this.resolveSenderInfo(transfer.senderTransportPubkey);
|
|
7636
|
+
if (added) {
|
|
7637
|
+
const incomingTokenId = extractTokenIdFromSdkData(token.sdkData);
|
|
7638
|
+
await this.addToHistory({
|
|
7639
|
+
type: "RECEIVED",
|
|
7640
|
+
amount: token.amount,
|
|
7641
|
+
coinId: token.coinId,
|
|
7642
|
+
symbol: token.symbol,
|
|
7643
|
+
timestamp: Date.now(),
|
|
7644
|
+
senderPubkey: transfer.senderTransportPubkey,
|
|
7645
|
+
...senderInfo,
|
|
7646
|
+
memo: payload.memo,
|
|
7647
|
+
tokenId: incomingTokenId || token.id
|
|
7648
|
+
});
|
|
7649
|
+
}
|
|
7548
7650
|
const incomingTransfer = {
|
|
7549
7651
|
id: transfer.id,
|
|
7550
7652
|
senderPubkey: transfer.senderTransportPubkey,
|
|
7653
|
+
senderNametag: senderInfo.senderNametag,
|
|
7551
7654
|
tokens: [token],
|
|
7552
7655
|
memo: payload.memo,
|
|
7553
7656
|
receivedAt: transfer.timestamp
|