@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/core/index.cjs +181 -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 +181 -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 +181 -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 +181 -80
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/core/index.cjs
CHANGED
|
@@ -3513,7 +3513,7 @@ var InstantSplitExecutor = class {
|
|
|
3513
3513
|
token: JSON.stringify(bundle),
|
|
3514
3514
|
proof: null,
|
|
3515
3515
|
// Proof is included in the bundle
|
|
3516
|
-
memo:
|
|
3516
|
+
memo: options?.memo,
|
|
3517
3517
|
sender: {
|
|
3518
3518
|
transportPubkey: senderPubkey
|
|
3519
3519
|
}
|
|
@@ -4072,6 +4072,11 @@ var import_MintCommitment3 = require("@unicitylabs/state-transition-sdk/lib/tran
|
|
|
4072
4072
|
var import_MintTransactionData3 = require("@unicitylabs/state-transition-sdk/lib/transaction/MintTransactionData");
|
|
4073
4073
|
var import_InclusionProofUtils5 = require("@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils");
|
|
4074
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
|
+
}
|
|
4075
4080
|
function enrichWithRegistry(info) {
|
|
4076
4081
|
const registry = TokenRegistry.getInstance();
|
|
4077
4082
|
const def = registry.getDefinition(info.coinId);
|
|
@@ -4370,7 +4375,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4370
4375
|
tombstones = [];
|
|
4371
4376
|
archivedTokens = /* @__PURE__ */ new Map();
|
|
4372
4377
|
forkedTokens = /* @__PURE__ */ new Map();
|
|
4373
|
-
|
|
4378
|
+
_historyCache = [];
|
|
4374
4379
|
nametags = [];
|
|
4375
4380
|
// Payment Requests State (Incoming)
|
|
4376
4381
|
paymentRequests = [];
|
|
@@ -4439,7 +4444,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4439
4444
|
this.tombstones = [];
|
|
4440
4445
|
this.archivedTokens.clear();
|
|
4441
4446
|
this.forkedTokens.clear();
|
|
4442
|
-
this.
|
|
4447
|
+
this._historyCache = [];
|
|
4443
4448
|
this.nametags = [];
|
|
4444
4449
|
this.deps = deps;
|
|
4445
4450
|
this.priceProvider = deps.price ?? null;
|
|
@@ -4490,14 +4495,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4490
4495
|
}
|
|
4491
4496
|
}
|
|
4492
4497
|
await this.loadPendingV5Tokens();
|
|
4493
|
-
|
|
4494
|
-
if (historyData) {
|
|
4495
|
-
try {
|
|
4496
|
-
this.transactionHistory = JSON.parse(historyData);
|
|
4497
|
-
} catch {
|
|
4498
|
-
this.transactionHistory = [];
|
|
4499
|
-
}
|
|
4500
|
-
}
|
|
4498
|
+
await this.loadHistory();
|
|
4501
4499
|
const pending2 = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.PENDING_TRANSFERS);
|
|
4502
4500
|
if (pending2) {
|
|
4503
4501
|
const transfers = JSON.parse(pending2);
|
|
@@ -4584,7 +4582,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4584
4582
|
}
|
|
4585
4583
|
await this.saveToOutbox(result, recipientPubkey);
|
|
4586
4584
|
result.status = "submitted";
|
|
4587
|
-
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);
|
|
4588
4586
|
const transferMode = request.transferMode ?? "instant";
|
|
4589
4587
|
if (splitPlan.requiresSplit && splitPlan.tokenToSplit) {
|
|
4590
4588
|
if (transferMode === "conservative") {
|
|
@@ -4615,7 +4613,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4615
4613
|
updatedAt: Date.now(),
|
|
4616
4614
|
sdkData: JSON.stringify(changeTokenData)
|
|
4617
4615
|
};
|
|
4618
|
-
await this.addToken(changeUiToken
|
|
4616
|
+
await this.addToken(changeUiToken);
|
|
4619
4617
|
this.log(`Conservative split: change token saved: ${changeUiToken.id}`);
|
|
4620
4618
|
await this.deps.transport.sendTokenTransfer(recipientPubkey, {
|
|
4621
4619
|
sourceToken: JSON.stringify(splitResult.tokenForRecipient.toJSON()),
|
|
@@ -4624,7 +4622,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4624
4622
|
});
|
|
4625
4623
|
const splitCommitmentRequestId = splitResult.recipientTransferTx?.data?.requestId ?? splitResult.recipientTransferTx?.requestId;
|
|
4626
4624
|
const splitRequestIdHex = splitCommitmentRequestId instanceof Uint8Array ? Array.from(splitCommitmentRequestId).map((b) => b.toString(16).padStart(2, "0")).join("") : splitCommitmentRequestId ? String(splitCommitmentRequestId) : void 0;
|
|
4627
|
-
await this.removeToken(splitPlan.tokenToSplit.uiToken.id
|
|
4625
|
+
await this.removeToken(splitPlan.tokenToSplit.uiToken.id);
|
|
4628
4626
|
result.tokenTransfers.push({
|
|
4629
4627
|
sourceTokenId: splitPlan.tokenToSplit.uiToken.id,
|
|
4630
4628
|
method: "split",
|
|
@@ -4649,6 +4647,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4649
4647
|
this.deps.transport,
|
|
4650
4648
|
recipientPubkey,
|
|
4651
4649
|
{
|
|
4650
|
+
memo: request.memo,
|
|
4652
4651
|
onChangeTokenCreated: async (changeToken) => {
|
|
4653
4652
|
const changeTokenData = changeToken.toJSON();
|
|
4654
4653
|
const uiToken = {
|
|
@@ -4664,7 +4663,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4664
4663
|
updatedAt: Date.now(),
|
|
4665
4664
|
sdkData: JSON.stringify(changeTokenData)
|
|
4666
4665
|
};
|
|
4667
|
-
await this.addToken(uiToken
|
|
4666
|
+
await this.addToken(uiToken);
|
|
4668
4667
|
this.log(`Change token saved via background: ${uiToken.id}`);
|
|
4669
4668
|
},
|
|
4670
4669
|
onStorageSync: async () => {
|
|
@@ -4679,7 +4678,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4679
4678
|
if (instantResult.backgroundPromise) {
|
|
4680
4679
|
this.pendingBackgroundTasks.push(instantResult.backgroundPromise);
|
|
4681
4680
|
}
|
|
4682
|
-
await this.removeToken(splitPlan.tokenToSplit.uiToken.id
|
|
4681
|
+
await this.removeToken(splitPlan.tokenToSplit.uiToken.id);
|
|
4683
4682
|
result.tokenTransfers.push({
|
|
4684
4683
|
sourceTokenId: splitPlan.tokenToSplit.uiToken.id,
|
|
4685
4684
|
method: "split",
|
|
@@ -4726,20 +4725,25 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4726
4725
|
requestIdHex
|
|
4727
4726
|
});
|
|
4728
4727
|
this.log(`Token ${token.id} sent via ${transferMode.toUpperCase()}, requestId: ${requestIdHex}`);
|
|
4729
|
-
await this.removeToken(token.id
|
|
4728
|
+
await this.removeToken(token.id);
|
|
4730
4729
|
}
|
|
4731
4730
|
result.status = "delivered";
|
|
4732
4731
|
await this.save();
|
|
4733
4732
|
await this.removeFromOutbox(result.id);
|
|
4734
4733
|
result.status = "completed";
|
|
4734
|
+
const sentTokenId = result.tokens[0] ? extractTokenIdFromSdkData(result.tokens[0].sdkData) : void 0;
|
|
4735
4735
|
await this.addToHistory({
|
|
4736
4736
|
type: "SENT",
|
|
4737
4737
|
amount: request.amount,
|
|
4738
4738
|
coinId: request.coinId,
|
|
4739
4739
|
symbol: this.getCoinSymbol(request.coinId),
|
|
4740
4740
|
timestamp: Date.now(),
|
|
4741
|
+
recipientPubkey,
|
|
4741
4742
|
recipientNametag,
|
|
4742
|
-
|
|
4743
|
+
recipientAddress: peerInfo?.directAddress || recipientAddress?.toString() || recipientPubkey,
|
|
4744
|
+
memo: request.memo,
|
|
4745
|
+
transferId: result.id,
|
|
4746
|
+
tokenId: sentTokenId || void 0
|
|
4743
4747
|
});
|
|
4744
4748
|
this.deps.emitEvent("transfer:confirmed", result);
|
|
4745
4749
|
return result;
|
|
@@ -4850,6 +4854,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4850
4854
|
recipientPubkey,
|
|
4851
4855
|
{
|
|
4852
4856
|
...options,
|
|
4857
|
+
memo: request.memo,
|
|
4853
4858
|
onChangeTokenCreated: async (changeToken) => {
|
|
4854
4859
|
const changeTokenData = changeToken.toJSON();
|
|
4855
4860
|
const uiToken = {
|
|
@@ -4865,7 +4870,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4865
4870
|
updatedAt: Date.now(),
|
|
4866
4871
|
sdkData: JSON.stringify(changeTokenData)
|
|
4867
4872
|
};
|
|
4868
|
-
await this.addToken(uiToken
|
|
4873
|
+
await this.addToken(uiToken);
|
|
4869
4874
|
this.log(`Change token saved via background: ${uiToken.id}`);
|
|
4870
4875
|
},
|
|
4871
4876
|
onStorageSync: async () => {
|
|
@@ -4878,15 +4883,20 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4878
4883
|
if (result.backgroundPromise) {
|
|
4879
4884
|
this.pendingBackgroundTasks.push(result.backgroundPromise);
|
|
4880
4885
|
}
|
|
4881
|
-
|
|
4882
|
-
|
|
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);
|
|
4883
4889
|
await this.addToHistory({
|
|
4884
4890
|
type: "SENT",
|
|
4885
4891
|
amount: request.amount,
|
|
4886
4892
|
coinId: request.coinId,
|
|
4887
4893
|
symbol: this.getCoinSymbol(request.coinId),
|
|
4888
4894
|
timestamp: Date.now(),
|
|
4889
|
-
|
|
4895
|
+
recipientPubkey,
|
|
4896
|
+
recipientNametag,
|
|
4897
|
+
recipientAddress: peerInfo?.directAddress || recipientAddress?.toString() || recipientPubkey,
|
|
4898
|
+
memo: request.memo,
|
|
4899
|
+
tokenId: splitTokenId || void 0
|
|
4890
4900
|
});
|
|
4891
4901
|
await this.save();
|
|
4892
4902
|
} else {
|
|
@@ -4917,10 +4927,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4917
4927
|
* @param senderPubkey - Sender's public key for verification
|
|
4918
4928
|
* @returns Processing result with finalized token
|
|
4919
4929
|
*/
|
|
4920
|
-
async processInstantSplitBundle(bundle, senderPubkey) {
|
|
4930
|
+
async processInstantSplitBundle(bundle, senderPubkey, memo) {
|
|
4921
4931
|
this.ensureInitialized();
|
|
4922
4932
|
if (!isInstantSplitBundleV5(bundle)) {
|
|
4923
|
-
return this.processInstantSplitBundleSync(bundle, senderPubkey);
|
|
4933
|
+
return this.processInstantSplitBundleSync(bundle, senderPubkey, memo);
|
|
4924
4934
|
}
|
|
4925
4935
|
try {
|
|
4926
4936
|
const deterministicId = `v5split_${bundle.splitGroupId}`;
|
|
@@ -4950,12 +4960,26 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4950
4960
|
updatedAt: Date.now(),
|
|
4951
4961
|
sdkData: JSON.stringify({ _pendingFinalization: pendingData })
|
|
4952
4962
|
};
|
|
4953
|
-
await this.addToken(uiToken
|
|
4963
|
+
await this.addToken(uiToken);
|
|
4954
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
|
+
});
|
|
4955
4977
|
this.deps.emitEvent("transfer:incoming", {
|
|
4956
4978
|
id: bundle.splitGroupId,
|
|
4957
4979
|
senderPubkey,
|
|
4980
|
+
senderNametag: senderInfo.senderNametag,
|
|
4958
4981
|
tokens: [uiToken],
|
|
4982
|
+
memo,
|
|
4959
4983
|
receivedAt: Date.now()
|
|
4960
4984
|
});
|
|
4961
4985
|
await this.save();
|
|
@@ -4975,7 +4999,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4975
4999
|
* Synchronous V4 bundle processing (dev mode only).
|
|
4976
5000
|
* Kept for backward compatibility with V4 bundles.
|
|
4977
5001
|
*/
|
|
4978
|
-
async processInstantSplitBundleSync(bundle, senderPubkey) {
|
|
5002
|
+
async processInstantSplitBundleSync(bundle, senderPubkey, memo) {
|
|
4979
5003
|
try {
|
|
4980
5004
|
const signingService = await this.createSigningService();
|
|
4981
5005
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
@@ -5035,19 +5059,26 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5035
5059
|
sdkData: JSON.stringify(tokenData)
|
|
5036
5060
|
};
|
|
5037
5061
|
await this.addToken(uiToken);
|
|
5062
|
+
const receivedTokenId = extractTokenIdFromSdkData(uiToken.sdkData);
|
|
5063
|
+
const senderInfo = await this.resolveSenderInfo(senderPubkey);
|
|
5038
5064
|
await this.addToHistory({
|
|
5039
5065
|
type: "RECEIVED",
|
|
5040
5066
|
amount: bundle.amount,
|
|
5041
5067
|
coinId: info.coinId,
|
|
5042
5068
|
symbol: info.symbol,
|
|
5043
5069
|
timestamp: Date.now(),
|
|
5044
|
-
senderPubkey
|
|
5070
|
+
senderPubkey,
|
|
5071
|
+
...senderInfo,
|
|
5072
|
+
memo,
|
|
5073
|
+
tokenId: receivedTokenId || uiToken.id
|
|
5045
5074
|
});
|
|
5046
5075
|
await this.save();
|
|
5047
5076
|
this.deps.emitEvent("transfer:incoming", {
|
|
5048
5077
|
id: bundle.splitGroupId,
|
|
5049
5078
|
senderPubkey,
|
|
5079
|
+
senderNametag: senderInfo.senderNametag,
|
|
5050
5080
|
tokens: [uiToken],
|
|
5081
|
+
memo,
|
|
5051
5082
|
receivedAt: Date.now()
|
|
5052
5083
|
});
|
|
5053
5084
|
}
|
|
@@ -5790,14 +5821,6 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5790
5821
|
sdkData: JSON.stringify(finalizedToken.toJSON())
|
|
5791
5822
|
};
|
|
5792
5823
|
this.tokens.set(tokenId, confirmedToken);
|
|
5793
|
-
await this.addToHistory({
|
|
5794
|
-
type: "RECEIVED",
|
|
5795
|
-
amount: confirmedToken.amount,
|
|
5796
|
-
coinId: confirmedToken.coinId,
|
|
5797
|
-
symbol: confirmedToken.symbol || "UNK",
|
|
5798
|
-
timestamp: Date.now(),
|
|
5799
|
-
senderPubkey: pending2.senderPubkey
|
|
5800
|
-
});
|
|
5801
5824
|
this.log(`V5 token resolved: ${tokenId.slice(0, 8)}...`);
|
|
5802
5825
|
return "resolved";
|
|
5803
5826
|
}
|
|
@@ -5981,10 +6004,9 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5981
6004
|
* the old state is archived and replaced with the incoming one.
|
|
5982
6005
|
*
|
|
5983
6006
|
* @param token - The token to add.
|
|
5984
|
-
* @param skipHistory - When `true`, do not create a `RECEIVED` transaction history entry (default `false`).
|
|
5985
6007
|
* @returns `true` if the token was added, `false` if rejected as duplicate or tombstoned.
|
|
5986
6008
|
*/
|
|
5987
|
-
async addToken(token
|
|
6009
|
+
async addToken(token) {
|
|
5988
6010
|
this.ensureInitialized();
|
|
5989
6011
|
const incomingTokenId = extractTokenIdFromSdkData(token.sdkData);
|
|
5990
6012
|
const incomingStateHash = extractStateHashFromSdkData(token.sdkData);
|
|
@@ -6030,15 +6052,6 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6030
6052
|
}
|
|
6031
6053
|
this.tokens.set(token.id, token);
|
|
6032
6054
|
await this.archiveToken(token);
|
|
6033
|
-
if (!skipHistory && token.coinId && token.amount) {
|
|
6034
|
-
await this.addToHistory({
|
|
6035
|
-
type: "RECEIVED",
|
|
6036
|
-
amount: token.amount,
|
|
6037
|
-
coinId: token.coinId,
|
|
6038
|
-
symbol: token.symbol || "UNK",
|
|
6039
|
-
timestamp: token.createdAt || Date.now()
|
|
6040
|
-
});
|
|
6041
|
-
}
|
|
6042
6055
|
await this.save();
|
|
6043
6056
|
this.log(`Added token ${token.id}, total: ${this.tokens.size}`);
|
|
6044
6057
|
return true;
|
|
@@ -6065,7 +6078,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6065
6078
|
}
|
|
6066
6079
|
}
|
|
6067
6080
|
if (!found) {
|
|
6068
|
-
await this.addToken(token
|
|
6081
|
+
await this.addToken(token);
|
|
6069
6082
|
return;
|
|
6070
6083
|
}
|
|
6071
6084
|
await this.archiveToken(token);
|
|
@@ -6080,10 +6093,8 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6080
6093
|
* entry is created unless `skipHistory` is `true`.
|
|
6081
6094
|
*
|
|
6082
6095
|
* @param tokenId - Local UUID of the token to remove.
|
|
6083
|
-
* @param recipientNametag - Optional nametag of the transfer recipient (for history).
|
|
6084
|
-
* @param skipHistory - When `true`, skip creating a transaction history entry (default `false`).
|
|
6085
6096
|
*/
|
|
6086
|
-
async removeToken(tokenId
|
|
6097
|
+
async removeToken(tokenId) {
|
|
6087
6098
|
this.ensureInitialized();
|
|
6088
6099
|
const token = this.tokens.get(tokenId);
|
|
6089
6100
|
if (!token) return;
|
|
@@ -6101,16 +6112,6 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6101
6112
|
this.log(`Warning: Could not create tombstone for token ${tokenId.slice(0, 8)}... (missing tokenId or stateHash)`);
|
|
6102
6113
|
}
|
|
6103
6114
|
this.tokens.delete(tokenId);
|
|
6104
|
-
if (!skipHistory && token.coinId && token.amount) {
|
|
6105
|
-
await this.addToHistory({
|
|
6106
|
-
type: "SENT",
|
|
6107
|
-
amount: token.amount,
|
|
6108
|
-
coinId: token.coinId,
|
|
6109
|
-
symbol: token.symbol || "UNK",
|
|
6110
|
-
timestamp: Date.now(),
|
|
6111
|
-
recipientNametag
|
|
6112
|
-
});
|
|
6113
|
-
}
|
|
6114
6115
|
await this.save();
|
|
6115
6116
|
}
|
|
6116
6117
|
// ===========================================================================
|
|
@@ -6335,26 +6336,104 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6335
6336
|
* @returns Array of {@link TransactionHistoryEntry} objects in descending timestamp order.
|
|
6336
6337
|
*/
|
|
6337
6338
|
getHistory() {
|
|
6338
|
-
return [...this.
|
|
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 {};
|
|
6339
6359
|
}
|
|
6340
6360
|
/**
|
|
6341
6361
|
* Append an entry to the transaction history.
|
|
6342
6362
|
*
|
|
6343
|
-
* A unique `id`
|
|
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).
|
|
6344
6366
|
*
|
|
6345
|
-
* @param entry - History entry fields (without `id`).
|
|
6367
|
+
* @param entry - History entry fields (without `id` and `dedupKey`).
|
|
6346
6368
|
*/
|
|
6347
6369
|
async addToHistory(entry) {
|
|
6348
6370
|
this.ensureInitialized();
|
|
6371
|
+
const dedupKey = computeHistoryDedupKey(entry.type, entry.tokenId, entry.transferId);
|
|
6349
6372
|
const historyEntry = {
|
|
6350
6373
|
id: crypto.randomUUID(),
|
|
6374
|
+
dedupKey,
|
|
6351
6375
|
...entry
|
|
6352
6376
|
};
|
|
6353
|
-
this.
|
|
6354
|
-
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
);
|
|
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;
|
|
6358
6437
|
}
|
|
6359
6438
|
// ===========================================================================
|
|
6360
6439
|
// Public API - Nametag
|
|
@@ -6897,14 +6976,27 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6897
6976
|
this.tokens.set(token.id, token);
|
|
6898
6977
|
await this.save();
|
|
6899
6978
|
this.log(`NOSTR-FIRST: Token ${token.id.slice(0, 8)}... added as submitted (unconfirmed)`);
|
|
6979
|
+
const senderInfo = await this.resolveSenderInfo(transfer.senderTransportPubkey);
|
|
6900
6980
|
const incomingTransfer = {
|
|
6901
6981
|
id: transfer.id,
|
|
6902
6982
|
senderPubkey: transfer.senderTransportPubkey,
|
|
6983
|
+
senderNametag: senderInfo.senderNametag,
|
|
6903
6984
|
tokens: [token],
|
|
6904
6985
|
memo: payload.memo,
|
|
6905
6986
|
receivedAt: transfer.timestamp
|
|
6906
6987
|
};
|
|
6907
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
|
+
});
|
|
6908
7000
|
try {
|
|
6909
7001
|
const commitment = await import_TransferCommitment4.TransferCommitment.fromJSON(commitmentInput);
|
|
6910
7002
|
const requestIdBytes = commitment.requestId;
|
|
@@ -6922,7 +7014,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6922
7014
|
attemptCount: 0,
|
|
6923
7015
|
lastAttemptAt: 0,
|
|
6924
7016
|
onProofReceived: async (tokenId) => {
|
|
6925
|
-
await this.finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput
|
|
7017
|
+
await this.finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput);
|
|
6926
7018
|
}
|
|
6927
7019
|
});
|
|
6928
7020
|
} catch (err) {
|
|
@@ -6981,7 +7073,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6981
7073
|
/**
|
|
6982
7074
|
* Finalize a received token after proof is available
|
|
6983
7075
|
*/
|
|
6984
|
-
async finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput
|
|
7076
|
+
async finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput) {
|
|
6985
7077
|
try {
|
|
6986
7078
|
const token = this.tokens.get(tokenId);
|
|
6987
7079
|
if (!token) {
|
|
@@ -7029,14 +7121,6 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7029
7121
|
tokens: [finalizedToken],
|
|
7030
7122
|
tokenTransfers: []
|
|
7031
7123
|
});
|
|
7032
|
-
await this.addToHistory({
|
|
7033
|
-
type: "RECEIVED",
|
|
7034
|
-
amount: finalizedToken.amount,
|
|
7035
|
-
coinId: finalizedToken.coinId,
|
|
7036
|
-
symbol: finalizedToken.symbol,
|
|
7037
|
-
timestamp: Date.now(),
|
|
7038
|
-
senderPubkey
|
|
7039
|
-
});
|
|
7040
7124
|
} catch (error) {
|
|
7041
7125
|
console.error("[Payments] Failed to finalize received token:", error);
|
|
7042
7126
|
const token = this.tokens.get(tokenId);
|
|
@@ -7067,7 +7151,8 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7067
7151
|
try {
|
|
7068
7152
|
const result = await this.processInstantSplitBundle(
|
|
7069
7153
|
instantBundle,
|
|
7070
|
-
transfer.senderTransportPubkey
|
|
7154
|
+
transfer.senderTransportPubkey,
|
|
7155
|
+
payload.memo
|
|
7071
7156
|
);
|
|
7072
7157
|
if (result.success) {
|
|
7073
7158
|
this.log("INSTANT_SPLIT processed successfully");
|
|
@@ -7185,10 +7270,26 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7185
7270
|
updatedAt: Date.now(),
|
|
7186
7271
|
sdkData: typeof tokenData === "string" ? tokenData : JSON.stringify(tokenData)
|
|
7187
7272
|
};
|
|
7188
|
-
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
|
+
}
|
|
7189
7289
|
const incomingTransfer = {
|
|
7190
7290
|
id: transfer.id,
|
|
7191
7291
|
senderPubkey: transfer.senderTransportPubkey,
|
|
7292
|
+
senderNametag: senderInfo.senderNametag,
|
|
7192
7293
|
tokens: [token],
|
|
7193
7294
|
memo: payload.memo,
|
|
7194
7295
|
receivedAt: transfer.timestamp
|