@arcanetech/privacy-sdk-stellar 0.5.4 → 0.6.2
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.d.ts +58 -21
- package/dist/index.js +422 -81
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +24 -1
- package/dist/node.js +420 -79
- package/dist/node.js.map +1 -1
- package/dist/state/index.d.ts +31 -1
- package/dist/state/index.js +10 -2
- package/dist/state/index.js.map +1 -1
- package/dist/transact/index.d.ts +22 -1
- package/dist/transact/index.js +323 -72
- package/dist/transact/index.js.map +1 -1
- package/package.json +3 -3
package/dist/transact/index.d.ts
CHANGED
|
@@ -29,6 +29,11 @@ interface StellarPrivateCoinNote {
|
|
|
29
29
|
asset_lo: string;
|
|
30
30
|
application_id?: string;
|
|
31
31
|
}
|
|
32
|
+
interface StellarLeanImtNode {
|
|
33
|
+
level: number;
|
|
34
|
+
index: number;
|
|
35
|
+
value: string;
|
|
36
|
+
}
|
|
32
37
|
interface StellarPoolMerkleState {
|
|
33
38
|
poolContract: string;
|
|
34
39
|
commitments: string[];
|
|
@@ -36,6 +41,7 @@ interface StellarPoolMerkleState {
|
|
|
36
41
|
merkleRootHex: string;
|
|
37
42
|
updatedAt: number;
|
|
38
43
|
syncedLedger?: number;
|
|
44
|
+
nodes?: StellarLeanImtNode[];
|
|
39
45
|
}
|
|
40
46
|
interface StellarLeafEphemeral {
|
|
41
47
|
poolContract: string;
|
|
@@ -100,6 +106,12 @@ interface LeafEphemeralStatePort {
|
|
|
100
106
|
}): Promise<StellarLeafEphemeral | undefined>;
|
|
101
107
|
set(ephemeral: StellarLeafEphemeral): Promise<void>;
|
|
102
108
|
}
|
|
109
|
+
interface CachedPoolMerkleView {
|
|
110
|
+
commitments: string[];
|
|
111
|
+
updatedAt: number;
|
|
112
|
+
merkleRootHex?: string;
|
|
113
|
+
nodes?: StellarLeanImtNode[];
|
|
114
|
+
}
|
|
103
115
|
|
|
104
116
|
type StellarSignTransaction = (input: {
|
|
105
117
|
xdr: string;
|
|
@@ -574,7 +586,16 @@ interface FetchContractMerkleResult {
|
|
|
574
586
|
commitments: string[];
|
|
575
587
|
merkleRootHex: string;
|
|
576
588
|
updatedAt: number;
|
|
589
|
+
nodes?: StellarLeanImtNode[];
|
|
577
590
|
}
|
|
591
|
+
declare function persistFetchedMerkleState(input: {
|
|
592
|
+
poolContractId: string;
|
|
593
|
+
commitments: string[];
|
|
594
|
+
merkleRootHex: string;
|
|
595
|
+
cachedState: CachedPoolMerkleView | undefined;
|
|
596
|
+
poolMerkleState?: PoolMerkleStatePort;
|
|
597
|
+
}): Promise<FetchContractMerkleResult>;
|
|
598
|
+
|
|
578
599
|
/**
|
|
579
600
|
* Loads pool Merkle leaves without `get_commitments()`. That helper walks the
|
|
580
601
|
* whole tree in one simulate and exceeds the Soroban host budget on a live
|
|
@@ -586,7 +607,7 @@ declare function fetchAndMergeMerkleState(parameters: {
|
|
|
586
607
|
walletPublicKey: string;
|
|
587
608
|
transactEnvironment: StellarTransactEnvironment;
|
|
588
609
|
poolMerkleState?: PoolMerkleStatePort;
|
|
589
|
-
}): Promise<
|
|
610
|
+
}): Promise<Awaited<ReturnType<typeof persistFetchedMerkleState>>>;
|
|
590
611
|
declare function readLeafEphemeralHex(parameters: {
|
|
591
612
|
poolContractId: string;
|
|
592
613
|
walletPublicKey: string;
|
package/dist/transact/index.js
CHANGED
|
@@ -228,11 +228,240 @@ function uniformApplicationIdHints(applicationId, nAuditSlots) {
|
|
|
228
228
|
|
|
229
229
|
// src/transact/proofs/confidential/helpers.ts
|
|
230
230
|
import { withdrawObjectFromMerkleWitness } from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
231
|
+
|
|
232
|
+
// src/transact/merkle/lean-imt-api.ts
|
|
233
|
+
function asLeanImtSessionApi(sdk) {
|
|
234
|
+
const candidate = sdk;
|
|
235
|
+
if (typeof candidate.importLeanImtFromState !== "function") {
|
|
236
|
+
return void 0;
|
|
237
|
+
}
|
|
238
|
+
if (typeof candidate.insertTwoLeanImt !== "function") {
|
|
239
|
+
return void 0;
|
|
240
|
+
}
|
|
241
|
+
if (typeof candidate.exportLeanImt !== "function") {
|
|
242
|
+
return void 0;
|
|
243
|
+
}
|
|
244
|
+
if (typeof candidate.dropLeanImt !== "function") {
|
|
245
|
+
return void 0;
|
|
246
|
+
}
|
|
247
|
+
if (typeof candidate.buildWithdrawMerkleWitnessFromHandle !== "function") {
|
|
248
|
+
return void 0;
|
|
249
|
+
}
|
|
250
|
+
return candidate;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// src/transact/merkle/field-decimal.ts
|
|
254
|
+
import { Buffer as Buffer4 } from "buffer";
|
|
255
|
+
var BN254 = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
|
|
256
|
+
var MERKLE_ROOT_BYTE_LENGTH = 32;
|
|
257
|
+
var DECIMAL_STRING_RADIX = 10;
|
|
258
|
+
function merkleRootBufferToFrDecimal(root) {
|
|
259
|
+
if (root.length !== MERKLE_ROOT_BYTE_LENGTH) {
|
|
260
|
+
throw new Error(
|
|
261
|
+
`expected ${MERKLE_ROOT_BYTE_LENGTH}-byte merkle root, got ${root.length}`
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
const hex = Buffer4.from(root).toString("hex");
|
|
265
|
+
return (BigInt(`0x${hex}`) % BN254).toString(DECIMAL_STRING_RADIX);
|
|
266
|
+
}
|
|
267
|
+
var MERKLE_ROOT_HEX_PATTERN = /^[0-9a-fA-F]{64}$/;
|
|
268
|
+
function merkleRootHexToFrDecimal(merkleRootHex) {
|
|
269
|
+
const trimmed = merkleRootHex.trim();
|
|
270
|
+
if (!MERKLE_ROOT_HEX_PATTERN.test(trimmed)) {
|
|
271
|
+
return void 0;
|
|
272
|
+
}
|
|
273
|
+
return merkleRootBufferToFrDecimal(Buffer4.from(trimmed, "hex"));
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// src/transact/merkle/state-file.ts
|
|
277
|
+
function merkleSnapshotToStateFile(input) {
|
|
278
|
+
const root = merkleRootHexToFrDecimal(input.merkleRootHex);
|
|
279
|
+
const nodes = input.nodes;
|
|
280
|
+
if (!nodes || nodes.length === 0 || root === void 0) {
|
|
281
|
+
return { commitments: input.commitments };
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
commitments: input.commitments,
|
|
285
|
+
nodes,
|
|
286
|
+
root
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// src/transact/merkle/extend-snapshot.ts
|
|
291
|
+
function isEvenLeafCount(count) {
|
|
292
|
+
return count % 2 === 0;
|
|
293
|
+
}
|
|
294
|
+
function importHandle(sdk, state) {
|
|
295
|
+
try {
|
|
296
|
+
return sdk.importLeanImtFromState(state);
|
|
297
|
+
} catch {
|
|
298
|
+
return void 0;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
function insertNewPairs(input) {
|
|
302
|
+
for (let index = input.prefixLength; index < input.commitments.length; index += 2) {
|
|
303
|
+
const leafA = input.commitments.at(index);
|
|
304
|
+
const leafB = input.commitments.at(index + 1);
|
|
305
|
+
if (leafA === void 0 || leafB === void 0) {
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
try {
|
|
309
|
+
input.sdk.insertTwoLeanImt(input.handle, leafA, leafB);
|
|
310
|
+
} catch {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
function snapshotNodes(sdk, handle) {
|
|
317
|
+
try {
|
|
318
|
+
return sdk.exportLeanImt(handle).nodes;
|
|
319
|
+
} catch {
|
|
320
|
+
return void 0;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function prefixSnapshotState(input) {
|
|
324
|
+
const prefixLength = input.cachedState?.nodes ? input.cachedState.commitments.length : 0;
|
|
325
|
+
return merkleSnapshotToStateFile({
|
|
326
|
+
commitments: input.commitments.slice(0, prefixLength),
|
|
327
|
+
merkleRootHex: input.cachedState?.merkleRootHex ?? input.merkleRootHex,
|
|
328
|
+
...input.cachedState?.nodes ? { nodes: input.cachedState.nodes } : {}
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
function importSnapshotState(input) {
|
|
332
|
+
if (input.prefixState.nodes && input.prefixState.commitments.length > 0) {
|
|
333
|
+
return input.prefixState;
|
|
334
|
+
}
|
|
335
|
+
return merkleSnapshotToStateFile({
|
|
336
|
+
commitments: input.commitments,
|
|
337
|
+
merkleRootHex: input.merkleRootHex
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
function exportExtendedNodes(input) {
|
|
341
|
+
const inserted = input.prefixState.nodes ? insertNewPairs({
|
|
342
|
+
sdk: input.sdk,
|
|
343
|
+
handle: input.handle,
|
|
344
|
+
prefixLength: input.prefixState.commitments.length,
|
|
345
|
+
commitments: input.commitments
|
|
346
|
+
}) : true;
|
|
347
|
+
if (!inserted) {
|
|
348
|
+
input.sdk.dropLeanImt(input.handle);
|
|
349
|
+
return void 0;
|
|
350
|
+
}
|
|
351
|
+
const nodes = snapshotNodes(input.sdk, input.handle);
|
|
352
|
+
if (!nodes) {
|
|
353
|
+
input.sdk.dropLeanImt(input.handle);
|
|
354
|
+
}
|
|
355
|
+
return nodes;
|
|
356
|
+
}
|
|
357
|
+
function extendMerkleSnapshotNodes(input) {
|
|
358
|
+
if (!isEvenLeafCount(input.commitments.length)) {
|
|
359
|
+
return {};
|
|
360
|
+
}
|
|
361
|
+
const prefixState = prefixSnapshotState(input);
|
|
362
|
+
const handle = importHandle(
|
|
363
|
+
input.sdk,
|
|
364
|
+
importSnapshotState({ ...input, prefixState })
|
|
365
|
+
);
|
|
366
|
+
if (handle === void 0) {
|
|
367
|
+
return {};
|
|
368
|
+
}
|
|
369
|
+
const nodes = exportExtendedNodes({
|
|
370
|
+
sdk: input.sdk,
|
|
371
|
+
handle,
|
|
372
|
+
prefixState,
|
|
373
|
+
commitments: input.commitments
|
|
374
|
+
});
|
|
375
|
+
if (!nodes) {
|
|
376
|
+
return {};
|
|
377
|
+
}
|
|
378
|
+
return { nodes, handle };
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// src/transact/merkle/tree-session.ts
|
|
382
|
+
var merkleSdkHost;
|
|
383
|
+
function registerMerkleSessionSdkHost(host) {
|
|
384
|
+
merkleSdkHost = host;
|
|
385
|
+
}
|
|
386
|
+
async function loadSessionSdk() {
|
|
387
|
+
const host = merkleSdkHost;
|
|
388
|
+
if (typeof host?.getInitializedSdk !== "function") {
|
|
389
|
+
return void 0;
|
|
390
|
+
}
|
|
391
|
+
try {
|
|
392
|
+
return asLeanImtSessionApi(await host.getInitializedSdk());
|
|
393
|
+
} catch {
|
|
394
|
+
return void 0;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
var sessionsByPool = /* @__PURE__ */ new Map();
|
|
398
|
+
var handlesByKey = /* @__PURE__ */ new Map();
|
|
399
|
+
function merkleSessionKey(state) {
|
|
400
|
+
const root = state.root?.trim();
|
|
401
|
+
if (root) {
|
|
402
|
+
return `${state.commitments.length}:${root}`;
|
|
403
|
+
}
|
|
404
|
+
const first = state.commitments[0] ?? "";
|
|
405
|
+
const last = state.commitments.at(-1) ?? "";
|
|
406
|
+
return `${state.commitments.length}:${first}:${last}`;
|
|
407
|
+
}
|
|
408
|
+
function rememberHandle(poolContract, key, handle) {
|
|
409
|
+
const existing = sessionsByPool.get(poolContract);
|
|
410
|
+
if (existing && existing.handle !== handle) {
|
|
411
|
+
handlesByKey.delete(existing.key);
|
|
412
|
+
}
|
|
413
|
+
sessionsByPool.set(poolContract, { handle, key });
|
|
414
|
+
handlesByKey.set(key, handle);
|
|
415
|
+
}
|
|
416
|
+
function merkleTreeHandleForState(state) {
|
|
417
|
+
return handlesByKey.get(merkleSessionKey(state));
|
|
418
|
+
}
|
|
419
|
+
function bindImportedMerkleTree(input) {
|
|
420
|
+
rememberHandle(input.poolContract, merkleSessionKey(input.state), input.handle);
|
|
421
|
+
}
|
|
422
|
+
async function resolveExtendedMerkleNodes(input) {
|
|
423
|
+
const cached = input.cachedState;
|
|
424
|
+
if (cached && cached.commitments.length === input.commitments.length && cached.merkleRootHex === input.merkleRootHex) {
|
|
425
|
+
return cached.nodes;
|
|
426
|
+
}
|
|
427
|
+
const sdk = await loadSessionSdk();
|
|
428
|
+
if (!sdk) {
|
|
429
|
+
return void 0;
|
|
430
|
+
}
|
|
431
|
+
const extended = extendMerkleSnapshotNodes({
|
|
432
|
+
sdk,
|
|
433
|
+
commitments: input.commitments,
|
|
434
|
+
merkleRootHex: input.merkleRootHex,
|
|
435
|
+
...cached ? { cachedState: cached } : {}
|
|
436
|
+
});
|
|
437
|
+
if (extended.handle !== void 0) {
|
|
438
|
+
bindImportedMerkleTree({
|
|
439
|
+
poolContract: input.poolContract,
|
|
440
|
+
handle: extended.handle,
|
|
441
|
+
state: merkleSnapshotToStateFile({
|
|
442
|
+
commitments: input.commitments,
|
|
443
|
+
merkleRootHex: input.merkleRootHex,
|
|
444
|
+
...extended.nodes ? { nodes: extended.nodes } : {}
|
|
445
|
+
})
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
return extended.nodes;
|
|
449
|
+
}
|
|
450
|
+
function withdrawMerkleWitnessFromTree(input) {
|
|
451
|
+
const session = asLeanImtSessionApi(input.sdk);
|
|
452
|
+
const handle = merkleTreeHandleForState(input.state);
|
|
453
|
+
if (session && handle !== void 0) {
|
|
454
|
+
return session.buildWithdrawMerkleWitnessFromHandle(input.coin, handle);
|
|
455
|
+
}
|
|
456
|
+
return input.sdk.buildWithdrawMerkleWitness(input.coin, input.state);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// src/transact/proofs/confidential/helpers.ts
|
|
231
460
|
var MIN_CONFIDENTIAL_TRANSFER_STROOPS = 1n;
|
|
232
461
|
var ZERO_STROOPS = 0n;
|
|
233
462
|
function withdrawWitnessForCoin(parameters) {
|
|
234
463
|
const { sdk, coin, state } = parameters;
|
|
235
|
-
const witness = sdk
|
|
464
|
+
const witness = withdrawMerkleWitnessFromTree({ sdk, coin, state });
|
|
236
465
|
const withdrawApplicationId = coin.application_id ?? parameters.applicationId;
|
|
237
466
|
const withdrawObject = withdrawObjectFromMerkleWitness(
|
|
238
467
|
witness,
|
|
@@ -419,7 +648,7 @@ import {
|
|
|
419
648
|
DEMO_AUDIT_PUBLIC_KEY,
|
|
420
649
|
resolveTransactionAuditParams
|
|
421
650
|
} from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
422
|
-
import { Buffer as
|
|
651
|
+
import { Buffer as Buffer5 } from "buffer";
|
|
423
652
|
var UNCOMPRESSED_PREFIX = "04";
|
|
424
653
|
var UNCOMPRESSED_HEX_LENGTH = 130;
|
|
425
654
|
var XY_HEX_LENGTH = 128;
|
|
@@ -446,7 +675,7 @@ function parseAuditPublicKeyFromEnvHex(raw) {
|
|
|
446
675
|
"Audit public key must be uncompressed 65-byte hex (04 + X + Y) or 64-byte X+Y hex"
|
|
447
676
|
);
|
|
448
677
|
}
|
|
449
|
-
const bytes =
|
|
678
|
+
const bytes = Buffer5.from(payload, "hex");
|
|
450
679
|
const auditPublicKeyXDecimal = BigInt(
|
|
451
680
|
`0x${bytes.subarray(0, X_OFFSET_END).toString("hex")}`
|
|
452
681
|
).toString(DECIMAL_RADIX);
|
|
@@ -489,13 +718,13 @@ import { ed25519PubkeyPayloadHexToWithdrawFrDecimals } from "@arcanetech/stellar
|
|
|
489
718
|
|
|
490
719
|
// src/transact/stellar/account.ts
|
|
491
720
|
import { StrKey as StrKey3 } from "@stellar/stellar-sdk";
|
|
492
|
-
import { Buffer as
|
|
721
|
+
import { Buffer as Buffer6 } from "buffer";
|
|
493
722
|
var MUXED_ACCOUNT_ID_BYTE_LENGTH = 8;
|
|
494
723
|
var ED25519_PUBLIC_KEY_BYTE_LENGTH = 32;
|
|
495
724
|
function ed25519HexFromGAddress(trimmed) {
|
|
496
725
|
try {
|
|
497
726
|
const raw = StrKey3.decodeEd25519PublicKey(trimmed);
|
|
498
|
-
return
|
|
727
|
+
return Buffer6.from(raw).toString("hex");
|
|
499
728
|
} catch {
|
|
500
729
|
return void 0;
|
|
501
730
|
}
|
|
@@ -782,10 +1011,11 @@ async function proveSingleWithdrawTransaction(parameters) {
|
|
|
782
1011
|
);
|
|
783
1012
|
}
|
|
784
1013
|
function buildPrimaryWithdrawForCoin(parameters) {
|
|
785
|
-
const witness =
|
|
786
|
-
parameters.
|
|
787
|
-
parameters.
|
|
788
|
-
|
|
1014
|
+
const witness = withdrawMerkleWitnessFromTree({
|
|
1015
|
+
sdk: parameters.sdk,
|
|
1016
|
+
coin: parameters.coin,
|
|
1017
|
+
state: parameters.state
|
|
1018
|
+
});
|
|
789
1019
|
const privKeyScalar = privKeyScalarDecimalFromRecipientScalarHex(
|
|
790
1020
|
parameters.privKeyScalarHex
|
|
791
1021
|
);
|
|
@@ -1207,23 +1437,6 @@ import {
|
|
|
1207
1437
|
randomFrDecimal253,
|
|
1208
1438
|
scalarHexToFrDecimal as scalarHexToFrDecimal2
|
|
1209
1439
|
} from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
1210
|
-
|
|
1211
|
-
// src/transact/merkle/field-decimal.ts
|
|
1212
|
-
import { Buffer as Buffer6 } from "buffer";
|
|
1213
|
-
var BN254 = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
|
|
1214
|
-
var MERKLE_ROOT_BYTE_LENGTH = 32;
|
|
1215
|
-
var DECIMAL_STRING_RADIX = 10;
|
|
1216
|
-
function merkleRootBufferToFrDecimal(root) {
|
|
1217
|
-
if (root.length !== MERKLE_ROOT_BYTE_LENGTH) {
|
|
1218
|
-
throw new Error(
|
|
1219
|
-
`expected ${MERKLE_ROOT_BYTE_LENGTH}-byte merkle root, got ${root.length}`
|
|
1220
|
-
);
|
|
1221
|
-
}
|
|
1222
|
-
const hex = Buffer6.from(root).toString("hex");
|
|
1223
|
-
return (BigInt(`0x${hex}`) % BN254).toString(DECIMAL_STRING_RADIX);
|
|
1224
|
-
}
|
|
1225
|
-
|
|
1226
|
-
// src/transact/pool/prepare-deposit-proof.ts
|
|
1227
1440
|
function userDepositSlot(input) {
|
|
1228
1441
|
return {
|
|
1229
1442
|
value: input.coin.value,
|
|
@@ -1455,6 +1668,7 @@ function createPrivacyPoolService(input) {
|
|
|
1455
1668
|
var configuredPrivacyPoolService;
|
|
1456
1669
|
function configurePrivacyPoolService(service) {
|
|
1457
1670
|
configuredPrivacyPoolService = service;
|
|
1671
|
+
registerMerkleSessionSdkHost(service);
|
|
1458
1672
|
}
|
|
1459
1673
|
function getPrivacyPoolService() {
|
|
1460
1674
|
if (!configuredPrivacyPoolService) {
|
|
@@ -3112,7 +3326,8 @@ function poolMerkleStateToCachedView(state) {
|
|
|
3112
3326
|
return {
|
|
3113
3327
|
commitments: state.commitments,
|
|
3114
3328
|
updatedAt: state.updatedAt,
|
|
3115
|
-
merkleRootHex: state.merkleRootHex
|
|
3329
|
+
merkleRootHex: state.merkleRootHex,
|
|
3330
|
+
...state.nodes ? { nodes: state.nodes } : {}
|
|
3116
3331
|
};
|
|
3117
3332
|
}
|
|
3118
3333
|
|
|
@@ -3245,6 +3460,65 @@ function reuseCachedCommitments(input) {
|
|
|
3245
3460
|
return cachedCommitments;
|
|
3246
3461
|
}
|
|
3247
3462
|
|
|
3463
|
+
// src/transact/merkle/persist-fetched.ts
|
|
3464
|
+
function cachedMerkleUnchanged(cachedState, commitments, merkleRootHex) {
|
|
3465
|
+
if (!cachedState) {
|
|
3466
|
+
return false;
|
|
3467
|
+
}
|
|
3468
|
+
if (cachedState.commitments.length !== commitments.length) {
|
|
3469
|
+
return false;
|
|
3470
|
+
}
|
|
3471
|
+
return cachedState.merkleRootHex === merkleRootHex;
|
|
3472
|
+
}
|
|
3473
|
+
function viewFromCachedMerkle(cachedState, merkleRootHex) {
|
|
3474
|
+
return {
|
|
3475
|
+
commitments: cachedState.commitments,
|
|
3476
|
+
updatedAt: cachedState.updatedAt,
|
|
3477
|
+
merkleRootHex: cachedState.merkleRootHex ?? merkleRootHex,
|
|
3478
|
+
commitmentCount: cachedState.commitments.length,
|
|
3479
|
+
...cachedState.nodes ? { nodes: cachedState.nodes } : {}
|
|
3480
|
+
};
|
|
3481
|
+
}
|
|
3482
|
+
function merkleStateForPersist(input) {
|
|
3483
|
+
return {
|
|
3484
|
+
poolContract: input.poolContractId,
|
|
3485
|
+
commitments: input.commitments,
|
|
3486
|
+
commitmentCount: input.commitments.length,
|
|
3487
|
+
merkleRootHex: input.merkleRootHex,
|
|
3488
|
+
updatedAt: input.updatedAt,
|
|
3489
|
+
...input.nodes ? { nodes: input.nodes } : {}
|
|
3490
|
+
};
|
|
3491
|
+
}
|
|
3492
|
+
async function persistFetchedMerkleState(input) {
|
|
3493
|
+
const cachedState = input.cachedState;
|
|
3494
|
+
if (cachedMerkleUnchanged(cachedState, input.commitments, input.merkleRootHex) && cachedState) {
|
|
3495
|
+
return viewFromCachedMerkle(cachedState, input.merkleRootHex);
|
|
3496
|
+
}
|
|
3497
|
+
const nodes = await resolveExtendedMerkleNodes({
|
|
3498
|
+
poolContract: input.poolContractId,
|
|
3499
|
+
commitments: input.commitments,
|
|
3500
|
+
merkleRootHex: input.merkleRootHex,
|
|
3501
|
+
...cachedState ? { cachedState } : {}
|
|
3502
|
+
});
|
|
3503
|
+
const updatedAt = Date.now();
|
|
3504
|
+
await input.poolMerkleState?.set(
|
|
3505
|
+
merkleStateForPersist({
|
|
3506
|
+
poolContractId: input.poolContractId,
|
|
3507
|
+
commitments: input.commitments,
|
|
3508
|
+
merkleRootHex: input.merkleRootHex,
|
|
3509
|
+
updatedAt,
|
|
3510
|
+
...nodes ? { nodes } : {}
|
|
3511
|
+
})
|
|
3512
|
+
);
|
|
3513
|
+
return {
|
|
3514
|
+
commitments: input.commitments,
|
|
3515
|
+
updatedAt,
|
|
3516
|
+
merkleRootHex: input.merkleRootHex,
|
|
3517
|
+
commitmentCount: input.commitments.length,
|
|
3518
|
+
...nodes ? { nodes } : {}
|
|
3519
|
+
};
|
|
3520
|
+
}
|
|
3521
|
+
|
|
3248
3522
|
// src/transact/merkle/fetch-contract.ts
|
|
3249
3523
|
async function fetchAndMergeMerkleState(parameters) {
|
|
3250
3524
|
const client = createPoolClient(parameters);
|
|
@@ -3337,43 +3611,6 @@ async function loadCommitments(input) {
|
|
|
3337
3611
|
});
|
|
3338
3612
|
return [...reused, ...fetched];
|
|
3339
3613
|
}
|
|
3340
|
-
async function persistFetchedMerkleState(input) {
|
|
3341
|
-
const cachedState = input.cachedState;
|
|
3342
|
-
if (cachedState && cachedMerkleUnchanged(cachedState, input.commitments, input.merkleRootHex)) {
|
|
3343
|
-
return viewFromCachedMerkle(cachedState, input.merkleRootHex);
|
|
3344
|
-
}
|
|
3345
|
-
const updatedAt = Date.now();
|
|
3346
|
-
await input.poolMerkleState?.set({
|
|
3347
|
-
poolContract: input.poolContractId,
|
|
3348
|
-
commitments: input.commitments,
|
|
3349
|
-
commitmentCount: input.commitments.length,
|
|
3350
|
-
merkleRootHex: input.merkleRootHex,
|
|
3351
|
-
updatedAt
|
|
3352
|
-
});
|
|
3353
|
-
return {
|
|
3354
|
-
commitments: input.commitments,
|
|
3355
|
-
updatedAt,
|
|
3356
|
-
merkleRootHex: input.merkleRootHex,
|
|
3357
|
-
commitmentCount: input.commitments.length
|
|
3358
|
-
};
|
|
3359
|
-
}
|
|
3360
|
-
function viewFromCachedMerkle(cachedState, merkleRootHex) {
|
|
3361
|
-
return {
|
|
3362
|
-
commitments: cachedState.commitments,
|
|
3363
|
-
updatedAt: cachedState.updatedAt,
|
|
3364
|
-
merkleRootHex: cachedState.merkleRootHex ?? merkleRootHex,
|
|
3365
|
-
commitmentCount: cachedState.commitments.length
|
|
3366
|
-
};
|
|
3367
|
-
}
|
|
3368
|
-
function cachedMerkleUnchanged(cachedState, commitments, merkleRootHex) {
|
|
3369
|
-
if (!cachedState) {
|
|
3370
|
-
return false;
|
|
3371
|
-
}
|
|
3372
|
-
if ((cachedState.merkleRootHex ?? merkleRootHex) !== merkleRootHex) {
|
|
3373
|
-
return false;
|
|
3374
|
-
}
|
|
3375
|
-
return cachedState.commitments.join(",") === commitments.join(",");
|
|
3376
|
-
}
|
|
3377
3614
|
|
|
3378
3615
|
// src/transact/encoding/fr-decimal-to-bytes.ts
|
|
3379
3616
|
var BN254_SCALAR_MOD = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
|
|
@@ -3486,13 +3723,19 @@ var walletPrivateAddressRecordSchema = z.object({
|
|
|
3486
3723
|
privateAddress: z.string().min(1),
|
|
3487
3724
|
createdAt: z.number()
|
|
3488
3725
|
});
|
|
3726
|
+
var leanImtNodeSchema = z.object({
|
|
3727
|
+
level: z.number().int().nonnegative(),
|
|
3728
|
+
index: z.number().int().nonnegative(),
|
|
3729
|
+
value: z.string().min(1)
|
|
3730
|
+
});
|
|
3489
3731
|
var poolMerkleStateSchema = z.object({
|
|
3490
3732
|
poolContract: z.string().min(1),
|
|
3491
3733
|
commitments: z.array(z.string()),
|
|
3492
3734
|
commitmentCount: z.number().int().nonnegative(),
|
|
3493
3735
|
merkleRootHex: z.string().min(1),
|
|
3494
3736
|
updatedAt: z.number(),
|
|
3495
|
-
syncedLedger: z.number().int().optional()
|
|
3737
|
+
syncedLedger: z.number().int().optional(),
|
|
3738
|
+
nodes: z.array(leanImtNodeSchema).optional()
|
|
3496
3739
|
});
|
|
3497
3740
|
var leafEphemeralSchema = z.object({
|
|
3498
3741
|
poolContract: z.string().min(1),
|
|
@@ -4905,6 +5148,7 @@ function createPoolMerkleService(context) {
|
|
|
4905
5148
|
async appendPoolCommitments(input) {
|
|
4906
5149
|
const current = await this.getPoolMerkleState(input.poolContract);
|
|
4907
5150
|
const mergedCommitments = [...current?.commitments ?? [], ...input.commitments];
|
|
5151
|
+
const nodes = input.nodes ?? (input.commitments.length === 0 ? current?.nodes : void 0);
|
|
4908
5152
|
await this.setPoolMerkleState(
|
|
4909
5153
|
withoutUndefinedFields({
|
|
4910
5154
|
poolContract: input.poolContract,
|
|
@@ -4912,7 +5156,8 @@ function createPoolMerkleService(context) {
|
|
|
4912
5156
|
commitmentCount: mergedCommitments.length,
|
|
4913
5157
|
merkleRootHex: input.merkleRootHex,
|
|
4914
5158
|
updatedAt: Date.now(),
|
|
4915
|
-
syncedLedger: input.syncedLedger ?? current?.syncedLedger
|
|
5159
|
+
syncedLedger: input.syncedLedger ?? current?.syncedLedger,
|
|
5160
|
+
nodes
|
|
4916
5161
|
})
|
|
4917
5162
|
);
|
|
4918
5163
|
}
|
|
@@ -5441,7 +5686,11 @@ async function loadMerkleState(environment, walletPublicKey) {
|
|
|
5441
5686
|
transactEnvironment: environment,
|
|
5442
5687
|
...environment.poolMerkleState ? { poolMerkleState: environment.poolMerkleState } : {}
|
|
5443
5688
|
});
|
|
5444
|
-
return {
|
|
5689
|
+
return merkleSnapshotToStateFile({
|
|
5690
|
+
commitments: merged.commitments,
|
|
5691
|
+
merkleRootHex: merged.merkleRootHex,
|
|
5692
|
+
...merged.nodes ? { nodes: merged.nodes } : {}
|
|
5693
|
+
});
|
|
5445
5694
|
}
|
|
5446
5695
|
|
|
5447
5696
|
// src/transact/escrow/require-escrow-spend-scalar.ts
|
|
@@ -5588,7 +5837,8 @@ async function buildSpendProofContextAtExecute(input) {
|
|
|
5588
5837
|
input.prepared.intent.asset
|
|
5589
5838
|
);
|
|
5590
5839
|
const coin = requireCoinNoteFromRecord(primaryRecord);
|
|
5591
|
-
const
|
|
5840
|
+
const merkleState = await loadMerkleState(input.environment, walletPublicKey);
|
|
5841
|
+
const commitments = merkleState.commitments;
|
|
5592
5842
|
const leafIndex = findCommitmentLeafIndex(commitments, coin.commitment);
|
|
5593
5843
|
if (leafIndex < 0) {
|
|
5594
5844
|
throw new Error("Coin commitment not found in on-chain Merkle state.");
|
|
@@ -5605,6 +5855,7 @@ async function buildSpendProofContextAtExecute(input) {
|
|
|
5605
5855
|
tokenAddress,
|
|
5606
5856
|
coin,
|
|
5607
5857
|
commitments,
|
|
5858
|
+
merkleState,
|
|
5608
5859
|
ephemeral,
|
|
5609
5860
|
senderPrivKeyScalarHex,
|
|
5610
5861
|
recipientPrivateAddressStpl1: input.recipientPrivateAddressStpl1
|
|
@@ -5670,7 +5921,7 @@ async function buildSingleTransferProofAtExecute(input) {
|
|
|
5670
5921
|
const changeStroops = BigInt(context.coin.value) - input.prepared.intent.amount - (feeOutput?.requiredFee ?? 0n);
|
|
5671
5922
|
const proof = await prepareConfidentialTransferProof({
|
|
5672
5923
|
coin: context.coin,
|
|
5673
|
-
state:
|
|
5924
|
+
state: context.merkleState,
|
|
5674
5925
|
senderPrivKeyScalarHex: context.senderPrivKeyScalarHex,
|
|
5675
5926
|
depositorEphemeralKey: serializeEphemeralKeyString({
|
|
5676
5927
|
xHex: context.ephemeral.xHex,
|
|
@@ -5707,7 +5958,7 @@ async function buildDualTransferProofAtExecute(input) {
|
|
|
5707
5958
|
const proof = await prepareConfidentialTransferProofDual({
|
|
5708
5959
|
coinA: context.coin,
|
|
5709
5960
|
coinB: secondary.coin,
|
|
5710
|
-
state:
|
|
5961
|
+
state: context.merkleState,
|
|
5711
5962
|
senderPrivKeyScalarHex: context.senderPrivKeyScalarHex,
|
|
5712
5963
|
ephemeralAKey: serializeEphemeralKeyString({
|
|
5713
5964
|
xHex: context.ephemeral.xHex,
|
|
@@ -5955,7 +6206,7 @@ async function finalizeSingleWithdrawAtExecute(prepared, environment, poolServic
|
|
|
5955
6206
|
});
|
|
5956
6207
|
const proof = await poolService.prepareWithdrawTransactProof({
|
|
5957
6208
|
coin: context.coin,
|
|
5958
|
-
state:
|
|
6209
|
+
state: context.merkleState,
|
|
5959
6210
|
destinationStellarAddress: prepared.intent.to,
|
|
5960
6211
|
privKeyScalarHex: context.senderPrivKeyScalarHex,
|
|
5961
6212
|
depositorEphemeralKey: serializeEphemeralKeyString({
|
|
@@ -6008,7 +6259,7 @@ async function finalizeDualWithdrawAtExecute(prepared, environment, poolService,
|
|
|
6008
6259
|
const proof = await poolService.prepareWithdrawTransactProofDual({
|
|
6009
6260
|
coinA: context.coin,
|
|
6010
6261
|
coinB: secondary.coin,
|
|
6011
|
-
state:
|
|
6262
|
+
state: context.merkleState,
|
|
6012
6263
|
destinationStellarAddress: prepared.intent.to,
|
|
6013
6264
|
privKeyScalarHex: context.senderPrivKeyScalarHex,
|
|
6014
6265
|
...dualWithdrawEphemeralKeys({ context, secondary }),
|