@unicitylabs/sphere-sdk 0.4.9 → 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/index.js CHANGED
@@ -3713,7 +3713,7 @@ var InstantSplitExecutor = class {
3713
3713
  token: JSON.stringify(bundle),
3714
3714
  proof: null,
3715
3715
  // Proof is included in the bundle
3716
- memo: "INSTANT_SPLIT_V5",
3716
+ memo: options?.memo,
3717
3717
  sender: {
3718
3718
  transportPubkey: senderPubkey
3719
3719
  }
@@ -4272,6 +4272,11 @@ import { MintCommitment as MintCommitment3 } from "@unicitylabs/state-transition
4272
4272
  import { MintTransactionData as MintTransactionData3 } from "@unicitylabs/state-transition-sdk/lib/transaction/MintTransactionData";
4273
4273
  import { waitInclusionProof as waitInclusionProof5 } from "@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils";
4274
4274
  import { InclusionProof } from "@unicitylabs/state-transition-sdk/lib/transaction/InclusionProof";
4275
+ function computeHistoryDedupKey(type, tokenId, transferId) {
4276
+ if (type === "SENT" && transferId) return `${type}_transfer_${transferId}`;
4277
+ if (tokenId) return `${type}_${tokenId}`;
4278
+ return `${type}_${crypto.randomUUID()}`;
4279
+ }
4275
4280
  function enrichWithRegistry(info) {
4276
4281
  const registry = TokenRegistry.getInstance();
4277
4282
  const def = registry.getDefinition(info.coinId);
@@ -4570,7 +4575,7 @@ var PaymentsModule = class _PaymentsModule {
4570
4575
  tombstones = [];
4571
4576
  archivedTokens = /* @__PURE__ */ new Map();
4572
4577
  forkedTokens = /* @__PURE__ */ new Map();
4573
- transactionHistory = [];
4578
+ _historyCache = [];
4574
4579
  nametags = [];
4575
4580
  // Payment Requests State (Incoming)
4576
4581
  paymentRequests = [];
@@ -4639,7 +4644,7 @@ var PaymentsModule = class _PaymentsModule {
4639
4644
  this.tombstones = [];
4640
4645
  this.archivedTokens.clear();
4641
4646
  this.forkedTokens.clear();
4642
- this.transactionHistory = [];
4647
+ this._historyCache = [];
4643
4648
  this.nametags = [];
4644
4649
  this.deps = deps;
4645
4650
  this.priceProvider = deps.price ?? null;
@@ -4690,14 +4695,7 @@ var PaymentsModule = class _PaymentsModule {
4690
4695
  }
4691
4696
  }
4692
4697
  await this.loadPendingV5Tokens();
4693
- const historyData = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.TRANSACTION_HISTORY);
4694
- if (historyData) {
4695
- try {
4696
- this.transactionHistory = JSON.parse(historyData);
4697
- } catch {
4698
- this.transactionHistory = [];
4699
- }
4700
- }
4698
+ await this.loadHistory();
4701
4699
  const pending2 = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.PENDING_TRANSFERS);
4702
4700
  if (pending2) {
4703
4701
  const transfers = JSON.parse(pending2);
@@ -4784,7 +4782,7 @@ var PaymentsModule = class _PaymentsModule {
4784
4782
  }
4785
4783
  await this.saveToOutbox(result, recipientPubkey);
4786
4784
  result.status = "submitted";
4787
- const recipientNametag = request.recipient.startsWith("@") ? request.recipient.slice(1) : void 0;
4785
+ const recipientNametag = peerInfo?.nametag || (request.recipient.startsWith("@") ? request.recipient.slice(1) : void 0);
4788
4786
  const transferMode = request.transferMode ?? "instant";
4789
4787
  if (splitPlan.requiresSplit && splitPlan.tokenToSplit) {
4790
4788
  if (transferMode === "conservative") {
@@ -4815,7 +4813,7 @@ var PaymentsModule = class _PaymentsModule {
4815
4813
  updatedAt: Date.now(),
4816
4814
  sdkData: JSON.stringify(changeTokenData)
4817
4815
  };
4818
- await this.addToken(changeUiToken, true);
4816
+ await this.addToken(changeUiToken);
4819
4817
  this.log(`Conservative split: change token saved: ${changeUiToken.id}`);
4820
4818
  await this.deps.transport.sendTokenTransfer(recipientPubkey, {
4821
4819
  sourceToken: JSON.stringify(splitResult.tokenForRecipient.toJSON()),
@@ -4824,7 +4822,7 @@ var PaymentsModule = class _PaymentsModule {
4824
4822
  });
4825
4823
  const splitCommitmentRequestId = splitResult.recipientTransferTx?.data?.requestId ?? splitResult.recipientTransferTx?.requestId;
4826
4824
  const splitRequestIdHex = splitCommitmentRequestId instanceof Uint8Array ? Array.from(splitCommitmentRequestId).map((b) => b.toString(16).padStart(2, "0")).join("") : splitCommitmentRequestId ? String(splitCommitmentRequestId) : void 0;
4827
- await this.removeToken(splitPlan.tokenToSplit.uiToken.id, recipientNametag, true);
4825
+ await this.removeToken(splitPlan.tokenToSplit.uiToken.id);
4828
4826
  result.tokenTransfers.push({
4829
4827
  sourceTokenId: splitPlan.tokenToSplit.uiToken.id,
4830
4828
  method: "split",
@@ -4849,6 +4847,7 @@ var PaymentsModule = class _PaymentsModule {
4849
4847
  this.deps.transport,
4850
4848
  recipientPubkey,
4851
4849
  {
4850
+ memo: request.memo,
4852
4851
  onChangeTokenCreated: async (changeToken) => {
4853
4852
  const changeTokenData = changeToken.toJSON();
4854
4853
  const uiToken = {
@@ -4864,7 +4863,7 @@ var PaymentsModule = class _PaymentsModule {
4864
4863
  updatedAt: Date.now(),
4865
4864
  sdkData: JSON.stringify(changeTokenData)
4866
4865
  };
4867
- await this.addToken(uiToken, true);
4866
+ await this.addToken(uiToken);
4868
4867
  this.log(`Change token saved via background: ${uiToken.id}`);
4869
4868
  },
4870
4869
  onStorageSync: async () => {
@@ -4879,7 +4878,7 @@ var PaymentsModule = class _PaymentsModule {
4879
4878
  if (instantResult.backgroundPromise) {
4880
4879
  this.pendingBackgroundTasks.push(instantResult.backgroundPromise);
4881
4880
  }
4882
- await this.removeToken(splitPlan.tokenToSplit.uiToken.id, recipientNametag);
4881
+ await this.removeToken(splitPlan.tokenToSplit.uiToken.id);
4883
4882
  result.tokenTransfers.push({
4884
4883
  sourceTokenId: splitPlan.tokenToSplit.uiToken.id,
4885
4884
  method: "split",
@@ -4926,20 +4925,25 @@ var PaymentsModule = class _PaymentsModule {
4926
4925
  requestIdHex
4927
4926
  });
4928
4927
  this.log(`Token ${token.id} sent via ${transferMode.toUpperCase()}, requestId: ${requestIdHex}`);
4929
- await this.removeToken(token.id, recipientNametag, true);
4928
+ await this.removeToken(token.id);
4930
4929
  }
4931
4930
  result.status = "delivered";
4932
4931
  await this.save();
4933
4932
  await this.removeFromOutbox(result.id);
4934
4933
  result.status = "completed";
4934
+ const sentTokenId = result.tokens[0] ? extractTokenIdFromSdkData(result.tokens[0].sdkData) : void 0;
4935
4935
  await this.addToHistory({
4936
4936
  type: "SENT",
4937
4937
  amount: request.amount,
4938
4938
  coinId: request.coinId,
4939
4939
  symbol: this.getCoinSymbol(request.coinId),
4940
4940
  timestamp: Date.now(),
4941
+ recipientPubkey,
4941
4942
  recipientNametag,
4942
- transferId: result.id
4943
+ recipientAddress: peerInfo?.directAddress || recipientAddress?.toString() || recipientPubkey,
4944
+ memo: request.memo,
4945
+ transferId: result.id,
4946
+ tokenId: sentTokenId || void 0
4943
4947
  });
4944
4948
  this.deps.emitEvent("transfer:confirmed", result);
4945
4949
  return result;
@@ -5050,6 +5054,7 @@ var PaymentsModule = class _PaymentsModule {
5050
5054
  recipientPubkey,
5051
5055
  {
5052
5056
  ...options,
5057
+ memo: request.memo,
5053
5058
  onChangeTokenCreated: async (changeToken) => {
5054
5059
  const changeTokenData = changeToken.toJSON();
5055
5060
  const uiToken = {
@@ -5065,7 +5070,7 @@ var PaymentsModule = class _PaymentsModule {
5065
5070
  updatedAt: Date.now(),
5066
5071
  sdkData: JSON.stringify(changeTokenData)
5067
5072
  };
5068
- await this.addToken(uiToken, true);
5073
+ await this.addToken(uiToken);
5069
5074
  this.log(`Change token saved via background: ${uiToken.id}`);
5070
5075
  },
5071
5076
  onStorageSync: async () => {
@@ -5078,15 +5083,20 @@ var PaymentsModule = class _PaymentsModule {
5078
5083
  if (result.backgroundPromise) {
5079
5084
  this.pendingBackgroundTasks.push(result.backgroundPromise);
5080
5085
  }
5081
- const recipientNametag = request.recipient.startsWith("@") ? request.recipient.slice(1) : void 0;
5082
- await this.removeToken(tokenToSplit.id, recipientNametag, true);
5086
+ await this.removeToken(tokenToSplit.id);
5087
+ const recipientNametag = peerInfo?.nametag || (request.recipient.startsWith("@") ? request.recipient.slice(1) : void 0);
5088
+ const splitTokenId = extractTokenIdFromSdkData(tokenToSplit.sdkData);
5083
5089
  await this.addToHistory({
5084
5090
  type: "SENT",
5085
5091
  amount: request.amount,
5086
5092
  coinId: request.coinId,
5087
5093
  symbol: this.getCoinSymbol(request.coinId),
5088
5094
  timestamp: Date.now(),
5089
- recipientNametag
5095
+ recipientPubkey,
5096
+ recipientNametag,
5097
+ recipientAddress: peerInfo?.directAddress || recipientAddress?.toString() || recipientPubkey,
5098
+ memo: request.memo,
5099
+ tokenId: splitTokenId || void 0
5090
5100
  });
5091
5101
  await this.save();
5092
5102
  } else {
@@ -5117,10 +5127,10 @@ var PaymentsModule = class _PaymentsModule {
5117
5127
  * @param senderPubkey - Sender's public key for verification
5118
5128
  * @returns Processing result with finalized token
5119
5129
  */
5120
- async processInstantSplitBundle(bundle, senderPubkey) {
5130
+ async processInstantSplitBundle(bundle, senderPubkey, memo) {
5121
5131
  this.ensureInitialized();
5122
5132
  if (!isInstantSplitBundleV5(bundle)) {
5123
- return this.processInstantSplitBundleSync(bundle, senderPubkey);
5133
+ return this.processInstantSplitBundleSync(bundle, senderPubkey, memo);
5124
5134
  }
5125
5135
  try {
5126
5136
  const deterministicId = `v5split_${bundle.splitGroupId}`;
@@ -5150,12 +5160,26 @@ var PaymentsModule = class _PaymentsModule {
5150
5160
  updatedAt: Date.now(),
5151
5161
  sdkData: JSON.stringify({ _pendingFinalization: pendingData })
5152
5162
  };
5153
- await this.addToken(uiToken, false);
5163
+ await this.addToken(uiToken);
5154
5164
  this.log(`V5 bundle saved as unconfirmed: ${uiToken.id.slice(0, 8)}...`);
5165
+ const senderInfo = await this.resolveSenderInfo(senderPubkey);
5166
+ await this.addToHistory({
5167
+ type: "RECEIVED",
5168
+ amount: bundle.amount,
5169
+ coinId: bundle.coinId,
5170
+ symbol: uiToken.symbol,
5171
+ timestamp: Date.now(),
5172
+ senderPubkey,
5173
+ ...senderInfo,
5174
+ memo,
5175
+ tokenId: deterministicId
5176
+ });
5155
5177
  this.deps.emitEvent("transfer:incoming", {
5156
5178
  id: bundle.splitGroupId,
5157
5179
  senderPubkey,
5180
+ senderNametag: senderInfo.senderNametag,
5158
5181
  tokens: [uiToken],
5182
+ memo,
5159
5183
  receivedAt: Date.now()
5160
5184
  });
5161
5185
  await this.save();
@@ -5175,7 +5199,7 @@ var PaymentsModule = class _PaymentsModule {
5175
5199
  * Synchronous V4 bundle processing (dev mode only).
5176
5200
  * Kept for backward compatibility with V4 bundles.
5177
5201
  */
5178
- async processInstantSplitBundleSync(bundle, senderPubkey) {
5202
+ async processInstantSplitBundleSync(bundle, senderPubkey, memo) {
5179
5203
  try {
5180
5204
  const signingService = await this.createSigningService();
5181
5205
  const stClient = this.deps.oracle.getStateTransitionClient?.();
@@ -5235,19 +5259,26 @@ var PaymentsModule = class _PaymentsModule {
5235
5259
  sdkData: JSON.stringify(tokenData)
5236
5260
  };
5237
5261
  await this.addToken(uiToken);
5262
+ const receivedTokenId = extractTokenIdFromSdkData(uiToken.sdkData);
5263
+ const senderInfo = await this.resolveSenderInfo(senderPubkey);
5238
5264
  await this.addToHistory({
5239
5265
  type: "RECEIVED",
5240
5266
  amount: bundle.amount,
5241
5267
  coinId: info.coinId,
5242
5268
  symbol: info.symbol,
5243
5269
  timestamp: Date.now(),
5244
- senderPubkey
5270
+ senderPubkey,
5271
+ ...senderInfo,
5272
+ memo,
5273
+ tokenId: receivedTokenId || uiToken.id
5245
5274
  });
5246
5275
  await this.save();
5247
5276
  this.deps.emitEvent("transfer:incoming", {
5248
5277
  id: bundle.splitGroupId,
5249
5278
  senderPubkey,
5279
+ senderNametag: senderInfo.senderNametag,
5250
5280
  tokens: [uiToken],
5281
+ memo,
5251
5282
  receivedAt: Date.now()
5252
5283
  });
5253
5284
  }
@@ -5990,14 +6021,6 @@ var PaymentsModule = class _PaymentsModule {
5990
6021
  sdkData: JSON.stringify(finalizedToken.toJSON())
5991
6022
  };
5992
6023
  this.tokens.set(tokenId, confirmedToken);
5993
- await this.addToHistory({
5994
- type: "RECEIVED",
5995
- amount: confirmedToken.amount,
5996
- coinId: confirmedToken.coinId,
5997
- symbol: confirmedToken.symbol || "UNK",
5998
- timestamp: Date.now(),
5999
- senderPubkey: pending2.senderPubkey
6000
- });
6001
6024
  this.log(`V5 token resolved: ${tokenId.slice(0, 8)}...`);
6002
6025
  return "resolved";
6003
6026
  }
@@ -6181,10 +6204,9 @@ var PaymentsModule = class _PaymentsModule {
6181
6204
  * the old state is archived and replaced with the incoming one.
6182
6205
  *
6183
6206
  * @param token - The token to add.
6184
- * @param skipHistory - When `true`, do not create a `RECEIVED` transaction history entry (default `false`).
6185
6207
  * @returns `true` if the token was added, `false` if rejected as duplicate or tombstoned.
6186
6208
  */
6187
- async addToken(token, skipHistory = false) {
6209
+ async addToken(token) {
6188
6210
  this.ensureInitialized();
6189
6211
  const incomingTokenId = extractTokenIdFromSdkData(token.sdkData);
6190
6212
  const incomingStateHash = extractStateHashFromSdkData(token.sdkData);
@@ -6230,15 +6252,6 @@ var PaymentsModule = class _PaymentsModule {
6230
6252
  }
6231
6253
  this.tokens.set(token.id, token);
6232
6254
  await this.archiveToken(token);
6233
- if (!skipHistory && token.coinId && token.amount) {
6234
- await this.addToHistory({
6235
- type: "RECEIVED",
6236
- amount: token.amount,
6237
- coinId: token.coinId,
6238
- symbol: token.symbol || "UNK",
6239
- timestamp: token.createdAt || Date.now()
6240
- });
6241
- }
6242
6255
  await this.save();
6243
6256
  this.log(`Added token ${token.id}, total: ${this.tokens.size}`);
6244
6257
  return true;
@@ -6265,7 +6278,7 @@ var PaymentsModule = class _PaymentsModule {
6265
6278
  }
6266
6279
  }
6267
6280
  if (!found) {
6268
- await this.addToken(token, true);
6281
+ await this.addToken(token);
6269
6282
  return;
6270
6283
  }
6271
6284
  await this.archiveToken(token);
@@ -6280,10 +6293,8 @@ var PaymentsModule = class _PaymentsModule {
6280
6293
  * entry is created unless `skipHistory` is `true`.
6281
6294
  *
6282
6295
  * @param tokenId - Local UUID of the token to remove.
6283
- * @param recipientNametag - Optional nametag of the transfer recipient (for history).
6284
- * @param skipHistory - When `true`, skip creating a transaction history entry (default `false`).
6285
6296
  */
6286
- async removeToken(tokenId, recipientNametag, skipHistory = false) {
6297
+ async removeToken(tokenId) {
6287
6298
  this.ensureInitialized();
6288
6299
  const token = this.tokens.get(tokenId);
6289
6300
  if (!token) return;
@@ -6301,16 +6312,6 @@ var PaymentsModule = class _PaymentsModule {
6301
6312
  this.log(`Warning: Could not create tombstone for token ${tokenId.slice(0, 8)}... (missing tokenId or stateHash)`);
6302
6313
  }
6303
6314
  this.tokens.delete(tokenId);
6304
- if (!skipHistory && token.coinId && token.amount) {
6305
- await this.addToHistory({
6306
- type: "SENT",
6307
- amount: token.amount,
6308
- coinId: token.coinId,
6309
- symbol: token.symbol || "UNK",
6310
- timestamp: Date.now(),
6311
- recipientNametag
6312
- });
6313
- }
6314
6315
  await this.save();
6315
6316
  }
6316
6317
  // ===========================================================================
@@ -6535,26 +6536,104 @@ var PaymentsModule = class _PaymentsModule {
6535
6536
  * @returns Array of {@link TransactionHistoryEntry} objects in descending timestamp order.
6536
6537
  */
6537
6538
  getHistory() {
6538
- return [...this.transactionHistory].sort((a, b) => b.timestamp - a.timestamp);
6539
+ return [...this._historyCache].sort((a, b) => b.timestamp - a.timestamp);
6540
+ }
6541
+ /**
6542
+ * Best-effort resolve sender's DIRECT address and nametag from their transport pubkey.
6543
+ * Returns empty object if transport doesn't support resolution or lookup fails.
6544
+ */
6545
+ async resolveSenderInfo(senderTransportPubkey) {
6546
+ try {
6547
+ if (this.deps?.transport?.resolveTransportPubkeyInfo) {
6548
+ const peerInfo = await this.deps.transport.resolveTransportPubkeyInfo(senderTransportPubkey);
6549
+ if (peerInfo) {
6550
+ return {
6551
+ senderAddress: peerInfo.directAddress || void 0,
6552
+ senderNametag: peerInfo.nametag || void 0
6553
+ };
6554
+ }
6555
+ }
6556
+ } catch {
6557
+ }
6558
+ return {};
6539
6559
  }
6540
6560
  /**
6541
6561
  * Append an entry to the transaction history.
6542
6562
  *
6543
- * A unique `id` is auto-generated. The entry is immediately persisted to storage.
6563
+ * A unique `id` and `dedupKey` are auto-generated. The entry is persisted to
6564
+ * the local token storage provider's `history` store (IndexedDB / file).
6565
+ * Duplicate entries with the same `dedupKey` are silently ignored (upsert).
6544
6566
  *
6545
- * @param entry - History entry fields (without `id`).
6567
+ * @param entry - History entry fields (without `id` and `dedupKey`).
6546
6568
  */
6547
6569
  async addToHistory(entry) {
6548
6570
  this.ensureInitialized();
6571
+ const dedupKey = computeHistoryDedupKey(entry.type, entry.tokenId, entry.transferId);
6549
6572
  const historyEntry = {
6550
6573
  id: crypto.randomUUID(),
6574
+ dedupKey,
6551
6575
  ...entry
6552
6576
  };
6553
- this.transactionHistory.push(historyEntry);
6554
- await this.deps.storage.set(
6555
- STORAGE_KEYS_ADDRESS.TRANSACTION_HISTORY,
6556
- JSON.stringify(this.transactionHistory)
6557
- );
6577
+ const provider = this.getLocalTokenStorageProvider();
6578
+ if (provider?.addHistoryEntry) {
6579
+ await provider.addHistoryEntry(historyEntry);
6580
+ }
6581
+ const existingIdx = this._historyCache.findIndex((e) => e.dedupKey === dedupKey);
6582
+ if (existingIdx >= 0) {
6583
+ this._historyCache[existingIdx] = historyEntry;
6584
+ } else {
6585
+ this._historyCache.push(historyEntry);
6586
+ }
6587
+ this.deps.emitEvent("history:updated", historyEntry);
6588
+ }
6589
+ /**
6590
+ * Load history from the local token storage provider into the in-memory cache.
6591
+ * Also performs one-time migration from legacy KV storage.
6592
+ */
6593
+ async loadHistory() {
6594
+ const provider = this.getLocalTokenStorageProvider();
6595
+ if (provider?.getHistoryEntries) {
6596
+ this._historyCache = await provider.getHistoryEntries();
6597
+ const legacyData = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.TRANSACTION_HISTORY);
6598
+ if (legacyData) {
6599
+ try {
6600
+ const legacyEntries = JSON.parse(legacyData);
6601
+ const records = legacyEntries.map((e) => ({
6602
+ ...e,
6603
+ dedupKey: e.dedupKey || computeHistoryDedupKey(e.type, e.tokenId, e.transferId)
6604
+ }));
6605
+ const imported = await provider.importHistoryEntries?.(records) ?? 0;
6606
+ if (imported > 0) {
6607
+ this._historyCache = await provider.getHistoryEntries();
6608
+ this.log(`Migrated ${imported} history entries from KV to history store`);
6609
+ }
6610
+ await this.deps.storage.remove(STORAGE_KEYS_ADDRESS.TRANSACTION_HISTORY);
6611
+ } catch {
6612
+ }
6613
+ }
6614
+ } else {
6615
+ const historyData = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.TRANSACTION_HISTORY);
6616
+ if (historyData) {
6617
+ try {
6618
+ this._historyCache = JSON.parse(historyData);
6619
+ } catch {
6620
+ this._historyCache = [];
6621
+ }
6622
+ }
6623
+ }
6624
+ }
6625
+ /**
6626
+ * Get the first local token storage provider (for history operations).
6627
+ */
6628
+ getLocalTokenStorageProvider() {
6629
+ const providers = this.getTokenStorageProviders();
6630
+ for (const [, provider] of providers) {
6631
+ if (provider.type === "local") return provider;
6632
+ }
6633
+ for (const [, provider] of providers) {
6634
+ return provider;
6635
+ }
6636
+ return null;
6558
6637
  }
6559
6638
  // ===========================================================================
6560
6639
  // Public API - Nametag
@@ -7097,14 +7176,27 @@ var PaymentsModule = class _PaymentsModule {
7097
7176
  this.tokens.set(token.id, token);
7098
7177
  await this.save();
7099
7178
  this.log(`NOSTR-FIRST: Token ${token.id.slice(0, 8)}... added as submitted (unconfirmed)`);
7179
+ const senderInfo = await this.resolveSenderInfo(transfer.senderTransportPubkey);
7100
7180
  const incomingTransfer = {
7101
7181
  id: transfer.id,
7102
7182
  senderPubkey: transfer.senderTransportPubkey,
7183
+ senderNametag: senderInfo.senderNametag,
7103
7184
  tokens: [token],
7104
7185
  memo: payload.memo,
7105
7186
  receivedAt: transfer.timestamp
7106
7187
  };
7107
7188
  this.deps.emitEvent("transfer:incoming", incomingTransfer);
7189
+ await this.addToHistory({
7190
+ type: "RECEIVED",
7191
+ amount: token.amount,
7192
+ coinId: token.coinId,
7193
+ symbol: token.symbol,
7194
+ timestamp: Date.now(),
7195
+ senderPubkey: transfer.senderTransportPubkey,
7196
+ ...senderInfo,
7197
+ memo: payload.memo,
7198
+ tokenId: nostrTokenId || token.id
7199
+ });
7108
7200
  try {
7109
7201
  const commitment = await TransferCommitment4.fromJSON(commitmentInput);
7110
7202
  const requestIdBytes = commitment.requestId;
@@ -7122,7 +7214,7 @@ var PaymentsModule = class _PaymentsModule {
7122
7214
  attemptCount: 0,
7123
7215
  lastAttemptAt: 0,
7124
7216
  onProofReceived: async (tokenId) => {
7125
- await this.finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput, transfer.senderTransportPubkey);
7217
+ await this.finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput);
7126
7218
  }
7127
7219
  });
7128
7220
  } catch (err) {
@@ -7181,7 +7273,7 @@ var PaymentsModule = class _PaymentsModule {
7181
7273
  /**
7182
7274
  * Finalize a received token after proof is available
7183
7275
  */
7184
- async finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput, senderPubkey) {
7276
+ async finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput) {
7185
7277
  try {
7186
7278
  const token = this.tokens.get(tokenId);
7187
7279
  if (!token) {
@@ -7229,14 +7321,6 @@ var PaymentsModule = class _PaymentsModule {
7229
7321
  tokens: [finalizedToken],
7230
7322
  tokenTransfers: []
7231
7323
  });
7232
- await this.addToHistory({
7233
- type: "RECEIVED",
7234
- amount: finalizedToken.amount,
7235
- coinId: finalizedToken.coinId,
7236
- symbol: finalizedToken.symbol,
7237
- timestamp: Date.now(),
7238
- senderPubkey
7239
- });
7240
7324
  } catch (error) {
7241
7325
  console.error("[Payments] Failed to finalize received token:", error);
7242
7326
  const token = this.tokens.get(tokenId);
@@ -7267,7 +7351,8 @@ var PaymentsModule = class _PaymentsModule {
7267
7351
  try {
7268
7352
  const result = await this.processInstantSplitBundle(
7269
7353
  instantBundle,
7270
- transfer.senderTransportPubkey
7354
+ transfer.senderTransportPubkey,
7355
+ payload.memo
7271
7356
  );
7272
7357
  if (result.success) {
7273
7358
  this.log("INSTANT_SPLIT processed successfully");
@@ -7385,10 +7470,26 @@ var PaymentsModule = class _PaymentsModule {
7385
7470
  updatedAt: Date.now(),
7386
7471
  sdkData: typeof tokenData === "string" ? tokenData : JSON.stringify(tokenData)
7387
7472
  };
7388
- await this.addToken(token);
7473
+ const added = await this.addToken(token);
7474
+ const senderInfo = await this.resolveSenderInfo(transfer.senderTransportPubkey);
7475
+ if (added) {
7476
+ const incomingTokenId = extractTokenIdFromSdkData(token.sdkData);
7477
+ await this.addToHistory({
7478
+ type: "RECEIVED",
7479
+ amount: token.amount,
7480
+ coinId: token.coinId,
7481
+ symbol: token.symbol,
7482
+ timestamp: Date.now(),
7483
+ senderPubkey: transfer.senderTransportPubkey,
7484
+ ...senderInfo,
7485
+ memo: payload.memo,
7486
+ tokenId: incomingTokenId || token.id
7487
+ });
7488
+ }
7389
7489
  const incomingTransfer = {
7390
7490
  id: transfer.id,
7391
7491
  senderPubkey: transfer.senderTransportPubkey,
7492
+ senderNametag: senderInfo.senderNametag,
7392
7493
  tokens: [token],
7393
7494
  memo: payload.memo,
7394
7495
  receivedAt: transfer.timestamp