@unicitylabs/sphere-sdk 0.4.8 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index.cjs +183 -80
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +222 -194
- package/dist/core/index.d.ts +222 -194
- package/dist/core/index.js +183 -80
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/index.cjs +64 -2
- package/dist/impl/browser/index.cjs.map +1 -1
- package/dist/impl/browser/index.js +64 -2
- package/dist/impl/browser/index.js.map +1 -1
- package/dist/impl/nodejs/index.cjs +61 -4
- package/dist/impl/nodejs/index.cjs.map +1 -1
- package/dist/impl/nodejs/index.d.cts +668 -628
- package/dist/impl/nodejs/index.d.ts +668 -628
- package/dist/impl/nodejs/index.js +61 -4
- package/dist/impl/nodejs/index.js.map +1 -1
- package/dist/index.cjs +183 -80
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +222 -194
- package/dist/index.d.ts +222 -194
- package/dist/index.js +183 -80
- package/dist/index.js.map +1 -1
- package/dist/l1/index.cjs +2 -0
- package/dist/l1/index.cjs.map +1 -1
- package/dist/l1/index.js +2 -0
- package/dist/l1/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -646,6 +646,8 @@ function disconnect() {
|
|
|
646
646
|
if (cb.timeoutId) clearTimeout(cb.timeoutId);
|
|
647
647
|
});
|
|
648
648
|
connectionCallbacks.length = 0;
|
|
649
|
+
blockSubscribers.length = 0;
|
|
650
|
+
lastBlockHeader = null;
|
|
649
651
|
}
|
|
650
652
|
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;
|
|
651
653
|
var init_network = __esm({
|
|
@@ -3711,7 +3713,7 @@ var InstantSplitExecutor = class {
|
|
|
3711
3713
|
token: JSON.stringify(bundle),
|
|
3712
3714
|
proof: null,
|
|
3713
3715
|
// Proof is included in the bundle
|
|
3714
|
-
memo:
|
|
3716
|
+
memo: options?.memo,
|
|
3715
3717
|
sender: {
|
|
3716
3718
|
transportPubkey: senderPubkey
|
|
3717
3719
|
}
|
|
@@ -4270,6 +4272,11 @@ import { MintCommitment as MintCommitment3 } from "@unicitylabs/state-transition
|
|
|
4270
4272
|
import { MintTransactionData as MintTransactionData3 } from "@unicitylabs/state-transition-sdk/lib/transaction/MintTransactionData";
|
|
4271
4273
|
import { waitInclusionProof as waitInclusionProof5 } from "@unicitylabs/state-transition-sdk/lib/util/InclusionProofUtils";
|
|
4272
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
|
+
}
|
|
4273
4280
|
function enrichWithRegistry(info) {
|
|
4274
4281
|
const registry = TokenRegistry.getInstance();
|
|
4275
4282
|
const def = registry.getDefinition(info.coinId);
|
|
@@ -4568,7 +4575,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4568
4575
|
tombstones = [];
|
|
4569
4576
|
archivedTokens = /* @__PURE__ */ new Map();
|
|
4570
4577
|
forkedTokens = /* @__PURE__ */ new Map();
|
|
4571
|
-
|
|
4578
|
+
_historyCache = [];
|
|
4572
4579
|
nametags = [];
|
|
4573
4580
|
// Payment Requests State (Incoming)
|
|
4574
4581
|
paymentRequests = [];
|
|
@@ -4637,7 +4644,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4637
4644
|
this.tombstones = [];
|
|
4638
4645
|
this.archivedTokens.clear();
|
|
4639
4646
|
this.forkedTokens.clear();
|
|
4640
|
-
this.
|
|
4647
|
+
this._historyCache = [];
|
|
4641
4648
|
this.nametags = [];
|
|
4642
4649
|
this.deps = deps;
|
|
4643
4650
|
this.priceProvider = deps.price ?? null;
|
|
@@ -4688,14 +4695,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4688
4695
|
}
|
|
4689
4696
|
}
|
|
4690
4697
|
await this.loadPendingV5Tokens();
|
|
4691
|
-
|
|
4692
|
-
if (historyData) {
|
|
4693
|
-
try {
|
|
4694
|
-
this.transactionHistory = JSON.parse(historyData);
|
|
4695
|
-
} catch {
|
|
4696
|
-
this.transactionHistory = [];
|
|
4697
|
-
}
|
|
4698
|
-
}
|
|
4698
|
+
await this.loadHistory();
|
|
4699
4699
|
const pending2 = await this.deps.storage.get(STORAGE_KEYS_ADDRESS.PENDING_TRANSFERS);
|
|
4700
4700
|
if (pending2) {
|
|
4701
4701
|
const transfers = JSON.parse(pending2);
|
|
@@ -4782,7 +4782,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4782
4782
|
}
|
|
4783
4783
|
await this.saveToOutbox(result, recipientPubkey);
|
|
4784
4784
|
result.status = "submitted";
|
|
4785
|
-
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);
|
|
4786
4786
|
const transferMode = request.transferMode ?? "instant";
|
|
4787
4787
|
if (splitPlan.requiresSplit && splitPlan.tokenToSplit) {
|
|
4788
4788
|
if (transferMode === "conservative") {
|
|
@@ -4813,7 +4813,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4813
4813
|
updatedAt: Date.now(),
|
|
4814
4814
|
sdkData: JSON.stringify(changeTokenData)
|
|
4815
4815
|
};
|
|
4816
|
-
await this.addToken(changeUiToken
|
|
4816
|
+
await this.addToken(changeUiToken);
|
|
4817
4817
|
this.log(`Conservative split: change token saved: ${changeUiToken.id}`);
|
|
4818
4818
|
await this.deps.transport.sendTokenTransfer(recipientPubkey, {
|
|
4819
4819
|
sourceToken: JSON.stringify(splitResult.tokenForRecipient.toJSON()),
|
|
@@ -4822,7 +4822,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4822
4822
|
});
|
|
4823
4823
|
const splitCommitmentRequestId = splitResult.recipientTransferTx?.data?.requestId ?? splitResult.recipientTransferTx?.requestId;
|
|
4824
4824
|
const splitRequestIdHex = splitCommitmentRequestId instanceof Uint8Array ? Array.from(splitCommitmentRequestId).map((b) => b.toString(16).padStart(2, "0")).join("") : splitCommitmentRequestId ? String(splitCommitmentRequestId) : void 0;
|
|
4825
|
-
await this.removeToken(splitPlan.tokenToSplit.uiToken.id
|
|
4825
|
+
await this.removeToken(splitPlan.tokenToSplit.uiToken.id);
|
|
4826
4826
|
result.tokenTransfers.push({
|
|
4827
4827
|
sourceTokenId: splitPlan.tokenToSplit.uiToken.id,
|
|
4828
4828
|
method: "split",
|
|
@@ -4847,6 +4847,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4847
4847
|
this.deps.transport,
|
|
4848
4848
|
recipientPubkey,
|
|
4849
4849
|
{
|
|
4850
|
+
memo: request.memo,
|
|
4850
4851
|
onChangeTokenCreated: async (changeToken) => {
|
|
4851
4852
|
const changeTokenData = changeToken.toJSON();
|
|
4852
4853
|
const uiToken = {
|
|
@@ -4862,7 +4863,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4862
4863
|
updatedAt: Date.now(),
|
|
4863
4864
|
sdkData: JSON.stringify(changeTokenData)
|
|
4864
4865
|
};
|
|
4865
|
-
await this.addToken(uiToken
|
|
4866
|
+
await this.addToken(uiToken);
|
|
4866
4867
|
this.log(`Change token saved via background: ${uiToken.id}`);
|
|
4867
4868
|
},
|
|
4868
4869
|
onStorageSync: async () => {
|
|
@@ -4877,7 +4878,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4877
4878
|
if (instantResult.backgroundPromise) {
|
|
4878
4879
|
this.pendingBackgroundTasks.push(instantResult.backgroundPromise);
|
|
4879
4880
|
}
|
|
4880
|
-
await this.removeToken(splitPlan.tokenToSplit.uiToken.id
|
|
4881
|
+
await this.removeToken(splitPlan.tokenToSplit.uiToken.id);
|
|
4881
4882
|
result.tokenTransfers.push({
|
|
4882
4883
|
sourceTokenId: splitPlan.tokenToSplit.uiToken.id,
|
|
4883
4884
|
method: "split",
|
|
@@ -4924,20 +4925,25 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
4924
4925
|
requestIdHex
|
|
4925
4926
|
});
|
|
4926
4927
|
this.log(`Token ${token.id} sent via ${transferMode.toUpperCase()}, requestId: ${requestIdHex}`);
|
|
4927
|
-
await this.removeToken(token.id
|
|
4928
|
+
await this.removeToken(token.id);
|
|
4928
4929
|
}
|
|
4929
4930
|
result.status = "delivered";
|
|
4930
4931
|
await this.save();
|
|
4931
4932
|
await this.removeFromOutbox(result.id);
|
|
4932
4933
|
result.status = "completed";
|
|
4934
|
+
const sentTokenId = result.tokens[0] ? extractTokenIdFromSdkData(result.tokens[0].sdkData) : void 0;
|
|
4933
4935
|
await this.addToHistory({
|
|
4934
4936
|
type: "SENT",
|
|
4935
4937
|
amount: request.amount,
|
|
4936
4938
|
coinId: request.coinId,
|
|
4937
4939
|
symbol: this.getCoinSymbol(request.coinId),
|
|
4938
4940
|
timestamp: Date.now(),
|
|
4941
|
+
recipientPubkey,
|
|
4939
4942
|
recipientNametag,
|
|
4940
|
-
|
|
4943
|
+
recipientAddress: peerInfo?.directAddress || recipientAddress?.toString() || recipientPubkey,
|
|
4944
|
+
memo: request.memo,
|
|
4945
|
+
transferId: result.id,
|
|
4946
|
+
tokenId: sentTokenId || void 0
|
|
4941
4947
|
});
|
|
4942
4948
|
this.deps.emitEvent("transfer:confirmed", result);
|
|
4943
4949
|
return result;
|
|
@@ -5048,6 +5054,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5048
5054
|
recipientPubkey,
|
|
5049
5055
|
{
|
|
5050
5056
|
...options,
|
|
5057
|
+
memo: request.memo,
|
|
5051
5058
|
onChangeTokenCreated: async (changeToken) => {
|
|
5052
5059
|
const changeTokenData = changeToken.toJSON();
|
|
5053
5060
|
const uiToken = {
|
|
@@ -5063,7 +5070,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5063
5070
|
updatedAt: Date.now(),
|
|
5064
5071
|
sdkData: JSON.stringify(changeTokenData)
|
|
5065
5072
|
};
|
|
5066
|
-
await this.addToken(uiToken
|
|
5073
|
+
await this.addToken(uiToken);
|
|
5067
5074
|
this.log(`Change token saved via background: ${uiToken.id}`);
|
|
5068
5075
|
},
|
|
5069
5076
|
onStorageSync: async () => {
|
|
@@ -5076,15 +5083,20 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5076
5083
|
if (result.backgroundPromise) {
|
|
5077
5084
|
this.pendingBackgroundTasks.push(result.backgroundPromise);
|
|
5078
5085
|
}
|
|
5079
|
-
|
|
5080
|
-
|
|
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);
|
|
5081
5089
|
await this.addToHistory({
|
|
5082
5090
|
type: "SENT",
|
|
5083
5091
|
amount: request.amount,
|
|
5084
5092
|
coinId: request.coinId,
|
|
5085
5093
|
symbol: this.getCoinSymbol(request.coinId),
|
|
5086
5094
|
timestamp: Date.now(),
|
|
5087
|
-
|
|
5095
|
+
recipientPubkey,
|
|
5096
|
+
recipientNametag,
|
|
5097
|
+
recipientAddress: peerInfo?.directAddress || recipientAddress?.toString() || recipientPubkey,
|
|
5098
|
+
memo: request.memo,
|
|
5099
|
+
tokenId: splitTokenId || void 0
|
|
5088
5100
|
});
|
|
5089
5101
|
await this.save();
|
|
5090
5102
|
} else {
|
|
@@ -5115,10 +5127,10 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5115
5127
|
* @param senderPubkey - Sender's public key for verification
|
|
5116
5128
|
* @returns Processing result with finalized token
|
|
5117
5129
|
*/
|
|
5118
|
-
async processInstantSplitBundle(bundle, senderPubkey) {
|
|
5130
|
+
async processInstantSplitBundle(bundle, senderPubkey, memo) {
|
|
5119
5131
|
this.ensureInitialized();
|
|
5120
5132
|
if (!isInstantSplitBundleV5(bundle)) {
|
|
5121
|
-
return this.processInstantSplitBundleSync(bundle, senderPubkey);
|
|
5133
|
+
return this.processInstantSplitBundleSync(bundle, senderPubkey, memo);
|
|
5122
5134
|
}
|
|
5123
5135
|
try {
|
|
5124
5136
|
const deterministicId = `v5split_${bundle.splitGroupId}`;
|
|
@@ -5148,12 +5160,26 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5148
5160
|
updatedAt: Date.now(),
|
|
5149
5161
|
sdkData: JSON.stringify({ _pendingFinalization: pendingData })
|
|
5150
5162
|
};
|
|
5151
|
-
await this.addToken(uiToken
|
|
5163
|
+
await this.addToken(uiToken);
|
|
5152
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
|
+
});
|
|
5153
5177
|
this.deps.emitEvent("transfer:incoming", {
|
|
5154
5178
|
id: bundle.splitGroupId,
|
|
5155
5179
|
senderPubkey,
|
|
5180
|
+
senderNametag: senderInfo.senderNametag,
|
|
5156
5181
|
tokens: [uiToken],
|
|
5182
|
+
memo,
|
|
5157
5183
|
receivedAt: Date.now()
|
|
5158
5184
|
});
|
|
5159
5185
|
await this.save();
|
|
@@ -5173,7 +5199,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5173
5199
|
* Synchronous V4 bundle processing (dev mode only).
|
|
5174
5200
|
* Kept for backward compatibility with V4 bundles.
|
|
5175
5201
|
*/
|
|
5176
|
-
async processInstantSplitBundleSync(bundle, senderPubkey) {
|
|
5202
|
+
async processInstantSplitBundleSync(bundle, senderPubkey, memo) {
|
|
5177
5203
|
try {
|
|
5178
5204
|
const signingService = await this.createSigningService();
|
|
5179
5205
|
const stClient = this.deps.oracle.getStateTransitionClient?.();
|
|
@@ -5233,19 +5259,26 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5233
5259
|
sdkData: JSON.stringify(tokenData)
|
|
5234
5260
|
};
|
|
5235
5261
|
await this.addToken(uiToken);
|
|
5262
|
+
const receivedTokenId = extractTokenIdFromSdkData(uiToken.sdkData);
|
|
5263
|
+
const senderInfo = await this.resolveSenderInfo(senderPubkey);
|
|
5236
5264
|
await this.addToHistory({
|
|
5237
5265
|
type: "RECEIVED",
|
|
5238
5266
|
amount: bundle.amount,
|
|
5239
5267
|
coinId: info.coinId,
|
|
5240
5268
|
symbol: info.symbol,
|
|
5241
5269
|
timestamp: Date.now(),
|
|
5242
|
-
senderPubkey
|
|
5270
|
+
senderPubkey,
|
|
5271
|
+
...senderInfo,
|
|
5272
|
+
memo,
|
|
5273
|
+
tokenId: receivedTokenId || uiToken.id
|
|
5243
5274
|
});
|
|
5244
5275
|
await this.save();
|
|
5245
5276
|
this.deps.emitEvent("transfer:incoming", {
|
|
5246
5277
|
id: bundle.splitGroupId,
|
|
5247
5278
|
senderPubkey,
|
|
5279
|
+
senderNametag: senderInfo.senderNametag,
|
|
5248
5280
|
tokens: [uiToken],
|
|
5281
|
+
memo,
|
|
5249
5282
|
receivedAt: Date.now()
|
|
5250
5283
|
});
|
|
5251
5284
|
}
|
|
@@ -5988,14 +6021,6 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
5988
6021
|
sdkData: JSON.stringify(finalizedToken.toJSON())
|
|
5989
6022
|
};
|
|
5990
6023
|
this.tokens.set(tokenId, confirmedToken);
|
|
5991
|
-
await this.addToHistory({
|
|
5992
|
-
type: "RECEIVED",
|
|
5993
|
-
amount: confirmedToken.amount,
|
|
5994
|
-
coinId: confirmedToken.coinId,
|
|
5995
|
-
symbol: confirmedToken.symbol || "UNK",
|
|
5996
|
-
timestamp: Date.now(),
|
|
5997
|
-
senderPubkey: pending2.senderPubkey
|
|
5998
|
-
});
|
|
5999
6024
|
this.log(`V5 token resolved: ${tokenId.slice(0, 8)}...`);
|
|
6000
6025
|
return "resolved";
|
|
6001
6026
|
}
|
|
@@ -6179,10 +6204,9 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6179
6204
|
* the old state is archived and replaced with the incoming one.
|
|
6180
6205
|
*
|
|
6181
6206
|
* @param token - The token to add.
|
|
6182
|
-
* @param skipHistory - When `true`, do not create a `RECEIVED` transaction history entry (default `false`).
|
|
6183
6207
|
* @returns `true` if the token was added, `false` if rejected as duplicate or tombstoned.
|
|
6184
6208
|
*/
|
|
6185
|
-
async addToken(token
|
|
6209
|
+
async addToken(token) {
|
|
6186
6210
|
this.ensureInitialized();
|
|
6187
6211
|
const incomingTokenId = extractTokenIdFromSdkData(token.sdkData);
|
|
6188
6212
|
const incomingStateHash = extractStateHashFromSdkData(token.sdkData);
|
|
@@ -6228,15 +6252,6 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6228
6252
|
}
|
|
6229
6253
|
this.tokens.set(token.id, token);
|
|
6230
6254
|
await this.archiveToken(token);
|
|
6231
|
-
if (!skipHistory && token.coinId && token.amount) {
|
|
6232
|
-
await this.addToHistory({
|
|
6233
|
-
type: "RECEIVED",
|
|
6234
|
-
amount: token.amount,
|
|
6235
|
-
coinId: token.coinId,
|
|
6236
|
-
symbol: token.symbol || "UNK",
|
|
6237
|
-
timestamp: token.createdAt || Date.now()
|
|
6238
|
-
});
|
|
6239
|
-
}
|
|
6240
6255
|
await this.save();
|
|
6241
6256
|
this.log(`Added token ${token.id}, total: ${this.tokens.size}`);
|
|
6242
6257
|
return true;
|
|
@@ -6263,7 +6278,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6263
6278
|
}
|
|
6264
6279
|
}
|
|
6265
6280
|
if (!found) {
|
|
6266
|
-
await this.addToken(token
|
|
6281
|
+
await this.addToken(token);
|
|
6267
6282
|
return;
|
|
6268
6283
|
}
|
|
6269
6284
|
await this.archiveToken(token);
|
|
@@ -6278,10 +6293,8 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6278
6293
|
* entry is created unless `skipHistory` is `true`.
|
|
6279
6294
|
*
|
|
6280
6295
|
* @param tokenId - Local UUID of the token to remove.
|
|
6281
|
-
* @param recipientNametag - Optional nametag of the transfer recipient (for history).
|
|
6282
|
-
* @param skipHistory - When `true`, skip creating a transaction history entry (default `false`).
|
|
6283
6296
|
*/
|
|
6284
|
-
async removeToken(tokenId
|
|
6297
|
+
async removeToken(tokenId) {
|
|
6285
6298
|
this.ensureInitialized();
|
|
6286
6299
|
const token = this.tokens.get(tokenId);
|
|
6287
6300
|
if (!token) return;
|
|
@@ -6299,16 +6312,6 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6299
6312
|
this.log(`Warning: Could not create tombstone for token ${tokenId.slice(0, 8)}... (missing tokenId or stateHash)`);
|
|
6300
6313
|
}
|
|
6301
6314
|
this.tokens.delete(tokenId);
|
|
6302
|
-
if (!skipHistory && token.coinId && token.amount) {
|
|
6303
|
-
await this.addToHistory({
|
|
6304
|
-
type: "SENT",
|
|
6305
|
-
amount: token.amount,
|
|
6306
|
-
coinId: token.coinId,
|
|
6307
|
-
symbol: token.symbol || "UNK",
|
|
6308
|
-
timestamp: Date.now(),
|
|
6309
|
-
recipientNametag
|
|
6310
|
-
});
|
|
6311
|
-
}
|
|
6312
6315
|
await this.save();
|
|
6313
6316
|
}
|
|
6314
6317
|
// ===========================================================================
|
|
@@ -6533,26 +6536,104 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
6533
6536
|
* @returns Array of {@link TransactionHistoryEntry} objects in descending timestamp order.
|
|
6534
6537
|
*/
|
|
6535
6538
|
getHistory() {
|
|
6536
|
-
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 {};
|
|
6537
6559
|
}
|
|
6538
6560
|
/**
|
|
6539
6561
|
* Append an entry to the transaction history.
|
|
6540
6562
|
*
|
|
6541
|
-
* 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).
|
|
6542
6566
|
*
|
|
6543
|
-
* @param entry - History entry fields (without `id`).
|
|
6567
|
+
* @param entry - History entry fields (without `id` and `dedupKey`).
|
|
6544
6568
|
*/
|
|
6545
6569
|
async addToHistory(entry) {
|
|
6546
6570
|
this.ensureInitialized();
|
|
6571
|
+
const dedupKey = computeHistoryDedupKey(entry.type, entry.tokenId, entry.transferId);
|
|
6547
6572
|
const historyEntry = {
|
|
6548
6573
|
id: crypto.randomUUID(),
|
|
6574
|
+
dedupKey,
|
|
6549
6575
|
...entry
|
|
6550
6576
|
};
|
|
6551
|
-
this.
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
);
|
|
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;
|
|
6556
6637
|
}
|
|
6557
6638
|
// ===========================================================================
|
|
6558
6639
|
// Public API - Nametag
|
|
@@ -7095,14 +7176,27 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7095
7176
|
this.tokens.set(token.id, token);
|
|
7096
7177
|
await this.save();
|
|
7097
7178
|
this.log(`NOSTR-FIRST: Token ${token.id.slice(0, 8)}... added as submitted (unconfirmed)`);
|
|
7179
|
+
const senderInfo = await this.resolveSenderInfo(transfer.senderTransportPubkey);
|
|
7098
7180
|
const incomingTransfer = {
|
|
7099
7181
|
id: transfer.id,
|
|
7100
7182
|
senderPubkey: transfer.senderTransportPubkey,
|
|
7183
|
+
senderNametag: senderInfo.senderNametag,
|
|
7101
7184
|
tokens: [token],
|
|
7102
7185
|
memo: payload.memo,
|
|
7103
7186
|
receivedAt: transfer.timestamp
|
|
7104
7187
|
};
|
|
7105
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
|
+
});
|
|
7106
7200
|
try {
|
|
7107
7201
|
const commitment = await TransferCommitment4.fromJSON(commitmentInput);
|
|
7108
7202
|
const requestIdBytes = commitment.requestId;
|
|
@@ -7120,7 +7214,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7120
7214
|
attemptCount: 0,
|
|
7121
7215
|
lastAttemptAt: 0,
|
|
7122
7216
|
onProofReceived: async (tokenId) => {
|
|
7123
|
-
await this.finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput
|
|
7217
|
+
await this.finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput);
|
|
7124
7218
|
}
|
|
7125
7219
|
});
|
|
7126
7220
|
} catch (err) {
|
|
@@ -7179,7 +7273,7 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7179
7273
|
/**
|
|
7180
7274
|
* Finalize a received token after proof is available
|
|
7181
7275
|
*/
|
|
7182
|
-
async finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput
|
|
7276
|
+
async finalizeReceivedToken(tokenId, sourceTokenInput, commitmentInput) {
|
|
7183
7277
|
try {
|
|
7184
7278
|
const token = this.tokens.get(tokenId);
|
|
7185
7279
|
if (!token) {
|
|
@@ -7227,14 +7321,6 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7227
7321
|
tokens: [finalizedToken],
|
|
7228
7322
|
tokenTransfers: []
|
|
7229
7323
|
});
|
|
7230
|
-
await this.addToHistory({
|
|
7231
|
-
type: "RECEIVED",
|
|
7232
|
-
amount: finalizedToken.amount,
|
|
7233
|
-
coinId: finalizedToken.coinId,
|
|
7234
|
-
symbol: finalizedToken.symbol,
|
|
7235
|
-
timestamp: Date.now(),
|
|
7236
|
-
senderPubkey
|
|
7237
|
-
});
|
|
7238
7324
|
} catch (error) {
|
|
7239
7325
|
console.error("[Payments] Failed to finalize received token:", error);
|
|
7240
7326
|
const token = this.tokens.get(tokenId);
|
|
@@ -7265,7 +7351,8 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7265
7351
|
try {
|
|
7266
7352
|
const result = await this.processInstantSplitBundle(
|
|
7267
7353
|
instantBundle,
|
|
7268
|
-
transfer.senderTransportPubkey
|
|
7354
|
+
transfer.senderTransportPubkey,
|
|
7355
|
+
payload.memo
|
|
7269
7356
|
);
|
|
7270
7357
|
if (result.success) {
|
|
7271
7358
|
this.log("INSTANT_SPLIT processed successfully");
|
|
@@ -7383,10 +7470,26 @@ var PaymentsModule = class _PaymentsModule {
|
|
|
7383
7470
|
updatedAt: Date.now(),
|
|
7384
7471
|
sdkData: typeof tokenData === "string" ? tokenData : JSON.stringify(tokenData)
|
|
7385
7472
|
};
|
|
7386
|
-
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
|
+
}
|
|
7387
7489
|
const incomingTransfer = {
|
|
7388
7490
|
id: transfer.id,
|
|
7389
7491
|
senderPubkey: transfer.senderTransportPubkey,
|
|
7492
|
+
senderNametag: senderInfo.senderNametag,
|
|
7390
7493
|
tokens: [token],
|
|
7391
7494
|
memo: payload.memo,
|
|
7392
7495
|
receivedAt: transfer.timestamp
|