@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/index.js
CHANGED
|
@@ -452,6 +452,261 @@ function buildPrivateRecordFromDeposit(input) {
|
|
|
452
452
|
};
|
|
453
453
|
}
|
|
454
454
|
|
|
455
|
+
// src/transact/merkle/lean-imt-api.ts
|
|
456
|
+
function asLeanImtSessionApi(sdk) {
|
|
457
|
+
const candidate = sdk;
|
|
458
|
+
if (typeof candidate.importLeanImtFromState !== "function") {
|
|
459
|
+
return void 0;
|
|
460
|
+
}
|
|
461
|
+
if (typeof candidate.insertTwoLeanImt !== "function") {
|
|
462
|
+
return void 0;
|
|
463
|
+
}
|
|
464
|
+
if (typeof candidate.exportLeanImt !== "function") {
|
|
465
|
+
return void 0;
|
|
466
|
+
}
|
|
467
|
+
if (typeof candidate.dropLeanImt !== "function") {
|
|
468
|
+
return void 0;
|
|
469
|
+
}
|
|
470
|
+
if (typeof candidate.buildWithdrawMerkleWitnessFromHandle !== "function") {
|
|
471
|
+
return void 0;
|
|
472
|
+
}
|
|
473
|
+
return candidate;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// src/transact/merkle/field-decimal.ts
|
|
477
|
+
import { Buffer as Buffer4 } from "buffer";
|
|
478
|
+
var BN254 = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
|
|
479
|
+
var MERKLE_ROOT_BYTE_LENGTH = 32;
|
|
480
|
+
var DECIMAL_STRING_RADIX = 10;
|
|
481
|
+
function merkleRootBufferToFrDecimal(root) {
|
|
482
|
+
if (root.length !== MERKLE_ROOT_BYTE_LENGTH) {
|
|
483
|
+
throw new Error(
|
|
484
|
+
`expected ${MERKLE_ROOT_BYTE_LENGTH}-byte merkle root, got ${root.length}`
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
const hex = Buffer4.from(root).toString("hex");
|
|
488
|
+
return (BigInt(`0x${hex}`) % BN254).toString(DECIMAL_STRING_RADIX);
|
|
489
|
+
}
|
|
490
|
+
var MERKLE_ROOT_HEX_PATTERN = /^[0-9a-fA-F]{64}$/;
|
|
491
|
+
function merkleRootHexToFrDecimal(merkleRootHex) {
|
|
492
|
+
const trimmed = merkleRootHex.trim();
|
|
493
|
+
if (!MERKLE_ROOT_HEX_PATTERN.test(trimmed)) {
|
|
494
|
+
return void 0;
|
|
495
|
+
}
|
|
496
|
+
return merkleRootBufferToFrDecimal(Buffer4.from(trimmed, "hex"));
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// src/transact/merkle/state-file.ts
|
|
500
|
+
function merkleSnapshotToStateFile(input) {
|
|
501
|
+
const root = merkleRootHexToFrDecimal(input.merkleRootHex);
|
|
502
|
+
const nodes = input.nodes;
|
|
503
|
+
if (!nodes || nodes.length === 0 || root === void 0) {
|
|
504
|
+
return { commitments: input.commitments };
|
|
505
|
+
}
|
|
506
|
+
return {
|
|
507
|
+
commitments: input.commitments,
|
|
508
|
+
nodes,
|
|
509
|
+
root
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// src/transact/merkle/extend-snapshot.ts
|
|
514
|
+
function isEvenLeafCount(count) {
|
|
515
|
+
return count % 2 === 0;
|
|
516
|
+
}
|
|
517
|
+
function importHandle(sdk, state) {
|
|
518
|
+
try {
|
|
519
|
+
return sdk.importLeanImtFromState(state);
|
|
520
|
+
} catch {
|
|
521
|
+
return void 0;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
function insertNewPairs(input) {
|
|
525
|
+
for (let index = input.prefixLength; index < input.commitments.length; index += 2) {
|
|
526
|
+
const leafA = input.commitments.at(index);
|
|
527
|
+
const leafB = input.commitments.at(index + 1);
|
|
528
|
+
if (leafA === void 0 || leafB === void 0) {
|
|
529
|
+
return false;
|
|
530
|
+
}
|
|
531
|
+
try {
|
|
532
|
+
input.sdk.insertTwoLeanImt(input.handle, leafA, leafB);
|
|
533
|
+
} catch {
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return true;
|
|
538
|
+
}
|
|
539
|
+
function snapshotNodes(sdk, handle) {
|
|
540
|
+
try {
|
|
541
|
+
return sdk.exportLeanImt(handle).nodes;
|
|
542
|
+
} catch {
|
|
543
|
+
return void 0;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
function prefixSnapshotState(input) {
|
|
547
|
+
const prefixLength = input.cachedState?.nodes ? input.cachedState.commitments.length : 0;
|
|
548
|
+
return merkleSnapshotToStateFile({
|
|
549
|
+
commitments: input.commitments.slice(0, prefixLength),
|
|
550
|
+
merkleRootHex: input.cachedState?.merkleRootHex ?? input.merkleRootHex,
|
|
551
|
+
...input.cachedState?.nodes ? { nodes: input.cachedState.nodes } : {}
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
function importSnapshotState(input) {
|
|
555
|
+
if (input.prefixState.nodes && input.prefixState.commitments.length > 0) {
|
|
556
|
+
return input.prefixState;
|
|
557
|
+
}
|
|
558
|
+
return merkleSnapshotToStateFile({
|
|
559
|
+
commitments: input.commitments,
|
|
560
|
+
merkleRootHex: input.merkleRootHex
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
function exportExtendedNodes(input) {
|
|
564
|
+
const inserted = input.prefixState.nodes ? insertNewPairs({
|
|
565
|
+
sdk: input.sdk,
|
|
566
|
+
handle: input.handle,
|
|
567
|
+
prefixLength: input.prefixState.commitments.length,
|
|
568
|
+
commitments: input.commitments
|
|
569
|
+
}) : true;
|
|
570
|
+
if (!inserted) {
|
|
571
|
+
input.sdk.dropLeanImt(input.handle);
|
|
572
|
+
return void 0;
|
|
573
|
+
}
|
|
574
|
+
const nodes = snapshotNodes(input.sdk, input.handle);
|
|
575
|
+
if (!nodes) {
|
|
576
|
+
input.sdk.dropLeanImt(input.handle);
|
|
577
|
+
}
|
|
578
|
+
return nodes;
|
|
579
|
+
}
|
|
580
|
+
function extendMerkleSnapshotNodes(input) {
|
|
581
|
+
if (!isEvenLeafCount(input.commitments.length)) {
|
|
582
|
+
return {};
|
|
583
|
+
}
|
|
584
|
+
const prefixState = prefixSnapshotState(input);
|
|
585
|
+
const handle = importHandle(
|
|
586
|
+
input.sdk,
|
|
587
|
+
importSnapshotState({ ...input, prefixState })
|
|
588
|
+
);
|
|
589
|
+
if (handle === void 0) {
|
|
590
|
+
return {};
|
|
591
|
+
}
|
|
592
|
+
const nodes = exportExtendedNodes({
|
|
593
|
+
sdk: input.sdk,
|
|
594
|
+
handle,
|
|
595
|
+
prefixState,
|
|
596
|
+
commitments: input.commitments
|
|
597
|
+
});
|
|
598
|
+
if (!nodes) {
|
|
599
|
+
return {};
|
|
600
|
+
}
|
|
601
|
+
return { nodes, handle };
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// src/transact/merkle/tree-session.ts
|
|
605
|
+
var merkleSdkHost;
|
|
606
|
+
function registerMerkleSessionSdkHost(host) {
|
|
607
|
+
merkleSdkHost = host;
|
|
608
|
+
}
|
|
609
|
+
async function loadSessionSdk() {
|
|
610
|
+
const host = merkleSdkHost;
|
|
611
|
+
if (typeof host?.getInitializedSdk !== "function") {
|
|
612
|
+
return void 0;
|
|
613
|
+
}
|
|
614
|
+
try {
|
|
615
|
+
return asLeanImtSessionApi(await host.getInitializedSdk());
|
|
616
|
+
} catch {
|
|
617
|
+
return void 0;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
var sessionsByPool = /* @__PURE__ */ new Map();
|
|
621
|
+
var handlesByKey = /* @__PURE__ */ new Map();
|
|
622
|
+
function merkleSessionKey(state) {
|
|
623
|
+
const root = state.root?.trim();
|
|
624
|
+
if (root) {
|
|
625
|
+
return `${state.commitments.length}:${root}`;
|
|
626
|
+
}
|
|
627
|
+
const first = state.commitments[0] ?? "";
|
|
628
|
+
const last = state.commitments.at(-1) ?? "";
|
|
629
|
+
return `${state.commitments.length}:${first}:${last}`;
|
|
630
|
+
}
|
|
631
|
+
function rememberHandle(poolContract, key, handle) {
|
|
632
|
+
const existing = sessionsByPool.get(poolContract);
|
|
633
|
+
if (existing && existing.handle !== handle) {
|
|
634
|
+
handlesByKey.delete(existing.key);
|
|
635
|
+
}
|
|
636
|
+
sessionsByPool.set(poolContract, { handle, key });
|
|
637
|
+
handlesByKey.set(key, handle);
|
|
638
|
+
}
|
|
639
|
+
function importHandle2(sdk, state) {
|
|
640
|
+
try {
|
|
641
|
+
return sdk.importLeanImtFromState(state);
|
|
642
|
+
} catch {
|
|
643
|
+
return void 0;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
function merkleTreeHandleForState(state) {
|
|
647
|
+
return handlesByKey.get(merkleSessionKey(state));
|
|
648
|
+
}
|
|
649
|
+
function bindImportedMerkleTree(input) {
|
|
650
|
+
rememberHandle(input.poolContract, merkleSessionKey(input.state), input.handle);
|
|
651
|
+
}
|
|
652
|
+
async function bindPoolMerkleTree(state) {
|
|
653
|
+
const sdk = await loadSessionSdk();
|
|
654
|
+
if (!sdk) {
|
|
655
|
+
return void 0;
|
|
656
|
+
}
|
|
657
|
+
const snapshot = merkleSnapshotToStateFile(state);
|
|
658
|
+
const key = merkleSessionKey(snapshot);
|
|
659
|
+
const existing = sessionsByPool.get(state.poolContract);
|
|
660
|
+
if (existing?.key === key) {
|
|
661
|
+
return existing.handle;
|
|
662
|
+
}
|
|
663
|
+
const handle = importHandle2(sdk, snapshot);
|
|
664
|
+
if (handle === void 0) {
|
|
665
|
+
return void 0;
|
|
666
|
+
}
|
|
667
|
+
if (existing) {
|
|
668
|
+
sdk.dropLeanImt(existing.handle);
|
|
669
|
+
}
|
|
670
|
+
rememberHandle(state.poolContract, key, handle);
|
|
671
|
+
return handle;
|
|
672
|
+
}
|
|
673
|
+
async function resolveExtendedMerkleNodes(input) {
|
|
674
|
+
const cached = input.cachedState;
|
|
675
|
+
if (cached && cached.commitments.length === input.commitments.length && cached.merkleRootHex === input.merkleRootHex) {
|
|
676
|
+
return cached.nodes;
|
|
677
|
+
}
|
|
678
|
+
const sdk = await loadSessionSdk();
|
|
679
|
+
if (!sdk) {
|
|
680
|
+
return void 0;
|
|
681
|
+
}
|
|
682
|
+
const extended = extendMerkleSnapshotNodes({
|
|
683
|
+
sdk,
|
|
684
|
+
commitments: input.commitments,
|
|
685
|
+
merkleRootHex: input.merkleRootHex,
|
|
686
|
+
...cached ? { cachedState: cached } : {}
|
|
687
|
+
});
|
|
688
|
+
if (extended.handle !== void 0) {
|
|
689
|
+
bindImportedMerkleTree({
|
|
690
|
+
poolContract: input.poolContract,
|
|
691
|
+
handle: extended.handle,
|
|
692
|
+
state: merkleSnapshotToStateFile({
|
|
693
|
+
commitments: input.commitments,
|
|
694
|
+
merkleRootHex: input.merkleRootHex,
|
|
695
|
+
...extended.nodes ? { nodes: extended.nodes } : {}
|
|
696
|
+
})
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
return extended.nodes;
|
|
700
|
+
}
|
|
701
|
+
function withdrawMerkleWitnessFromTree(input) {
|
|
702
|
+
const session = asLeanImtSessionApi(input.sdk);
|
|
703
|
+
const handle = merkleTreeHandleForState(input.state);
|
|
704
|
+
if (session && handle !== void 0) {
|
|
705
|
+
return session.buildWithdrawMerkleWitnessFromHandle(input.coin, handle);
|
|
706
|
+
}
|
|
707
|
+
return input.sdk.buildWithdrawMerkleWitness(input.coin, input.state);
|
|
708
|
+
}
|
|
709
|
+
|
|
455
710
|
// src/transact/pool/service.ts
|
|
456
711
|
import {
|
|
457
712
|
decodeDecodedEphemeralKey
|
|
@@ -512,18 +767,18 @@ function privateAddressSdk(sdk) {
|
|
|
512
767
|
import { withdrawObjectFromMerkleWitness as withdrawObjectFromMerkleWitness2 } from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
513
768
|
|
|
514
769
|
// src/transact/proofs/transaction-input.ts
|
|
515
|
-
import { Buffer as
|
|
770
|
+
import { Buffer as Buffer6 } from "buffer";
|
|
516
771
|
import { StrKey as StrKey2 } from "@stellar/stellar-sdk";
|
|
517
772
|
|
|
518
773
|
// src/transact/stellar/token-contract.ts
|
|
519
|
-
import { Buffer as
|
|
774
|
+
import { Buffer as Buffer5 } from "buffer";
|
|
520
775
|
import { StrKey } from "@stellar/stellar-sdk";
|
|
521
776
|
var CONTRACT_ID_BYTE_LENGTH = 32;
|
|
522
777
|
var HEX_CHARS_PER_BYTE = 2;
|
|
523
778
|
var CONTRACT_ID_HEX_CHAR_LENGTH = CONTRACT_ID_BYTE_LENGTH * HEX_CHARS_PER_BYTE;
|
|
524
779
|
var CONTRACT_ID_HEX = /^(?:0x)?([0-9a-f]{64})$/i;
|
|
525
780
|
function encodeContractFromHex(hexPayload) {
|
|
526
|
-
return StrKey.encodeContract(
|
|
781
|
+
return StrKey.encodeContract(Buffer5.from(hexPayload, "hex"));
|
|
527
782
|
}
|
|
528
783
|
function normalizeSorobanContractId(raw) {
|
|
529
784
|
const trimmed = raw.trim();
|
|
@@ -556,14 +811,14 @@ var ZERO_PUBLIC_WITHDRAW_ADDRESS = {
|
|
|
556
811
|
var CONTRACT_ADDRESS_HALF_BYTES = 16;
|
|
557
812
|
var CONTRACT_ADDRESS_BYTES = 32;
|
|
558
813
|
function bytes16ToDecimal(bytes) {
|
|
559
|
-
return BigInt(`0x${
|
|
814
|
+
return BigInt(`0x${Buffer6.from(bytes).toString("hex")}`).toString();
|
|
560
815
|
}
|
|
561
816
|
function decimalToBytes16(value) {
|
|
562
817
|
const hex = BigInt(value).toString(16).padStart(CONTRACT_ADDRESS_HALF_BYTES * 2, "0");
|
|
563
818
|
if (hex.length > CONTRACT_ADDRESS_HALF_BYTES * 2) {
|
|
564
819
|
throw new Error("Asset leg does not fit into 16 bytes.");
|
|
565
820
|
}
|
|
566
|
-
return
|
|
821
|
+
return Buffer6.from(hex, "hex");
|
|
567
822
|
}
|
|
568
823
|
function tokenAddressFrParts(tokenAddress) {
|
|
569
824
|
const normalized = resolveTokenContractId(tokenAddress);
|
|
@@ -605,7 +860,7 @@ function tokenAddressToAssetLeg(tokenAddress) {
|
|
|
605
860
|
return [hi, lo];
|
|
606
861
|
}
|
|
607
862
|
function assetLegToTokenAddress(assetHi, assetLo) {
|
|
608
|
-
const payload =
|
|
863
|
+
const payload = Buffer6.concat([decimalToBytes16(assetHi), decimalToBytes16(assetLo)]);
|
|
609
864
|
return StrKey2.encodeContract(payload);
|
|
610
865
|
}
|
|
611
866
|
function buildZeroPublicLegs(publicNInputs = 1, publicNOutputs = 1) {
|
|
@@ -686,7 +941,7 @@ var MIN_CONFIDENTIAL_TRANSFER_STROOPS = 1n;
|
|
|
686
941
|
var ZERO_STROOPS = 0n;
|
|
687
942
|
function withdrawWitnessForCoin(parameters) {
|
|
688
943
|
const { sdk, coin, state } = parameters;
|
|
689
|
-
const witness = sdk
|
|
944
|
+
const witness = withdrawMerkleWitnessFromTree({ sdk, coin, state });
|
|
690
945
|
const withdrawApplicationId = coin.application_id ?? parameters.applicationId;
|
|
691
946
|
const withdrawObject = withdrawObjectFromMerkleWitness(
|
|
692
947
|
witness,
|
|
@@ -873,7 +1128,7 @@ import {
|
|
|
873
1128
|
DEMO_AUDIT_PUBLIC_KEY,
|
|
874
1129
|
resolveTransactionAuditParams
|
|
875
1130
|
} from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
876
|
-
import { Buffer as
|
|
1131
|
+
import { Buffer as Buffer7 } from "buffer";
|
|
877
1132
|
var UNCOMPRESSED_PREFIX = "04";
|
|
878
1133
|
var UNCOMPRESSED_HEX_LENGTH = 130;
|
|
879
1134
|
var XY_HEX_LENGTH = 128;
|
|
@@ -900,7 +1155,7 @@ function parseAuditPublicKeyFromEnvHex(raw) {
|
|
|
900
1155
|
"Audit public key must be uncompressed 65-byte hex (04 + X + Y) or 64-byte X+Y hex"
|
|
901
1156
|
);
|
|
902
1157
|
}
|
|
903
|
-
const bytes =
|
|
1158
|
+
const bytes = Buffer7.from(payload, "hex");
|
|
904
1159
|
const auditPublicKeyXDecimal = BigInt(
|
|
905
1160
|
`0x${bytes.subarray(0, X_OFFSET_END).toString("hex")}`
|
|
906
1161
|
).toString(DECIMAL_RADIX);
|
|
@@ -943,13 +1198,13 @@ import { ed25519PubkeyPayloadHexToWithdrawFrDecimals } from "@arcanetech/stellar
|
|
|
943
1198
|
|
|
944
1199
|
// src/transact/stellar/account.ts
|
|
945
1200
|
import { StrKey as StrKey3 } from "@stellar/stellar-sdk";
|
|
946
|
-
import { Buffer as
|
|
1201
|
+
import { Buffer as Buffer8 } from "buffer";
|
|
947
1202
|
var MUXED_ACCOUNT_ID_BYTE_LENGTH = 8;
|
|
948
1203
|
var ED25519_PUBLIC_KEY_BYTE_LENGTH = 32;
|
|
949
1204
|
function ed25519HexFromGAddress(trimmed) {
|
|
950
1205
|
try {
|
|
951
1206
|
const raw = StrKey3.decodeEd25519PublicKey(trimmed);
|
|
952
|
-
return
|
|
1207
|
+
return Buffer8.from(raw).toString("hex");
|
|
953
1208
|
} catch {
|
|
954
1209
|
return void 0;
|
|
955
1210
|
}
|
|
@@ -1236,10 +1491,11 @@ async function proveSingleWithdrawTransaction(parameters) {
|
|
|
1236
1491
|
);
|
|
1237
1492
|
}
|
|
1238
1493
|
function buildPrimaryWithdrawForCoin(parameters) {
|
|
1239
|
-
const witness =
|
|
1240
|
-
parameters.
|
|
1241
|
-
parameters.
|
|
1242
|
-
|
|
1494
|
+
const witness = withdrawMerkleWitnessFromTree({
|
|
1495
|
+
sdk: parameters.sdk,
|
|
1496
|
+
coin: parameters.coin,
|
|
1497
|
+
state: parameters.state
|
|
1498
|
+
});
|
|
1243
1499
|
const privKeyScalar = privKeyScalarDecimalFromRecipientScalarHex(
|
|
1244
1500
|
parameters.privKeyScalarHex
|
|
1245
1501
|
);
|
|
@@ -1661,23 +1917,6 @@ import {
|
|
|
1661
1917
|
randomFrDecimal253,
|
|
1662
1918
|
scalarHexToFrDecimal as scalarHexToFrDecimal2
|
|
1663
1919
|
} from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
1664
|
-
|
|
1665
|
-
// src/transact/merkle/field-decimal.ts
|
|
1666
|
-
import { Buffer as Buffer8 } from "buffer";
|
|
1667
|
-
var BN254 = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
|
|
1668
|
-
var MERKLE_ROOT_BYTE_LENGTH = 32;
|
|
1669
|
-
var DECIMAL_STRING_RADIX = 10;
|
|
1670
|
-
function merkleRootBufferToFrDecimal(root) {
|
|
1671
|
-
if (root.length !== MERKLE_ROOT_BYTE_LENGTH) {
|
|
1672
|
-
throw new Error(
|
|
1673
|
-
`expected ${MERKLE_ROOT_BYTE_LENGTH}-byte merkle root, got ${root.length}`
|
|
1674
|
-
);
|
|
1675
|
-
}
|
|
1676
|
-
const hex = Buffer8.from(root).toString("hex");
|
|
1677
|
-
return (BigInt(`0x${hex}`) % BN254).toString(DECIMAL_STRING_RADIX);
|
|
1678
|
-
}
|
|
1679
|
-
|
|
1680
|
-
// src/transact/pool/prepare-deposit-proof.ts
|
|
1681
1920
|
function userDepositSlot(input) {
|
|
1682
1921
|
return {
|
|
1683
1922
|
value: input.coin.value,
|
|
@@ -1909,6 +2148,7 @@ function createPrivacyPoolService(input) {
|
|
|
1909
2148
|
var configuredPrivacyPoolService;
|
|
1910
2149
|
function configurePrivacyPoolService(service) {
|
|
1911
2150
|
configuredPrivacyPoolService = service;
|
|
2151
|
+
registerMerkleSessionSdkHost(service);
|
|
1912
2152
|
}
|
|
1913
2153
|
function getPrivacyPoolService() {
|
|
1914
2154
|
if (!configuredPrivacyPoolService) {
|
|
@@ -1927,7 +2167,8 @@ function poolMerkleStateToCachedView(state) {
|
|
|
1927
2167
|
return {
|
|
1928
2168
|
commitments: state.commitments,
|
|
1929
2169
|
updatedAt: state.updatedAt,
|
|
1930
|
-
merkleRootHex: state.merkleRootHex
|
|
2170
|
+
merkleRootHex: state.merkleRootHex,
|
|
2171
|
+
...state.nodes ? { nodes: state.nodes } : {}
|
|
1931
2172
|
};
|
|
1932
2173
|
}
|
|
1933
2174
|
|
|
@@ -2060,6 +2301,65 @@ function reuseCachedCommitments(input) {
|
|
|
2060
2301
|
return cachedCommitments;
|
|
2061
2302
|
}
|
|
2062
2303
|
|
|
2304
|
+
// src/transact/merkle/persist-fetched.ts
|
|
2305
|
+
function cachedMerkleUnchanged(cachedState, commitments, merkleRootHex) {
|
|
2306
|
+
if (!cachedState) {
|
|
2307
|
+
return false;
|
|
2308
|
+
}
|
|
2309
|
+
if (cachedState.commitments.length !== commitments.length) {
|
|
2310
|
+
return false;
|
|
2311
|
+
}
|
|
2312
|
+
return cachedState.merkleRootHex === merkleRootHex;
|
|
2313
|
+
}
|
|
2314
|
+
function viewFromCachedMerkle(cachedState, merkleRootHex) {
|
|
2315
|
+
return {
|
|
2316
|
+
commitments: cachedState.commitments,
|
|
2317
|
+
updatedAt: cachedState.updatedAt,
|
|
2318
|
+
merkleRootHex: cachedState.merkleRootHex ?? merkleRootHex,
|
|
2319
|
+
commitmentCount: cachedState.commitments.length,
|
|
2320
|
+
...cachedState.nodes ? { nodes: cachedState.nodes } : {}
|
|
2321
|
+
};
|
|
2322
|
+
}
|
|
2323
|
+
function merkleStateForPersist(input) {
|
|
2324
|
+
return {
|
|
2325
|
+
poolContract: input.poolContractId,
|
|
2326
|
+
commitments: input.commitments,
|
|
2327
|
+
commitmentCount: input.commitments.length,
|
|
2328
|
+
merkleRootHex: input.merkleRootHex,
|
|
2329
|
+
updatedAt: input.updatedAt,
|
|
2330
|
+
...input.nodes ? { nodes: input.nodes } : {}
|
|
2331
|
+
};
|
|
2332
|
+
}
|
|
2333
|
+
async function persistFetchedMerkleState(input) {
|
|
2334
|
+
const cachedState = input.cachedState;
|
|
2335
|
+
if (cachedMerkleUnchanged(cachedState, input.commitments, input.merkleRootHex) && cachedState) {
|
|
2336
|
+
return viewFromCachedMerkle(cachedState, input.merkleRootHex);
|
|
2337
|
+
}
|
|
2338
|
+
const nodes = await resolveExtendedMerkleNodes({
|
|
2339
|
+
poolContract: input.poolContractId,
|
|
2340
|
+
commitments: input.commitments,
|
|
2341
|
+
merkleRootHex: input.merkleRootHex,
|
|
2342
|
+
...cachedState ? { cachedState } : {}
|
|
2343
|
+
});
|
|
2344
|
+
const updatedAt = Date.now();
|
|
2345
|
+
await input.poolMerkleState?.set(
|
|
2346
|
+
merkleStateForPersist({
|
|
2347
|
+
poolContractId: input.poolContractId,
|
|
2348
|
+
commitments: input.commitments,
|
|
2349
|
+
merkleRootHex: input.merkleRootHex,
|
|
2350
|
+
updatedAt,
|
|
2351
|
+
...nodes ? { nodes } : {}
|
|
2352
|
+
})
|
|
2353
|
+
);
|
|
2354
|
+
return {
|
|
2355
|
+
commitments: input.commitments,
|
|
2356
|
+
updatedAt,
|
|
2357
|
+
merkleRootHex: input.merkleRootHex,
|
|
2358
|
+
commitmentCount: input.commitments.length,
|
|
2359
|
+
...nodes ? { nodes } : {}
|
|
2360
|
+
};
|
|
2361
|
+
}
|
|
2362
|
+
|
|
2063
2363
|
// src/transact/merkle/fetch-contract.ts
|
|
2064
2364
|
async function fetchAndMergeMerkleState(parameters) {
|
|
2065
2365
|
const client = createPoolClient(parameters);
|
|
@@ -2152,43 +2452,6 @@ async function loadCommitments(input) {
|
|
|
2152
2452
|
});
|
|
2153
2453
|
return [...reused, ...fetched];
|
|
2154
2454
|
}
|
|
2155
|
-
async function persistFetchedMerkleState(input) {
|
|
2156
|
-
const cachedState = input.cachedState;
|
|
2157
|
-
if (cachedState && cachedMerkleUnchanged(cachedState, input.commitments, input.merkleRootHex)) {
|
|
2158
|
-
return viewFromCachedMerkle(cachedState, input.merkleRootHex);
|
|
2159
|
-
}
|
|
2160
|
-
const updatedAt = Date.now();
|
|
2161
|
-
await input.poolMerkleState?.set({
|
|
2162
|
-
poolContract: input.poolContractId,
|
|
2163
|
-
commitments: input.commitments,
|
|
2164
|
-
commitmentCount: input.commitments.length,
|
|
2165
|
-
merkleRootHex: input.merkleRootHex,
|
|
2166
|
-
updatedAt
|
|
2167
|
-
});
|
|
2168
|
-
return {
|
|
2169
|
-
commitments: input.commitments,
|
|
2170
|
-
updatedAt,
|
|
2171
|
-
merkleRootHex: input.merkleRootHex,
|
|
2172
|
-
commitmentCount: input.commitments.length
|
|
2173
|
-
};
|
|
2174
|
-
}
|
|
2175
|
-
function viewFromCachedMerkle(cachedState, merkleRootHex) {
|
|
2176
|
-
return {
|
|
2177
|
-
commitments: cachedState.commitments,
|
|
2178
|
-
updatedAt: cachedState.updatedAt,
|
|
2179
|
-
merkleRootHex: cachedState.merkleRootHex ?? merkleRootHex,
|
|
2180
|
-
commitmentCount: cachedState.commitments.length
|
|
2181
|
-
};
|
|
2182
|
-
}
|
|
2183
|
-
function cachedMerkleUnchanged(cachedState, commitments, merkleRootHex) {
|
|
2184
|
-
if (!cachedState) {
|
|
2185
|
-
return false;
|
|
2186
|
-
}
|
|
2187
|
-
if ((cachedState.merkleRootHex ?? merkleRootHex) !== merkleRootHex) {
|
|
2188
|
-
return false;
|
|
2189
|
-
}
|
|
2190
|
-
return cachedState.commitments.join(",") === commitments.join(",");
|
|
2191
|
-
}
|
|
2192
2455
|
|
|
2193
2456
|
// src/transact/engine/prepare/shared.ts
|
|
2194
2457
|
async function resolveTokenContractId2(environment, assetId) {
|
|
@@ -2263,7 +2526,11 @@ async function loadMerkleState(environment, walletPublicKey) {
|
|
|
2263
2526
|
transactEnvironment: environment,
|
|
2264
2527
|
...environment.poolMerkleState ? { poolMerkleState: environment.poolMerkleState } : {}
|
|
2265
2528
|
});
|
|
2266
|
-
return {
|
|
2529
|
+
return merkleSnapshotToStateFile({
|
|
2530
|
+
commitments: merged.commitments,
|
|
2531
|
+
merkleRootHex: merged.merkleRootHex,
|
|
2532
|
+
...merged.nodes ? { nodes: merged.nodes } : {}
|
|
2533
|
+
});
|
|
2267
2534
|
}
|
|
2268
2535
|
function enrichPreparedOperation(prepared, outputRecords, artifacts) {
|
|
2269
2536
|
return {
|
|
@@ -2772,13 +3039,19 @@ var walletPrivateAddressRecordSchema = z.object({
|
|
|
2772
3039
|
privateAddress: z.string().min(1),
|
|
2773
3040
|
createdAt: z.number()
|
|
2774
3041
|
});
|
|
3042
|
+
var leanImtNodeSchema = z.object({
|
|
3043
|
+
level: z.number().int().nonnegative(),
|
|
3044
|
+
index: z.number().int().nonnegative(),
|
|
3045
|
+
value: z.string().min(1)
|
|
3046
|
+
});
|
|
2775
3047
|
var poolMerkleStateSchema = z.object({
|
|
2776
3048
|
poolContract: z.string().min(1),
|
|
2777
3049
|
commitments: z.array(z.string()),
|
|
2778
3050
|
commitmentCount: z.number().int().nonnegative(),
|
|
2779
3051
|
merkleRootHex: z.string().min(1),
|
|
2780
3052
|
updatedAt: z.number(),
|
|
2781
|
-
syncedLedger: z.number().int().optional()
|
|
3053
|
+
syncedLedger: z.number().int().optional(),
|
|
3054
|
+
nodes: z.array(leanImtNodeSchema).optional()
|
|
2782
3055
|
});
|
|
2783
3056
|
var leafEphemeralSchema = z.object({
|
|
2784
3057
|
poolContract: z.string().min(1),
|
|
@@ -4337,6 +4610,7 @@ function createPoolMerkleService(context) {
|
|
|
4337
4610
|
async appendPoolCommitments(input) {
|
|
4338
4611
|
const current = await this.getPoolMerkleState(input.poolContract);
|
|
4339
4612
|
const mergedCommitments = [...current?.commitments ?? [], ...input.commitments];
|
|
4613
|
+
const nodes = input.nodes ?? (input.commitments.length === 0 ? current?.nodes : void 0);
|
|
4340
4614
|
await this.setPoolMerkleState(
|
|
4341
4615
|
withoutUndefinedFields({
|
|
4342
4616
|
poolContract: input.poolContract,
|
|
@@ -4344,7 +4618,8 @@ function createPoolMerkleService(context) {
|
|
|
4344
4618
|
commitmentCount: mergedCommitments.length,
|
|
4345
4619
|
merkleRootHex: input.merkleRootHex,
|
|
4346
4620
|
updatedAt: Date.now(),
|
|
4347
|
-
syncedLedger: input.syncedLedger ?? current?.syncedLedger
|
|
4621
|
+
syncedLedger: input.syncedLedger ?? current?.syncedLedger,
|
|
4622
|
+
nodes
|
|
4348
4623
|
})
|
|
4349
4624
|
);
|
|
4350
4625
|
}
|
|
@@ -5614,12 +5889,46 @@ function createDeliveriesStateDelegates(state) {
|
|
|
5614
5889
|
};
|
|
5615
5890
|
}
|
|
5616
5891
|
|
|
5892
|
+
// src/transact/merkle/write-snapshot.ts
|
|
5893
|
+
async function writePoolMerkleState(input) {
|
|
5894
|
+
await input.setPoolMerkleState(input.state);
|
|
5895
|
+
await bindPoolMerkleTree(input.state);
|
|
5896
|
+
}
|
|
5897
|
+
async function appendPoolMerkleCommitments(input) {
|
|
5898
|
+
const current = await input.getPoolMerkleState(input.payload.poolContract);
|
|
5899
|
+
const merged = [...current?.commitments ?? [], ...input.payload.commitments];
|
|
5900
|
+
const nodes = input.payload.nodes ?? await resolveExtendedMerkleNodes({
|
|
5901
|
+
poolContract: input.payload.poolContract,
|
|
5902
|
+
commitments: merged,
|
|
5903
|
+
merkleRootHex: input.payload.merkleRootHex,
|
|
5904
|
+
...current ? { cachedState: poolMerkleStateToCachedView(current) } : {}
|
|
5905
|
+
});
|
|
5906
|
+
await input.appendPoolCommitments({
|
|
5907
|
+
poolContract: input.payload.poolContract,
|
|
5908
|
+
commitments: input.payload.commitments,
|
|
5909
|
+
merkleRootHex: input.payload.merkleRootHex,
|
|
5910
|
+
...input.payload.syncedLedger === void 0 ? {} : { syncedLedger: input.payload.syncedLedger },
|
|
5911
|
+
...nodes ? { nodes } : {}
|
|
5912
|
+
});
|
|
5913
|
+
const written = await input.getPoolMerkleState(input.payload.poolContract);
|
|
5914
|
+
if (written) {
|
|
5915
|
+
await bindPoolMerkleTree(written);
|
|
5916
|
+
}
|
|
5917
|
+
}
|
|
5918
|
+
|
|
5617
5919
|
// src/client/state-delegates/pool.ts
|
|
5618
5920
|
function createPoolStateDelegates(state) {
|
|
5619
5921
|
return {
|
|
5620
5922
|
getPoolMerkleState: (poolContract) => state.getPoolMerkleState(poolContract),
|
|
5621
|
-
setPoolMerkleState: (poolState) =>
|
|
5622
|
-
|
|
5923
|
+
setPoolMerkleState: (poolState) => writePoolMerkleState({
|
|
5924
|
+
setPoolMerkleState: (next) => state.setPoolMerkleState(next),
|
|
5925
|
+
state: poolState
|
|
5926
|
+
}),
|
|
5927
|
+
appendPoolCommitments: (input) => appendPoolMerkleCommitments({
|
|
5928
|
+
getPoolMerkleState: (poolContract) => state.getPoolMerkleState(poolContract),
|
|
5929
|
+
appendPoolCommitments: (payload) => state.appendPoolCommitments(payload),
|
|
5930
|
+
payload: input
|
|
5931
|
+
}),
|
|
5623
5932
|
getLeafEphemeral: (input) => state.getLeafEphemeral(input),
|
|
5624
5933
|
setLeafEphemeral: (ephemeral) => state.setLeafEphemeral(ephemeral)
|
|
5625
5934
|
};
|
|
@@ -5672,12 +5981,42 @@ function createStateDelegates(state) {
|
|
|
5672
5981
|
};
|
|
5673
5982
|
}
|
|
5674
5983
|
|
|
5984
|
+
// src/client/hydrate-state.ts
|
|
5985
|
+
async function hydratePoolMerkleStates(client, states) {
|
|
5986
|
+
for (const poolState of states ?? []) {
|
|
5987
|
+
await client.setPoolMerkleState(poolState);
|
|
5988
|
+
}
|
|
5989
|
+
}
|
|
5990
|
+
async function hydrateWalletAddresses(client, snapshot) {
|
|
5991
|
+
for (const record of snapshot.walletPrivateAddressRecords ?? []) {
|
|
5992
|
+
await client.saveWalletPrivateAddressRecord(record);
|
|
5993
|
+
}
|
|
5994
|
+
for (const scalar of snapshot.walletPrivateAddressScalars ?? []) {
|
|
5995
|
+
await client.saveWalletPrivateAddressScalar(scalar);
|
|
5996
|
+
}
|
|
5997
|
+
for (const entry of snapshot.walletDefaultPrivateAddressNonces ?? []) {
|
|
5998
|
+
await client.setWalletDefaultPrivateAddressNonce(entry);
|
|
5999
|
+
}
|
|
6000
|
+
}
|
|
6001
|
+
async function hydrateStellarPrivacyState(client, snapshot) {
|
|
6002
|
+
if (snapshot.assets && snapshot.assets.length > 0) {
|
|
6003
|
+
await client.replaceAssets(snapshot.assets);
|
|
6004
|
+
}
|
|
6005
|
+
await hydratePoolMerkleStates(client, snapshot.poolMerkleStates);
|
|
6006
|
+
if (snapshot.privateRecords && snapshot.privateRecords.length > 0) {
|
|
6007
|
+
await client.upsertPrivateRecords(snapshot.privateRecords);
|
|
6008
|
+
}
|
|
6009
|
+
await hydrateWalletAddresses(client, snapshot);
|
|
6010
|
+
}
|
|
6011
|
+
|
|
5675
6012
|
// src/client/client.ts
|
|
5676
6013
|
function createStellarPrivacyClientInstance(config) {
|
|
5677
6014
|
const composed = composeStellarPrivacyClient(config);
|
|
6015
|
+
const stateDelegates = createStateDelegates(composed.state);
|
|
5678
6016
|
return {
|
|
5679
6017
|
state: composed.state,
|
|
5680
|
-
...
|
|
6018
|
+
...stateDelegates,
|
|
6019
|
+
hydrateState: (snapshot) => hydrateStellarPrivacyState(stateDelegates, snapshot),
|
|
5681
6020
|
deposit: (intent) => composed.operations.deposit(intent),
|
|
5682
6021
|
transfer: (intent) => composed.operations.transfer(intent),
|
|
5683
6022
|
withdraw: (intent) => composed.operations.withdraw(intent),
|
|
@@ -5998,7 +6337,8 @@ async function buildSpendProofContextAtExecute(input) {
|
|
|
5998
6337
|
input.prepared.intent.asset
|
|
5999
6338
|
);
|
|
6000
6339
|
const coin = requireCoinNoteFromRecord(primaryRecord);
|
|
6001
|
-
const
|
|
6340
|
+
const merkleState = await loadMerkleState(input.environment, walletPublicKey);
|
|
6341
|
+
const commitments = merkleState.commitments;
|
|
6002
6342
|
const leafIndex = findCommitmentLeafIndex(commitments, coin.commitment);
|
|
6003
6343
|
if (leafIndex < 0) {
|
|
6004
6344
|
throw new Error("Coin commitment not found in on-chain Merkle state.");
|
|
@@ -6015,6 +6355,7 @@ async function buildSpendProofContextAtExecute(input) {
|
|
|
6015
6355
|
tokenAddress,
|
|
6016
6356
|
coin,
|
|
6017
6357
|
commitments,
|
|
6358
|
+
merkleState,
|
|
6018
6359
|
ephemeral,
|
|
6019
6360
|
senderPrivKeyScalarHex,
|
|
6020
6361
|
recipientPrivateAddressStpl1: input.recipientPrivateAddressStpl1
|
|
@@ -6516,7 +6857,7 @@ async function buildSingleTransferProofAtExecute(input) {
|
|
|
6516
6857
|
const changeStroops = BigInt(context.coin.value) - input.prepared.intent.amount - (feeOutput?.requiredFee ?? 0n);
|
|
6517
6858
|
const proof = await prepareConfidentialTransferProof({
|
|
6518
6859
|
coin: context.coin,
|
|
6519
|
-
state:
|
|
6860
|
+
state: context.merkleState,
|
|
6520
6861
|
senderPrivKeyScalarHex: context.senderPrivKeyScalarHex,
|
|
6521
6862
|
depositorEphemeralKey: serializeEphemeralKeyString({
|
|
6522
6863
|
xHex: context.ephemeral.xHex,
|
|
@@ -6553,7 +6894,7 @@ async function buildDualTransferProofAtExecute(input) {
|
|
|
6553
6894
|
const proof = await prepareConfidentialTransferProofDual({
|
|
6554
6895
|
coinA: context.coin,
|
|
6555
6896
|
coinB: secondary.coin,
|
|
6556
|
-
state:
|
|
6897
|
+
state: context.merkleState,
|
|
6557
6898
|
senderPrivKeyScalarHex: context.senderPrivKeyScalarHex,
|
|
6558
6899
|
ephemeralAKey: serializeEphemeralKeyString({
|
|
6559
6900
|
xHex: context.ephemeral.xHex,
|
|
@@ -6801,7 +7142,7 @@ async function finalizeSingleWithdrawAtExecute(prepared, environment, poolServic
|
|
|
6801
7142
|
});
|
|
6802
7143
|
const proof = await poolService.prepareWithdrawTransactProof({
|
|
6803
7144
|
coin: context.coin,
|
|
6804
|
-
state:
|
|
7145
|
+
state: context.merkleState,
|
|
6805
7146
|
destinationStellarAddress: prepared.intent.to,
|
|
6806
7147
|
privKeyScalarHex: context.senderPrivKeyScalarHex,
|
|
6807
7148
|
depositorEphemeralKey: serializeEphemeralKeyString({
|
|
@@ -6854,7 +7195,7 @@ async function finalizeDualWithdrawAtExecute(prepared, environment, poolService,
|
|
|
6854
7195
|
const proof = await poolService.prepareWithdrawTransactProofDual({
|
|
6855
7196
|
coinA: context.coin,
|
|
6856
7197
|
coinB: secondary.coin,
|
|
6857
|
-
state:
|
|
7198
|
+
state: context.merkleState,
|
|
6858
7199
|
destinationStellarAddress: prepared.intent.to,
|
|
6859
7200
|
privKeyScalarHex: context.senderPrivKeyScalarHex,
|
|
6860
7201
|
...dualWithdrawEphemeralKeys({ context, secondary }),
|