@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.
@@ -610,6 +610,8 @@ function disconnect() {
610
610
  if (cb.timeoutId) clearTimeout(cb.timeoutId);
611
611
  });
612
612
  connectionCallbacks.length = 0;
613
+ blockSubscribers.length = 0;
614
+ lastBlockHeader = null;
613
615
  }
614
616
  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;
615
617
  var init_network = __esm({
@@ -3511,7 +3513,7 @@ var InstantSplitExecutor = class {
3511
3513
  token: JSON.stringify(bundle),
3512
3514
  proof: null,
3513
3515
  // Proof is included in the bundle
3514
- memo: "INSTANT_SPLIT_V5",
3516
+ memo: options?.memo,
3515
3517
  sender: {
3516
3518
  transportPubkey: senderPubkey
3517
3519
  }
@@ -4070,6 +4072,11 @@ var import_MintCommitment3 = require("@unicitylabs/state-transition-sdk/lib/tran
4070
4072
  var import_MintTransactionData3 = require("@unicitylabs/state-transition-sdk/lib/transaction/MintTransactionData");
4071
4073
  var import_InclusionProofUtils5 = require("@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils");
4072
4074
  var import_InclusionProof = require("@unicitylabs/state-transition-sdk/lib/transaction/InclusionProof");
4075
+ function computeHistoryDedupKey(type, tokenId, transferId) {
4076
+ if (type === "SENT" && transferId) return `${type}_transfer_${transferId}`;
4077
+ if (tokenId) return `${type}_${tokenId}`;
4078
+ return `${type}_${crypto.randomUUID()}`;
4079
+ }
4073
4080
  function enrichWithRegistry(info) {
4074
4081
  const registry = TokenRegistry.getInstance();
4075
4082
  const def = registry.getDefinition(info.coinId);
@@ -4368,7 +4375,7 @@ var PaymentsModule = class _PaymentsModule {
4368
4375
  tombstones = [];
4369
4376
  archivedTokens = /* @__PURE__ */ new Map();
4370
4377
  forkedTokens = /* @__PURE__ */ new Map();
4371
- transactionHistory = [];
4378
+ _historyCache = [];
4372
4379
  nametags = [];
4373
4380
  // Payment Requests State (Incoming)
4374
4381
  paymentRequests = [];
@@ -4437,7 +4444,7 @@ var PaymentsModule = class _PaymentsModule {
4437
4444
  this.tombstones = [];
4438
4445
  this.archivedTokens.clear();
4439
4446
  this.forkedTokens.clear();
4440
- this.transactionHistory = [];
4447
+ this._historyCache = [];
4441
4448
  this.nametags = [];
4442
4449
  this.deps = deps;
4443
4450
  this.priceProvider = deps.price ?? null;
@@ -4488,14 +4495,7 @@ var PaymentsModule = class _PaymentsModule {
4488
4495
  }
4489
4496
  }
4490
4497
  await this.loadPendingV5Tokens();
4491
- const historyData = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.TRANSACTION_HISTORY);
4492
- if (historyData) {
4493
- try {
4494
- this.transactionHistory = JSON.parse(historyData);
4495
- } catch {
4496
- this.transactionHistory = [];
4497
- }
4498
- }
4498
+ await this.loadHistory();
4499
4499
  const pending2 = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.PENDING_TRANSFERS);
4500
4500
  if (pending2) {
4501
4501
  const transfers = JSON.parse(pending2);
@@ -4582,7 +4582,7 @@ var PaymentsModule = class _PaymentsModule {
4582
4582
  }
4583
4583
  await this.saveToOutbox(result, recipientPubkey);
4584
4584
  result.status = "submitted";
4585
- const recipientNametag = request.recipient.startsWith("@") ? request.recipient.slice(1) : void 0;
4585
+ const recipientNametag = peerInfo?.nametag || (request.recipient.startsWith("@") ? request.recipient.slice(1) : void 0);
4586
4586
  const transferMode = request.transferMode ?? "instant";
4587
4587
  if (splitPlan.requiresSplit && splitPlan.tokenToSplit) {
4588
4588
  if (transferMode === "conservative") {
@@ -4613,7 +4613,7 @@ var PaymentsModule = class _PaymentsModule {
4613
4613
  updatedAt: Date.now(),
4614
4614
  sdkData: JSON.stringify(changeTokenData)
4615
4615
  };
4616
- await this.addToken(changeUiToken, true);
4616
+ await this.addToken(changeUiToken);
4617
4617
  this.log(`Conservative split: change token saved: ${changeUiToken.id}`);
4618
4618
  await this.deps.transport.sendTokenTransfer(recipientPubkey, {
4619
4619
  sourceToken: JSON.stringify(splitResult.tokenForRecipient.toJSON()),
@@ -4622,7 +4622,7 @@ var PaymentsModule = class _PaymentsModule {
4622
4622
  });
4623
4623
  const splitCommitmentRequestId = splitResult.recipientTransferTx?.data?.requestId ?? splitResult.recipientTransferTx?.requestId;
4624
4624
  const splitRequestIdHex = splitCommitmentRequestId instanceof Uint8Array ? Array.from(splitCommitmentRequestId).map((b) => b.toString(16).padStart(2, "0")).join("") : splitCommitmentRequestId ? String(splitCommitmentRequestId) : void 0;
4625
- await this.removeToken(splitPlan.tokenToSplit.uiToken.id, recipientNametag, true);
4625
+ await this.removeToken(splitPlan.tokenToSplit.uiToken.id);
4626
4626
  result.tokenTransfers.push({
4627
4627
  sourceTokenId: splitPlan.tokenToSplit.uiToken.id,
4628
4628
  method: "split",
@@ -4647,6 +4647,7 @@ var PaymentsModule = class _PaymentsModule {
4647
4647
  this.deps.transport,
4648
4648
  recipientPubkey,
4649
4649
  {
4650
+ memo: request.memo,
4650
4651
  onChangeTokenCreated: async (changeToken) => {
4651
4652
  const changeTokenData = changeToken.toJSON();
4652
4653
  const uiToken = {
@@ -4662,7 +4663,7 @@ var PaymentsModule = class _PaymentsModule {
4662
4663
  updatedAt: Date.now(),
4663
4664
  sdkData: JSON.stringify(changeTokenData)
4664
4665
  };
4665
- await this.addToken(uiToken, true);
4666
+ await this.addToken(uiToken);
4666
4667
  this.log(`Change token saved via background: ${uiToken.id}`);
4667
4668
  },
4668
4669
  onStorageSync: async () => {
@@ -4677,7 +4678,7 @@ var PaymentsModule = class _PaymentsModule {
4677
4678
  if (instantResult.backgroundPromise) {
4678
4679
  this.pendingBackgroundTasks.push(instantResult.backgroundPromise);
4679
4680
  }
4680
- await this.removeToken(splitPlan.tokenToSplit.uiToken.id, recipientNametag);
4681
+ await this.removeToken(splitPlan.tokenToSplit.uiToken.id);
4681
4682
  result.tokenTransfers.push({
4682
4683
  sourceTokenId: splitPlan.tokenToSplit.uiToken.id,
4683
4684
  method: "split",
@@ -4724,20 +4725,25 @@ var PaymentsModule = class _PaymentsModule {
4724
4725
  requestIdHex
4725
4726
  });
4726
4727
  this.log(`Token ${token.id} sent via ${transferMode.toUpperCase()}, requestId: ${requestIdHex}`);
4727
- await this.removeToken(token.id, recipientNametag, true);
4728
+ await this.removeToken(token.id);
4728
4729
  }
4729
4730
  result.status = "delivered";
4730
4731
  await this.save();
4731
4732
  await this.removeFromOutbox(result.id);
4732
4733
  result.status = "completed";
4734
+ const sentTokenId = result.tokens[0] ? extractTokenIdFromSdkData(result.tokens[0].sdkData) : void 0;
4733
4735
  await this.addToHistory({
4734
4736
  type: "SENT",
4735
4737
  amount: request.amount,
4736
4738
  coinId: request.coinId,
4737
4739
  symbol: this.getCoinSymbol(request.coinId),
4738
4740
  timestamp: Date.now(),
4741
+ recipientPubkey,
4739
4742
  recipientNametag,
4740
- transferId: result.id
4743
+ recipientAddress: peerInfo?.directAddress || recipientAddress?.toString() || recipientPubkey,
4744
+ memo: request.memo,
4745
+ transferId: result.id,
4746
+ tokenId: sentTokenId || void 0
4741
4747
  });
4742
4748
  this.deps.emitEvent("transfer:confirmed", result);
4743
4749
  return result;
@@ -4848,6 +4854,7 @@ var PaymentsModule = class _PaymentsModule {
4848
4854
  recipientPubkey,
4849
4855
  {
4850
4856
  ...options,
4857
+ memo: request.memo,
4851
4858
  onChangeTokenCreated: async (changeToken) => {
4852
4859
  const changeTokenData = changeToken.toJSON();
4853
4860
  const uiToken = {
@@ -4863,7 +4870,7 @@ var PaymentsModule = class _PaymentsModule {
4863
4870
  updatedAt: Date.now(),
4864
4871
  sdkData: JSON.stringify(changeTokenData)
4865
4872
  };
4866
- await this.addToken(uiToken, true);
4873
+ await this.addToken(uiToken);
4867
4874
  this.log(`Change token saved via background: ${uiToken.id}`);
4868
4875
  },
4869
4876
  onStorageSync: async () => {
@@ -4876,15 +4883,20 @@ var PaymentsModule = class _PaymentsModule {
4876
4883
  if (result.backgroundPromise) {
4877
4884
  this.pendingBackgroundTasks.push(result.backgroundPromise);
4878
4885
  }
4879
- const recipientNametag = request.recipient.startsWith("@") ? request.recipient.slice(1) : void 0;
4880
- await this.removeToken(tokenToSplit.id, recipientNametag, true);
4886
+ await this.removeToken(tokenToSplit.id);
4887
+ const recipientNametag = peerInfo?.nametag || (request.recipient.startsWith("@") ? request.recipient.slice(1) : void 0);
4888
+ const splitTokenId = extractTokenIdFromSdkData(tokenToSplit.sdkData);
4881
4889
  await this.addToHistory({
4882
4890
  type: "SENT",
4883
4891
  amount: request.amount,
4884
4892
  coinId: request.coinId,
4885
4893
  symbol: this.getCoinSymbol(request.coinId),
4886
4894
  timestamp: Date.now(),
4887
- recipientNametag
4895
+ recipientPubkey,
4896
+ recipientNametag,
4897
+ recipientAddress: peerInfo?.directAddress || recipientAddress?.toString() || recipientPubkey,
4898
+ memo: request.memo,
4899
+ tokenId: splitTokenId || void 0
4888
4900
  });
4889
4901
  await this.save();
4890
4902
  } else {
@@ -4915,10 +4927,10 @@ var PaymentsModule = class _PaymentsModule {
4915
4927
  * @param senderPubkey - Sender's public key for verification
4916
4928
  * @returns Processing result with finalized token
4917
4929
  */
4918
- async processInstantSplitBundle(bundle, senderPubkey) {
4930
+ async processInstantSplitBundle(bundle, senderPubkey, memo) {
4919
4931
  this.ensureInitialized();
4920
4932
  if (!isInstantSplitBundleV5(bundle)) {
4921
- return this.processInstantSplitBundleSync(bundle, senderPubkey);
4933
+ return this.processInstantSplitBundleSync(bundle, senderPubkey, memo);
4922
4934
  }
4923
4935
  try {
4924
4936
  const deterministicId = `v5split_${bundle.splitGroupId}`;
@@ -4948,12 +4960,26 @@ var PaymentsModule = class _PaymentsModule {
4948
4960
  updatedAt: Date.now(),
4949
4961
  sdkData: JSON.stringify({ _pendingFinalization: pendingData })
4950
4962
  };
4951
- await this.addToken(uiToken, false);
4963
+ await this.addToken(uiToken);
4952
4964
  this.log(`V5 bundle saved as unconfirmed: ${uiToken.id.slice(0, 8)}...`);
4965
+ const senderInfo = await this.resolveSenderInfo(senderPubkey);
4966
+ await this.addToHistory({
4967
+ type: "RECEIVED",
4968
+ amount: bundle.amount,
4969
+ coinId: bundle.coinId,
4970
+ symbol: uiToken.symbol,
4971
+ timestamp: Date.now(),
4972
+ senderPubkey,
4973
+ ...senderInfo,
4974
+ memo,
4975
+ tokenId: deterministicId
4976
+ });
4953
4977
  this.deps.emitEvent("transfer:incoming", {
4954
4978
  id: bundle.splitGroupId,
4955
4979
  senderPubkey,
4980
+ senderNametag: senderInfo.senderNametag,
4956
4981
  tokens: [uiToken],
4982
+ memo,
4957
4983
  receivedAt: Date.now()
4958
4984
  });
4959
4985
  await this.save();
@@ -4973,7 +4999,7 @@ var PaymentsModule = class _PaymentsModule {
4973
4999
  * Synchronous V4 bundle processing (dev mode only).
4974
5000
  * Kept for backward compatibility with V4 bundles.
4975
5001
  */
4976
- async processInstantSplitBundleSync(bundle, senderPubkey) {
5002
+ async processInstantSplitBundleSync(bundle, senderPubkey, memo) {
4977
5003
  try {
4978
5004
  const signingService = await this.createSigningService();
4979
5005
  const stClient = this.deps.oracle.getStateTransitionClient?.();
@@ -5033,19 +5059,26 @@ var PaymentsModule = class _PaymentsModule {
5033
5059
  sdkData: JSON.stringify(tokenData)
5034
5060
  };
5035
5061
  await this.addToken(uiToken);
5062
+ const receivedTokenId = extractTokenIdFromSdkData(uiToken.sdkData);
5063
+ const senderInfo = await this.resolveSenderInfo(senderPubkey);
5036
5064
  await this.addToHistory({
5037
5065
  type: "RECEIVED",
5038
5066
  amount: bundle.amount,
5039
5067
  coinId: info.coinId,
5040
5068
  symbol: info.symbol,
5041
5069
  timestamp: Date.now(),
5042
- senderPubkey
5070
+ senderPubkey,
5071
+ ...senderInfo,
5072
+ memo,
5073
+ tokenId: receivedTokenId || uiToken.id
5043
5074
  });
5044
5075
  await this.save();
5045
5076
  this.deps.emitEvent("transfer:incoming", {
5046
5077
  id: bundle.splitGroupId,
5047
5078
  senderPubkey,
5079
+ senderNametag: senderInfo.senderNametag,
5048
5080
  tokens: [uiToken],
5081
+ memo,
5049
5082
  receivedAt: Date.now()
5050
5083
  });
5051
5084
  }
@@ -5788,14 +5821,6 @@ var PaymentsModule = class _PaymentsModule {
5788
5821
  sdkData: JSON.stringify(finalizedToken.toJSON())
5789
5822
  };
5790
5823
  this.tokens.set(tokenId, confirmedToken);
5791
- await this.addToHistory({
5792
- type: "RECEIVED",
5793
- amount: confirmedToken.amount,
5794
- coinId: confirmedToken.coinId,
5795
- symbol: confirmedToken.symbol || "UNK",
5796
- timestamp: Date.now(),
5797
- senderPubkey: pending2.senderPubkey
5798
- });
5799
5824
  this.log(`V5 token resolved: ${tokenId.slice(0, 8)}...`);
5800
5825
  return "resolved";
5801
5826
  }
@@ -5979,10 +6004,9 @@ var PaymentsModule = class _PaymentsModule {
5979
6004
  * the old state is archived and replaced with the incoming one.
5980
6005
  *
5981
6006
  * @param token - The token to add.
5982
- * @param skipHistory - When `true`, do not create a `RECEIVED` transaction history entry (default `false`).
5983
6007
  * @returns `true` if the token was added, `false` if rejected as duplicate or tombstoned.
5984
6008
  */
5985
- async addToken(token, skipHistory = false) {
6009
+ async addToken(token) {
5986
6010
  this.ensureInitialized();
5987
6011
  const incomingTokenId = extractTokenIdFromSdkData(token.sdkData);
5988
6012
  const incomingStateHash = extractStateHashFromSdkData(token.sdkData);
@@ -6028,15 +6052,6 @@ var PaymentsModule = class _PaymentsModule {
6028
6052
  }
6029
6053
  this.tokens.set(token.id, token);
6030
6054
  await this.archiveToken(token);
6031
- if (!skipHistory && token.coinId && token.amount) {
6032
- await this.addToHistory({
6033
- type: "RECEIVED",
6034
- amount: token.amount,
6035
- coinId: token.coinId,
6036
- symbol: token.symbol || "UNK",
6037
- timestamp: token.createdAt || Date.now()
6038
- });
6039
- }
6040
6055
  await this.save();
6041
6056
  this.log(`Added token ${token.id}, total: ${this.tokens.size}`);
6042
6057
  return true;
@@ -6063,7 +6078,7 @@ var PaymentsModule = class _PaymentsModule {
6063
6078
  }
6064
6079
  }
6065
6080
  if (!found) {
6066
- await this.addToken(token, true);
6081
+ await this.addToken(token);
6067
6082
  return;
6068
6083
  }
6069
6084
  await this.archiveToken(token);
@@ -6078,10 +6093,8 @@ var PaymentsModule = class _PaymentsModule {
6078
6093
  * entry is created unless `skipHistory` is `true`.
6079
6094
  *
6080
6095
  * @param tokenId - Local UUID of the token to remove.
6081
- * @param recipientNametag - Optional nametag of the transfer recipient (for history).
6082
- * @param skipHistory - When `true`, skip creating a transaction history entry (default `false`).
6083
6096
  */
6084
- async removeToken(tokenId, recipientNametag, skipHistory = false) {
6097
+ async removeToken(tokenId) {
6085
6098
  this.ensureInitialized();
6086
6099
  const token = this.tokens.get(tokenId);
6087
6100
  if (!token) return;
@@ -6099,16 +6112,6 @@ var PaymentsModule = class _PaymentsModule {
6099
6112
  this.log(`Warning: Could not create tombstone for token ${tokenId.slice(0, 8)}... (missing tokenId or stateHash)`);
6100
6113
  }
6101
6114
  this.tokens.delete(tokenId);
6102
- if (!skipHistory && token.coinId && token.amount) {
6103
- await this.addToHistory({
6104
- type: "SENT",
6105
- amount: token.amount,
6106
- coinId: token.coinId,
6107
- symbol: token.symbol || "UNK",
6108
- timestamp: Date.now(),
6109
- recipientNametag
6110
- });
6111
- }
6112
6115
  await this.save();
6113
6116
  }
6114
6117
  // ===========================================================================
@@ -6333,26 +6336,104 @@ var PaymentsModule = class _PaymentsModule {
6333
6336
  * @returns Array of {@link TransactionHistoryEntry} objects in descending timestamp order.
6334
6337
  */
6335
6338
  getHistory() {
6336
- return [...this.transactionHistory].sort((a, b) => b.timestamp - a.timestamp);
6339
+ return [...this._historyCache].sort((a, b) => b.timestamp - a.timestamp);
6340
+ }
6341
+ /**
6342
+ * Best-effort resolve sender's DIRECT address and nametag from their transport pubkey.
6343
+ * Returns empty object if transport doesn't support resolution or lookup fails.
6344
+ */
6345
+ async resolveSenderInfo(senderTransportPubkey) {
6346
+ try {
6347
+ if (this.deps?.transport?.resolveTransportPubkeyInfo) {
6348
+ const peerInfo = await this.deps.transport.resolveTransportPubkeyInfo(senderTransportPubkey);
6349
+ if (peerInfo) {
6350
+ return {
6351
+ senderAddress: peerInfo.directAddress || void 0,
6352
+ senderNametag: peerInfo.nametag || void 0
6353
+ };
6354
+ }
6355
+ }
6356
+ } catch {
6357
+ }
6358
+ return {};
6337
6359
  }
6338
6360
  /**
6339
6361
  * Append an entry to the transaction history.
6340
6362
  *
6341
- * A unique `id` is auto-generated. The entry is immediately persisted to storage.
6363
+ * A unique `id` and `dedupKey` are auto-generated. The entry is persisted to
6364
+ * the local token storage provider's `history` store (IndexedDB / file).
6365
+ * Duplicate entries with the same `dedupKey` are silently ignored (upsert).
6342
6366
  *
6343
- * @param entry - History entry fields (without `id`).
6367
+ * @param entry - History entry fields (without `id` and `dedupKey`).
6344
6368
  */
6345
6369
  async addToHistory(entry) {
6346
6370
  this.ensureInitialized();
6371
+ const dedupKey = computeHistoryDedupKey(entry.type, entry.tokenId, entry.transferId);
6347
6372
  const historyEntry = {
6348
6373
  id: crypto.randomUUID(),
6374
+ dedupKey,
6349
6375
  ...entry
6350
6376
  };
6351
- this.transactionHistory.push(historyEntry);
6352
- await this.deps.storage.set(
6353
- STORAGE_KEYS_ADDRESS.TRANSACTION_HISTORY,
6354
- JSON.stringify(this.transactionHistory)
6355
- );
6377
+ const provider = this.getLocalTokenStorageProvider();
6378
+ if (provider?.addHistoryEntry) {
6379
+ await provider.addHistoryEntry(historyEntry);
6380
+ }
6381
+ const existingIdx = this._historyCache.findIndex((e) => e.dedupKey === dedupKey);
6382
+ if (existingIdx >= 0) {
6383
+ this._historyCache[existingIdx] = historyEntry;
6384
+ } else {
6385
+ this._historyCache.push(historyEntry);
6386
+ }
6387
+ this.deps.emitEvent("history:updated", historyEntry);
6388
+ }
6389
+ /**
6390
+ * Load history from the local token storage provider into the in-memory cache.
6391
+ * Also performs one-time migration from legacy KV storage.
6392
+ */
6393
+ async loadHistory() {
6394
+ const provider = this.getLocalTokenStorageProvider();
6395
+ if (provider?.getHistoryEntries) {
6396
+ this._historyCache = await provider.getHistoryEntries();
6397
+ const legacyData = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.TRANSACTION_HISTORY);
6398
+ if (legacyData) {
6399
+ try {
6400
+ const legacyEntries = JSON.parse(legacyData);
6401
+ const records = legacyEntries.map((e) => ({
6402
+ ...e,
6403
+ dedupKey: e.dedupKey || computeHistoryDedupKey(e.type, e.tokenId, e.transferId)
6404
+ }));
6405
+ const imported = await provider.importHistoryEntries?.(records) ?? 0;
6406
+ if (imported > 0) {
6407
+ this._historyCache = await provider.getHistoryEntries();
6408
+ this.log(`Migrated ${imported} history entries from KV to history store`);
6409
+ }
6410
+ await this.deps.storage.remove(STORAGE_KEYS_ADDRESS.TRANSACTION_HISTORY);
6411
+ } catch {
6412
+ }
6413
+ }
6414
+ } else {
6415
+ const historyData = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.TRANSACTION_HISTORY);
6416
+ if (historyData) {
6417
+ try {
6418
+ this._historyCache = JSON.parse(historyData);
6419
+ } catch {
6420
+ this._historyCache = [];
6421
+ }
6422
+ }
6423
+ }
6424
+ }
6425
+ /**
6426
+ * Get the first local token storage provider (for history operations).
6427
+ */
6428
+ getLocalTokenStorageProvider() {
6429
+ const providers = this.getTokenStorageProviders();
6430
+ for (const [, provider] of providers) {
6431
+ if (provider.type === "local") return provider;
6432
+ }
6433
+ for (const [, provider] of providers) {
6434
+ return provider;
6435
+ }
6436
+ return null;
6356
6437
  }
6357
6438
  // ===========================================================================
6358
6439
  // Public API - Nametag
@@ -6895,14 +6976,27 @@ var PaymentsModule = class _PaymentsModule {
6895
6976
  this.tokens.set(token.id, token);
6896
6977
  await this.save();
6897
6978
  this.log(`NOSTR-FIRST: Token ${token.id.slice(0, 8)}... added as submitted (unconfirmed)`);
6979
+ const senderInfo = await this.resolveSenderInfo(transfer.senderTransportPubkey);
6898
6980
  const incomingTransfer = {
6899
6981
  id: transfer.id,
6900
6982
  senderPubkey: transfer.senderTransportPubkey,
6983
+ senderNametag: senderInfo.senderNametag,
6901
6984
  tokens: [token],
6902
6985
  memo: payload.memo,
6903
6986
  receivedAt: transfer.timestamp
6904
6987
  };
6905
6988
  this.deps.emitEvent("transfer:incoming", incomingTransfer);
6989
+ await this.addToHistory({
6990
+ type: "RECEIVED",
6991
+ amount: token.amount,
6992
+ coinId: token.coinId,
6993
+ symbol: token.symbol,
6994
+ timestamp: Date.now(),
6995
+ senderPubkey: transfer.senderTransportPubkey,
6996
+ ...senderInfo,
6997
+ memo: payload.memo,
6998
+ tokenId: nostrTokenId || token.id
6999
+ });
6906
7000
  try {
6907
7001
  const commitment = await import_TransferCommitment4.TransferCommitment.fromJSON(commitmentInput);
6908
7002
  const requestIdBytes = commitment.requestId;
@@ -6920,7 +7014,7 @@ var PaymentsModule = class _PaymentsModule {
6920
7014
  attemptCount: 0,
6921
7015
  lastAttemptAt: 0,
6922
7016
  onProofReceived: async (tokenId) => {
6923
- await this.finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput, transfer.senderTransportPubkey);
7017
+ await this.finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput);
6924
7018
  }
6925
7019
  });
6926
7020
  } catch (err) {
@@ -6979,7 +7073,7 @@ var PaymentsModule = class _PaymentsModule {
6979
7073
  /**
6980
7074
  * Finalize a received token after proof is available
6981
7075
  */
6982
- async finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput, senderPubkey) {
7076
+ async finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput) {
6983
7077
  try {
6984
7078
  const token = this.tokens.get(tokenId);
6985
7079
  if (!token) {
@@ -7027,14 +7121,6 @@ var PaymentsModule = class _PaymentsModule {
7027
7121
  tokens: [finalizedToken],
7028
7122
  tokenTransfers: []
7029
7123
  });
7030
- await this.addToHistory({
7031
- type: "RECEIVED",
7032
- amount: finalizedToken.amount,
7033
- coinId: finalizedToken.coinId,
7034
- symbol: finalizedToken.symbol,
7035
- timestamp: Date.now(),
7036
- senderPubkey
7037
- });
7038
7124
  } catch (error) {
7039
7125
  console.error("[Payments] Failed to finalize received token:", error);
7040
7126
  const token = this.tokens.get(tokenId);
@@ -7065,7 +7151,8 @@ var PaymentsModule = class _PaymentsModule {
7065
7151
  try {
7066
7152
  const result = await this.processInstantSplitBundle(
7067
7153
  instantBundle,
7068
- transfer.senderTransportPubkey
7154
+ transfer.senderTransportPubkey,
7155
+ payload.memo
7069
7156
  );
7070
7157
  if (result.success) {
7071
7158
  this.log("INSTANT_SPLIT processed successfully");
@@ -7183,10 +7270,26 @@ var PaymentsModule = class _PaymentsModule {
7183
7270
  updatedAt: Date.now(),
7184
7271
  sdkData: typeof tokenData === "string" ? tokenData : JSON.stringify(tokenData)
7185
7272
  };
7186
- await this.addToken(token);
7273
+ const added = await this.addToken(token);
7274
+ const senderInfo = await this.resolveSenderInfo(transfer.senderTransportPubkey);
7275
+ if (added) {
7276
+ const incomingTokenId = extractTokenIdFromSdkData(token.sdkData);
7277
+ await this.addToHistory({
7278
+ type: "RECEIVED",
7279
+ amount: token.amount,
7280
+ coinId: token.coinId,
7281
+ symbol: token.symbol,
7282
+ timestamp: Date.now(),
7283
+ senderPubkey: transfer.senderTransportPubkey,
7284
+ ...senderInfo,
7285
+ memo: payload.memo,
7286
+ tokenId: incomingTokenId || token.id
7287
+ });
7288
+ }
7187
7289
  const incomingTransfer = {
7188
7290
  id: transfer.id,
7189
7291
  senderPubkey: transfer.senderTransportPubkey,
7292
+ senderNametag: senderInfo.senderNametag,
7190
7293
  tokens: [token],
7191
7294
  memo: payload.memo,
7192
7295
  receivedAt: transfer.timestamp