@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/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:
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
5082
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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`
|
|
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.
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
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
|
|
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
|
|
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
|