@arcanetech/privacy-sdk-stellar 0.5.4 → 0.6.1
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 +2 -2
package/dist/node.js
CHANGED
|
@@ -466,6 +466,261 @@ function buildPrivateRecordFromDeposit(input) {
|
|
|
466
466
|
};
|
|
467
467
|
}
|
|
468
468
|
|
|
469
|
+
// src/transact/merkle/lean-imt-api.ts
|
|
470
|
+
function asLeanImtSessionApi(sdk) {
|
|
471
|
+
const candidate = sdk;
|
|
472
|
+
if (typeof candidate.importLeanImtFromState !== "function") {
|
|
473
|
+
return void 0;
|
|
474
|
+
}
|
|
475
|
+
if (typeof candidate.insertTwoLeanImt !== "function") {
|
|
476
|
+
return void 0;
|
|
477
|
+
}
|
|
478
|
+
if (typeof candidate.exportLeanImt !== "function") {
|
|
479
|
+
return void 0;
|
|
480
|
+
}
|
|
481
|
+
if (typeof candidate.dropLeanImt !== "function") {
|
|
482
|
+
return void 0;
|
|
483
|
+
}
|
|
484
|
+
if (typeof candidate.buildWithdrawMerkleWitnessFromHandle !== "function") {
|
|
485
|
+
return void 0;
|
|
486
|
+
}
|
|
487
|
+
return candidate;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// src/transact/merkle/field-decimal.ts
|
|
491
|
+
import { Buffer as Buffer4 } from "buffer";
|
|
492
|
+
var BN254 = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
|
|
493
|
+
var MERKLE_ROOT_BYTE_LENGTH = 32;
|
|
494
|
+
var DECIMAL_STRING_RADIX = 10;
|
|
495
|
+
function merkleRootBufferToFrDecimal(root) {
|
|
496
|
+
if (root.length !== MERKLE_ROOT_BYTE_LENGTH) {
|
|
497
|
+
throw new Error(
|
|
498
|
+
`expected ${MERKLE_ROOT_BYTE_LENGTH}-byte merkle root, got ${root.length}`
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
const hex = Buffer4.from(root).toString("hex");
|
|
502
|
+
return (BigInt(`0x${hex}`) % BN254).toString(DECIMAL_STRING_RADIX);
|
|
503
|
+
}
|
|
504
|
+
var MERKLE_ROOT_HEX_PATTERN = /^[0-9a-fA-F]{64}$/;
|
|
505
|
+
function merkleRootHexToFrDecimal(merkleRootHex) {
|
|
506
|
+
const trimmed = merkleRootHex.trim();
|
|
507
|
+
if (!MERKLE_ROOT_HEX_PATTERN.test(trimmed)) {
|
|
508
|
+
return void 0;
|
|
509
|
+
}
|
|
510
|
+
return merkleRootBufferToFrDecimal(Buffer4.from(trimmed, "hex"));
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// src/transact/merkle/state-file.ts
|
|
514
|
+
function merkleSnapshotToStateFile(input) {
|
|
515
|
+
const root = merkleRootHexToFrDecimal(input.merkleRootHex);
|
|
516
|
+
const nodes = input.nodes;
|
|
517
|
+
if (!nodes || nodes.length === 0 || root === void 0) {
|
|
518
|
+
return { commitments: input.commitments };
|
|
519
|
+
}
|
|
520
|
+
return {
|
|
521
|
+
commitments: input.commitments,
|
|
522
|
+
nodes,
|
|
523
|
+
root
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// src/transact/merkle/extend-snapshot.ts
|
|
528
|
+
function isEvenLeafCount(count) {
|
|
529
|
+
return count % 2 === 0;
|
|
530
|
+
}
|
|
531
|
+
function importHandle(sdk, state) {
|
|
532
|
+
try {
|
|
533
|
+
return sdk.importLeanImtFromState(state);
|
|
534
|
+
} catch {
|
|
535
|
+
return void 0;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
function insertNewPairs(input) {
|
|
539
|
+
for (let index = input.prefixLength; index < input.commitments.length; index += 2) {
|
|
540
|
+
const leafA = input.commitments.at(index);
|
|
541
|
+
const leafB = input.commitments.at(index + 1);
|
|
542
|
+
if (leafA === void 0 || leafB === void 0) {
|
|
543
|
+
return false;
|
|
544
|
+
}
|
|
545
|
+
try {
|
|
546
|
+
input.sdk.insertTwoLeanImt(input.handle, leafA, leafB);
|
|
547
|
+
} catch {
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
return true;
|
|
552
|
+
}
|
|
553
|
+
function snapshotNodes(sdk, handle) {
|
|
554
|
+
try {
|
|
555
|
+
return sdk.exportLeanImt(handle).nodes;
|
|
556
|
+
} catch {
|
|
557
|
+
return void 0;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
function prefixSnapshotState(input) {
|
|
561
|
+
const prefixLength = input.cachedState?.nodes ? input.cachedState.commitments.length : 0;
|
|
562
|
+
return merkleSnapshotToStateFile({
|
|
563
|
+
commitments: input.commitments.slice(0, prefixLength),
|
|
564
|
+
merkleRootHex: input.cachedState?.merkleRootHex ?? input.merkleRootHex,
|
|
565
|
+
...input.cachedState?.nodes ? { nodes: input.cachedState.nodes } : {}
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
function importSnapshotState(input) {
|
|
569
|
+
if (input.prefixState.nodes && input.prefixState.commitments.length > 0) {
|
|
570
|
+
return input.prefixState;
|
|
571
|
+
}
|
|
572
|
+
return merkleSnapshotToStateFile({
|
|
573
|
+
commitments: input.commitments,
|
|
574
|
+
merkleRootHex: input.merkleRootHex
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
function exportExtendedNodes(input) {
|
|
578
|
+
const inserted = input.prefixState.nodes ? insertNewPairs({
|
|
579
|
+
sdk: input.sdk,
|
|
580
|
+
handle: input.handle,
|
|
581
|
+
prefixLength: input.prefixState.commitments.length,
|
|
582
|
+
commitments: input.commitments
|
|
583
|
+
}) : true;
|
|
584
|
+
if (!inserted) {
|
|
585
|
+
input.sdk.dropLeanImt(input.handle);
|
|
586
|
+
return void 0;
|
|
587
|
+
}
|
|
588
|
+
const nodes = snapshotNodes(input.sdk, input.handle);
|
|
589
|
+
if (!nodes) {
|
|
590
|
+
input.sdk.dropLeanImt(input.handle);
|
|
591
|
+
}
|
|
592
|
+
return nodes;
|
|
593
|
+
}
|
|
594
|
+
function extendMerkleSnapshotNodes(input) {
|
|
595
|
+
if (!isEvenLeafCount(input.commitments.length)) {
|
|
596
|
+
return {};
|
|
597
|
+
}
|
|
598
|
+
const prefixState = prefixSnapshotState(input);
|
|
599
|
+
const handle = importHandle(
|
|
600
|
+
input.sdk,
|
|
601
|
+
importSnapshotState({ ...input, prefixState })
|
|
602
|
+
);
|
|
603
|
+
if (handle === void 0) {
|
|
604
|
+
return {};
|
|
605
|
+
}
|
|
606
|
+
const nodes = exportExtendedNodes({
|
|
607
|
+
sdk: input.sdk,
|
|
608
|
+
handle,
|
|
609
|
+
prefixState,
|
|
610
|
+
commitments: input.commitments
|
|
611
|
+
});
|
|
612
|
+
if (!nodes) {
|
|
613
|
+
return {};
|
|
614
|
+
}
|
|
615
|
+
return { nodes, handle };
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// src/transact/merkle/tree-session.ts
|
|
619
|
+
var merkleSdkHost;
|
|
620
|
+
function registerMerkleSessionSdkHost(host) {
|
|
621
|
+
merkleSdkHost = host;
|
|
622
|
+
}
|
|
623
|
+
async function loadSessionSdk() {
|
|
624
|
+
const host = merkleSdkHost;
|
|
625
|
+
if (typeof host?.getInitializedSdk !== "function") {
|
|
626
|
+
return void 0;
|
|
627
|
+
}
|
|
628
|
+
try {
|
|
629
|
+
return asLeanImtSessionApi(await host.getInitializedSdk());
|
|
630
|
+
} catch {
|
|
631
|
+
return void 0;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
var sessionsByPool = /* @__PURE__ */ new Map();
|
|
635
|
+
var handlesByKey = /* @__PURE__ */ new Map();
|
|
636
|
+
function merkleSessionKey(state) {
|
|
637
|
+
const root = state.root?.trim();
|
|
638
|
+
if (root) {
|
|
639
|
+
return `${state.commitments.length}:${root}`;
|
|
640
|
+
}
|
|
641
|
+
const first = state.commitments[0] ?? "";
|
|
642
|
+
const last = state.commitments.at(-1) ?? "";
|
|
643
|
+
return `${state.commitments.length}:${first}:${last}`;
|
|
644
|
+
}
|
|
645
|
+
function rememberHandle(poolContract, key, handle) {
|
|
646
|
+
const existing = sessionsByPool.get(poolContract);
|
|
647
|
+
if (existing && existing.handle !== handle) {
|
|
648
|
+
handlesByKey.delete(existing.key);
|
|
649
|
+
}
|
|
650
|
+
sessionsByPool.set(poolContract, { handle, key });
|
|
651
|
+
handlesByKey.set(key, handle);
|
|
652
|
+
}
|
|
653
|
+
function importHandle2(sdk, state) {
|
|
654
|
+
try {
|
|
655
|
+
return sdk.importLeanImtFromState(state);
|
|
656
|
+
} catch {
|
|
657
|
+
return void 0;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
function merkleTreeHandleForState(state) {
|
|
661
|
+
return handlesByKey.get(merkleSessionKey(state));
|
|
662
|
+
}
|
|
663
|
+
function bindImportedMerkleTree(input) {
|
|
664
|
+
rememberHandle(input.poolContract, merkleSessionKey(input.state), input.handle);
|
|
665
|
+
}
|
|
666
|
+
async function bindPoolMerkleTree(state) {
|
|
667
|
+
const sdk = await loadSessionSdk();
|
|
668
|
+
if (!sdk) {
|
|
669
|
+
return void 0;
|
|
670
|
+
}
|
|
671
|
+
const snapshot = merkleSnapshotToStateFile(state);
|
|
672
|
+
const key = merkleSessionKey(snapshot);
|
|
673
|
+
const existing = sessionsByPool.get(state.poolContract);
|
|
674
|
+
if (existing?.key === key) {
|
|
675
|
+
return existing.handle;
|
|
676
|
+
}
|
|
677
|
+
const handle = importHandle2(sdk, snapshot);
|
|
678
|
+
if (handle === void 0) {
|
|
679
|
+
return void 0;
|
|
680
|
+
}
|
|
681
|
+
if (existing) {
|
|
682
|
+
sdk.dropLeanImt(existing.handle);
|
|
683
|
+
}
|
|
684
|
+
rememberHandle(state.poolContract, key, handle);
|
|
685
|
+
return handle;
|
|
686
|
+
}
|
|
687
|
+
async function resolveExtendedMerkleNodes(input) {
|
|
688
|
+
const cached = input.cachedState;
|
|
689
|
+
if (cached && cached.commitments.length === input.commitments.length && cached.merkleRootHex === input.merkleRootHex) {
|
|
690
|
+
return cached.nodes;
|
|
691
|
+
}
|
|
692
|
+
const sdk = await loadSessionSdk();
|
|
693
|
+
if (!sdk) {
|
|
694
|
+
return void 0;
|
|
695
|
+
}
|
|
696
|
+
const extended = extendMerkleSnapshotNodes({
|
|
697
|
+
sdk,
|
|
698
|
+
commitments: input.commitments,
|
|
699
|
+
merkleRootHex: input.merkleRootHex,
|
|
700
|
+
...cached ? { cachedState: cached } : {}
|
|
701
|
+
});
|
|
702
|
+
if (extended.handle !== void 0) {
|
|
703
|
+
bindImportedMerkleTree({
|
|
704
|
+
poolContract: input.poolContract,
|
|
705
|
+
handle: extended.handle,
|
|
706
|
+
state: merkleSnapshotToStateFile({
|
|
707
|
+
commitments: input.commitments,
|
|
708
|
+
merkleRootHex: input.merkleRootHex,
|
|
709
|
+
...extended.nodes ? { nodes: extended.nodes } : {}
|
|
710
|
+
})
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
return extended.nodes;
|
|
714
|
+
}
|
|
715
|
+
function withdrawMerkleWitnessFromTree(input) {
|
|
716
|
+
const session = asLeanImtSessionApi(input.sdk);
|
|
717
|
+
const handle = merkleTreeHandleForState(input.state);
|
|
718
|
+
if (session && handle !== void 0) {
|
|
719
|
+
return session.buildWithdrawMerkleWitnessFromHandle(input.coin, handle);
|
|
720
|
+
}
|
|
721
|
+
return input.sdk.buildWithdrawMerkleWitness(input.coin, input.state);
|
|
722
|
+
}
|
|
723
|
+
|
|
469
724
|
// src/transact/pool/service.ts
|
|
470
725
|
import {
|
|
471
726
|
decodeDecodedEphemeralKey
|
|
@@ -519,18 +774,18 @@ function privateAddressSdk(sdk) {
|
|
|
519
774
|
import { withdrawObjectFromMerkleWitness as withdrawObjectFromMerkleWitness2 } from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
520
775
|
|
|
521
776
|
// src/transact/proofs/transaction-input.ts
|
|
522
|
-
import { Buffer as
|
|
777
|
+
import { Buffer as Buffer6 } from "buffer";
|
|
523
778
|
import { StrKey as StrKey2 } from "@stellar/stellar-sdk";
|
|
524
779
|
|
|
525
780
|
// src/transact/stellar/token-contract.ts
|
|
526
|
-
import { Buffer as
|
|
781
|
+
import { Buffer as Buffer5 } from "buffer";
|
|
527
782
|
import { StrKey } from "@stellar/stellar-sdk";
|
|
528
783
|
var CONTRACT_ID_BYTE_LENGTH = 32;
|
|
529
784
|
var HEX_CHARS_PER_BYTE = 2;
|
|
530
785
|
var CONTRACT_ID_HEX_CHAR_LENGTH = CONTRACT_ID_BYTE_LENGTH * HEX_CHARS_PER_BYTE;
|
|
531
786
|
var CONTRACT_ID_HEX = /^(?:0x)?([0-9a-f]{64})$/i;
|
|
532
787
|
function encodeContractFromHex(hexPayload) {
|
|
533
|
-
return StrKey.encodeContract(
|
|
788
|
+
return StrKey.encodeContract(Buffer5.from(hexPayload, "hex"));
|
|
534
789
|
}
|
|
535
790
|
function normalizeSorobanContractId(raw) {
|
|
536
791
|
const trimmed = raw.trim();
|
|
@@ -563,7 +818,7 @@ var ZERO_PUBLIC_WITHDRAW_ADDRESS = {
|
|
|
563
818
|
var CONTRACT_ADDRESS_HALF_BYTES = 16;
|
|
564
819
|
var CONTRACT_ADDRESS_BYTES = 32;
|
|
565
820
|
function bytes16ToDecimal(bytes) {
|
|
566
|
-
return BigInt(`0x${
|
|
821
|
+
return BigInt(`0x${Buffer6.from(bytes).toString("hex")}`).toString();
|
|
567
822
|
}
|
|
568
823
|
function tokenAddressFrParts(tokenAddress) {
|
|
569
824
|
const normalized = resolveTokenContractId(tokenAddress);
|
|
@@ -682,7 +937,7 @@ var MIN_CONFIDENTIAL_TRANSFER_STROOPS = 1n;
|
|
|
682
937
|
var ZERO_STROOPS = 0n;
|
|
683
938
|
function withdrawWitnessForCoin(parameters) {
|
|
684
939
|
const { sdk, coin, state } = parameters;
|
|
685
|
-
const witness = sdk
|
|
940
|
+
const witness = withdrawMerkleWitnessFromTree({ sdk, coin, state });
|
|
686
941
|
const withdrawApplicationId = coin.application_id ?? parameters.applicationId;
|
|
687
942
|
const withdrawObject = withdrawObjectFromMerkleWitness(
|
|
688
943
|
witness,
|
|
@@ -869,7 +1124,7 @@ import {
|
|
|
869
1124
|
DEMO_AUDIT_PUBLIC_KEY,
|
|
870
1125
|
resolveTransactionAuditParams
|
|
871
1126
|
} from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
872
|
-
import { Buffer as
|
|
1127
|
+
import { Buffer as Buffer7 } from "buffer";
|
|
873
1128
|
var UNCOMPRESSED_PREFIX = "04";
|
|
874
1129
|
var UNCOMPRESSED_HEX_LENGTH = 130;
|
|
875
1130
|
var XY_HEX_LENGTH = 128;
|
|
@@ -896,7 +1151,7 @@ function parseAuditPublicKeyFromEnvHex(raw) {
|
|
|
896
1151
|
"Audit public key must be uncompressed 65-byte hex (04 + X + Y) or 64-byte X+Y hex"
|
|
897
1152
|
);
|
|
898
1153
|
}
|
|
899
|
-
const bytes =
|
|
1154
|
+
const bytes = Buffer7.from(payload, "hex");
|
|
900
1155
|
const auditPublicKeyXDecimal = BigInt(
|
|
901
1156
|
`0x${bytes.subarray(0, X_OFFSET_END).toString("hex")}`
|
|
902
1157
|
).toString(DECIMAL_RADIX);
|
|
@@ -939,13 +1194,13 @@ import { ed25519PubkeyPayloadHexToWithdrawFrDecimals } from "@arcanetech/stellar
|
|
|
939
1194
|
|
|
940
1195
|
// src/transact/stellar/account.ts
|
|
941
1196
|
import { StrKey as StrKey3 } from "@stellar/stellar-sdk";
|
|
942
|
-
import { Buffer as
|
|
1197
|
+
import { Buffer as Buffer8 } from "buffer";
|
|
943
1198
|
var MUXED_ACCOUNT_ID_BYTE_LENGTH = 8;
|
|
944
1199
|
var ED25519_PUBLIC_KEY_BYTE_LENGTH = 32;
|
|
945
1200
|
function ed25519HexFromGAddress(trimmed) {
|
|
946
1201
|
try {
|
|
947
1202
|
const raw = StrKey3.decodeEd25519PublicKey(trimmed);
|
|
948
|
-
return
|
|
1203
|
+
return Buffer8.from(raw).toString("hex");
|
|
949
1204
|
} catch {
|
|
950
1205
|
return void 0;
|
|
951
1206
|
}
|
|
@@ -1232,10 +1487,11 @@ async function proveSingleWithdrawTransaction(parameters) {
|
|
|
1232
1487
|
);
|
|
1233
1488
|
}
|
|
1234
1489
|
function buildPrimaryWithdrawForCoin(parameters) {
|
|
1235
|
-
const witness =
|
|
1236
|
-
parameters.
|
|
1237
|
-
parameters.
|
|
1238
|
-
|
|
1490
|
+
const witness = withdrawMerkleWitnessFromTree({
|
|
1491
|
+
sdk: parameters.sdk,
|
|
1492
|
+
coin: parameters.coin,
|
|
1493
|
+
state: parameters.state
|
|
1494
|
+
});
|
|
1239
1495
|
const privKeyScalar = privKeyScalarDecimalFromRecipientScalarHex(
|
|
1240
1496
|
parameters.privKeyScalarHex
|
|
1241
1497
|
);
|
|
@@ -1654,23 +1910,6 @@ import {
|
|
|
1654
1910
|
randomFrDecimal253,
|
|
1655
1911
|
scalarHexToFrDecimal as scalarHexToFrDecimal2
|
|
1656
1912
|
} from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
1657
|
-
|
|
1658
|
-
// src/transact/merkle/field-decimal.ts
|
|
1659
|
-
import { Buffer as Buffer8 } from "buffer";
|
|
1660
|
-
var BN254 = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
|
|
1661
|
-
var MERKLE_ROOT_BYTE_LENGTH = 32;
|
|
1662
|
-
var DECIMAL_STRING_RADIX = 10;
|
|
1663
|
-
function merkleRootBufferToFrDecimal(root) {
|
|
1664
|
-
if (root.length !== MERKLE_ROOT_BYTE_LENGTH) {
|
|
1665
|
-
throw new Error(
|
|
1666
|
-
`expected ${MERKLE_ROOT_BYTE_LENGTH}-byte merkle root, got ${root.length}`
|
|
1667
|
-
);
|
|
1668
|
-
}
|
|
1669
|
-
const hex = Buffer8.from(root).toString("hex");
|
|
1670
|
-
return (BigInt(`0x${hex}`) % BN254).toString(DECIMAL_STRING_RADIX);
|
|
1671
|
-
}
|
|
1672
|
-
|
|
1673
|
-
// src/transact/pool/prepare-deposit-proof.ts
|
|
1674
1913
|
function userDepositSlot(input) {
|
|
1675
1914
|
return {
|
|
1676
1915
|
value: input.coin.value,
|
|
@@ -1902,6 +2141,7 @@ function createPrivacyPoolService(input) {
|
|
|
1902
2141
|
var configuredPrivacyPoolService;
|
|
1903
2142
|
function configurePrivacyPoolService(service) {
|
|
1904
2143
|
configuredPrivacyPoolService = service;
|
|
2144
|
+
registerMerkleSessionSdkHost(service);
|
|
1905
2145
|
}
|
|
1906
2146
|
function getPrivacyPoolService() {
|
|
1907
2147
|
if (!configuredPrivacyPoolService) {
|
|
@@ -1920,7 +2160,8 @@ function poolMerkleStateToCachedView(state) {
|
|
|
1920
2160
|
return {
|
|
1921
2161
|
commitments: state.commitments,
|
|
1922
2162
|
updatedAt: state.updatedAt,
|
|
1923
|
-
merkleRootHex: state.merkleRootHex
|
|
2163
|
+
merkleRootHex: state.merkleRootHex,
|
|
2164
|
+
...state.nodes ? { nodes: state.nodes } : {}
|
|
1924
2165
|
};
|
|
1925
2166
|
}
|
|
1926
2167
|
|
|
@@ -2053,6 +2294,65 @@ function reuseCachedCommitments(input) {
|
|
|
2053
2294
|
return cachedCommitments;
|
|
2054
2295
|
}
|
|
2055
2296
|
|
|
2297
|
+
// src/transact/merkle/persist-fetched.ts
|
|
2298
|
+
function cachedMerkleUnchanged(cachedState, commitments, merkleRootHex) {
|
|
2299
|
+
if (!cachedState) {
|
|
2300
|
+
return false;
|
|
2301
|
+
}
|
|
2302
|
+
if (cachedState.commitments.length !== commitments.length) {
|
|
2303
|
+
return false;
|
|
2304
|
+
}
|
|
2305
|
+
return cachedState.merkleRootHex === merkleRootHex;
|
|
2306
|
+
}
|
|
2307
|
+
function viewFromCachedMerkle(cachedState, merkleRootHex) {
|
|
2308
|
+
return {
|
|
2309
|
+
commitments: cachedState.commitments,
|
|
2310
|
+
updatedAt: cachedState.updatedAt,
|
|
2311
|
+
merkleRootHex: cachedState.merkleRootHex ?? merkleRootHex,
|
|
2312
|
+
commitmentCount: cachedState.commitments.length,
|
|
2313
|
+
...cachedState.nodes ? { nodes: cachedState.nodes } : {}
|
|
2314
|
+
};
|
|
2315
|
+
}
|
|
2316
|
+
function merkleStateForPersist(input) {
|
|
2317
|
+
return {
|
|
2318
|
+
poolContract: input.poolContractId,
|
|
2319
|
+
commitments: input.commitments,
|
|
2320
|
+
commitmentCount: input.commitments.length,
|
|
2321
|
+
merkleRootHex: input.merkleRootHex,
|
|
2322
|
+
updatedAt: input.updatedAt,
|
|
2323
|
+
...input.nodes ? { nodes: input.nodes } : {}
|
|
2324
|
+
};
|
|
2325
|
+
}
|
|
2326
|
+
async function persistFetchedMerkleState(input) {
|
|
2327
|
+
const cachedState = input.cachedState;
|
|
2328
|
+
if (cachedMerkleUnchanged(cachedState, input.commitments, input.merkleRootHex) && cachedState) {
|
|
2329
|
+
return viewFromCachedMerkle(cachedState, input.merkleRootHex);
|
|
2330
|
+
}
|
|
2331
|
+
const nodes = await resolveExtendedMerkleNodes({
|
|
2332
|
+
poolContract: input.poolContractId,
|
|
2333
|
+
commitments: input.commitments,
|
|
2334
|
+
merkleRootHex: input.merkleRootHex,
|
|
2335
|
+
...cachedState ? { cachedState } : {}
|
|
2336
|
+
});
|
|
2337
|
+
const updatedAt = Date.now();
|
|
2338
|
+
await input.poolMerkleState?.set(
|
|
2339
|
+
merkleStateForPersist({
|
|
2340
|
+
poolContractId: input.poolContractId,
|
|
2341
|
+
commitments: input.commitments,
|
|
2342
|
+
merkleRootHex: input.merkleRootHex,
|
|
2343
|
+
updatedAt,
|
|
2344
|
+
...nodes ? { nodes } : {}
|
|
2345
|
+
})
|
|
2346
|
+
);
|
|
2347
|
+
return {
|
|
2348
|
+
commitments: input.commitments,
|
|
2349
|
+
updatedAt,
|
|
2350
|
+
merkleRootHex: input.merkleRootHex,
|
|
2351
|
+
commitmentCount: input.commitments.length,
|
|
2352
|
+
...nodes ? { nodes } : {}
|
|
2353
|
+
};
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2056
2356
|
// src/transact/merkle/fetch-contract.ts
|
|
2057
2357
|
async function fetchAndMergeMerkleState(parameters) {
|
|
2058
2358
|
const client = createPoolClient(parameters);
|
|
@@ -2145,43 +2445,6 @@ async function loadCommitments(input) {
|
|
|
2145
2445
|
});
|
|
2146
2446
|
return [...reused, ...fetched];
|
|
2147
2447
|
}
|
|
2148
|
-
async function persistFetchedMerkleState(input) {
|
|
2149
|
-
const cachedState = input.cachedState;
|
|
2150
|
-
if (cachedState && cachedMerkleUnchanged(cachedState, input.commitments, input.merkleRootHex)) {
|
|
2151
|
-
return viewFromCachedMerkle(cachedState, input.merkleRootHex);
|
|
2152
|
-
}
|
|
2153
|
-
const updatedAt = Date.now();
|
|
2154
|
-
await input.poolMerkleState?.set({
|
|
2155
|
-
poolContract: input.poolContractId,
|
|
2156
|
-
commitments: input.commitments,
|
|
2157
|
-
commitmentCount: input.commitments.length,
|
|
2158
|
-
merkleRootHex: input.merkleRootHex,
|
|
2159
|
-
updatedAt
|
|
2160
|
-
});
|
|
2161
|
-
return {
|
|
2162
|
-
commitments: input.commitments,
|
|
2163
|
-
updatedAt,
|
|
2164
|
-
merkleRootHex: input.merkleRootHex,
|
|
2165
|
-
commitmentCount: input.commitments.length
|
|
2166
|
-
};
|
|
2167
|
-
}
|
|
2168
|
-
function viewFromCachedMerkle(cachedState, merkleRootHex) {
|
|
2169
|
-
return {
|
|
2170
|
-
commitments: cachedState.commitments,
|
|
2171
|
-
updatedAt: cachedState.updatedAt,
|
|
2172
|
-
merkleRootHex: cachedState.merkleRootHex ?? merkleRootHex,
|
|
2173
|
-
commitmentCount: cachedState.commitments.length
|
|
2174
|
-
};
|
|
2175
|
-
}
|
|
2176
|
-
function cachedMerkleUnchanged(cachedState, commitments, merkleRootHex) {
|
|
2177
|
-
if (!cachedState) {
|
|
2178
|
-
return false;
|
|
2179
|
-
}
|
|
2180
|
-
if ((cachedState.merkleRootHex ?? merkleRootHex) !== merkleRootHex) {
|
|
2181
|
-
return false;
|
|
2182
|
-
}
|
|
2183
|
-
return cachedState.commitments.join(",") === commitments.join(",");
|
|
2184
|
-
}
|
|
2185
2448
|
|
|
2186
2449
|
// src/transact/engine/prepare/shared.ts
|
|
2187
2450
|
async function resolveTokenContractId2(environment, assetId) {
|
|
@@ -2256,7 +2519,11 @@ async function loadMerkleState(environment, walletPublicKey) {
|
|
|
2256
2519
|
transactEnvironment: environment,
|
|
2257
2520
|
...environment.poolMerkleState ? { poolMerkleState: environment.poolMerkleState } : {}
|
|
2258
2521
|
});
|
|
2259
|
-
return {
|
|
2522
|
+
return merkleSnapshotToStateFile({
|
|
2523
|
+
commitments: merged.commitments,
|
|
2524
|
+
merkleRootHex: merged.merkleRootHex,
|
|
2525
|
+
...merged.nodes ? { nodes: merged.nodes } : {}
|
|
2526
|
+
});
|
|
2260
2527
|
}
|
|
2261
2528
|
function enrichPreparedOperation(prepared, outputRecords, artifacts) {
|
|
2262
2529
|
return {
|
|
@@ -2765,13 +3032,19 @@ var walletPrivateAddressRecordSchema = z.object({
|
|
|
2765
3032
|
privateAddress: z.string().min(1),
|
|
2766
3033
|
createdAt: z.number()
|
|
2767
3034
|
});
|
|
3035
|
+
var leanImtNodeSchema = z.object({
|
|
3036
|
+
level: z.number().int().nonnegative(),
|
|
3037
|
+
index: z.number().int().nonnegative(),
|
|
3038
|
+
value: z.string().min(1)
|
|
3039
|
+
});
|
|
2768
3040
|
var poolMerkleStateSchema = z.object({
|
|
2769
3041
|
poolContract: z.string().min(1),
|
|
2770
3042
|
commitments: z.array(z.string()),
|
|
2771
3043
|
commitmentCount: z.number().int().nonnegative(),
|
|
2772
3044
|
merkleRootHex: z.string().min(1),
|
|
2773
3045
|
updatedAt: z.number(),
|
|
2774
|
-
syncedLedger: z.number().int().optional()
|
|
3046
|
+
syncedLedger: z.number().int().optional(),
|
|
3047
|
+
nodes: z.array(leanImtNodeSchema).optional()
|
|
2775
3048
|
});
|
|
2776
3049
|
var leafEphemeralSchema = z.object({
|
|
2777
3050
|
poolContract: z.string().min(1),
|
|
@@ -4184,6 +4457,7 @@ function createPoolMerkleService(context) {
|
|
|
4184
4457
|
async appendPoolCommitments(input) {
|
|
4185
4458
|
const current = await this.getPoolMerkleState(input.poolContract);
|
|
4186
4459
|
const mergedCommitments = [...current?.commitments ?? [], ...input.commitments];
|
|
4460
|
+
const nodes = input.nodes ?? (input.commitments.length === 0 ? current?.nodes : void 0);
|
|
4187
4461
|
await this.setPoolMerkleState(
|
|
4188
4462
|
withoutUndefinedFields({
|
|
4189
4463
|
poolContract: input.poolContract,
|
|
@@ -4191,7 +4465,8 @@ function createPoolMerkleService(context) {
|
|
|
4191
4465
|
commitmentCount: mergedCommitments.length,
|
|
4192
4466
|
merkleRootHex: input.merkleRootHex,
|
|
4193
4467
|
updatedAt: Date.now(),
|
|
4194
|
-
syncedLedger: input.syncedLedger ?? current?.syncedLedger
|
|
4468
|
+
syncedLedger: input.syncedLedger ?? current?.syncedLedger,
|
|
4469
|
+
nodes
|
|
4195
4470
|
})
|
|
4196
4471
|
);
|
|
4197
4472
|
}
|
|
@@ -5461,12 +5736,46 @@ function createDeliveriesStateDelegates(state) {
|
|
|
5461
5736
|
};
|
|
5462
5737
|
}
|
|
5463
5738
|
|
|
5739
|
+
// src/transact/merkle/write-snapshot.ts
|
|
5740
|
+
async function writePoolMerkleState(input) {
|
|
5741
|
+
await input.setPoolMerkleState(input.state);
|
|
5742
|
+
await bindPoolMerkleTree(input.state);
|
|
5743
|
+
}
|
|
5744
|
+
async function appendPoolMerkleCommitments(input) {
|
|
5745
|
+
const current = await input.getPoolMerkleState(input.payload.poolContract);
|
|
5746
|
+
const merged = [...current?.commitments ?? [], ...input.payload.commitments];
|
|
5747
|
+
const nodes = input.payload.nodes ?? await resolveExtendedMerkleNodes({
|
|
5748
|
+
poolContract: input.payload.poolContract,
|
|
5749
|
+
commitments: merged,
|
|
5750
|
+
merkleRootHex: input.payload.merkleRootHex,
|
|
5751
|
+
...current ? { cachedState: poolMerkleStateToCachedView(current) } : {}
|
|
5752
|
+
});
|
|
5753
|
+
await input.appendPoolCommitments({
|
|
5754
|
+
poolContract: input.payload.poolContract,
|
|
5755
|
+
commitments: input.payload.commitments,
|
|
5756
|
+
merkleRootHex: input.payload.merkleRootHex,
|
|
5757
|
+
...input.payload.syncedLedger === void 0 ? {} : { syncedLedger: input.payload.syncedLedger },
|
|
5758
|
+
...nodes ? { nodes } : {}
|
|
5759
|
+
});
|
|
5760
|
+
const written = await input.getPoolMerkleState(input.payload.poolContract);
|
|
5761
|
+
if (written) {
|
|
5762
|
+
await bindPoolMerkleTree(written);
|
|
5763
|
+
}
|
|
5764
|
+
}
|
|
5765
|
+
|
|
5464
5766
|
// src/client/state-delegates/pool.ts
|
|
5465
5767
|
function createPoolStateDelegates(state) {
|
|
5466
5768
|
return {
|
|
5467
5769
|
getPoolMerkleState: (poolContract) => state.getPoolMerkleState(poolContract),
|
|
5468
|
-
setPoolMerkleState: (poolState) =>
|
|
5469
|
-
|
|
5770
|
+
setPoolMerkleState: (poolState) => writePoolMerkleState({
|
|
5771
|
+
setPoolMerkleState: (next) => state.setPoolMerkleState(next),
|
|
5772
|
+
state: poolState
|
|
5773
|
+
}),
|
|
5774
|
+
appendPoolCommitments: (input) => appendPoolMerkleCommitments({
|
|
5775
|
+
getPoolMerkleState: (poolContract) => state.getPoolMerkleState(poolContract),
|
|
5776
|
+
appendPoolCommitments: (payload) => state.appendPoolCommitments(payload),
|
|
5777
|
+
payload: input
|
|
5778
|
+
}),
|
|
5470
5779
|
getLeafEphemeral: (input) => state.getLeafEphemeral(input),
|
|
5471
5780
|
setLeafEphemeral: (ephemeral) => state.setLeafEphemeral(ephemeral)
|
|
5472
5781
|
};
|
|
@@ -5519,12 +5828,42 @@ function createStateDelegates(state) {
|
|
|
5519
5828
|
};
|
|
5520
5829
|
}
|
|
5521
5830
|
|
|
5831
|
+
// src/client/hydrate-state.ts
|
|
5832
|
+
async function hydratePoolMerkleStates(client, states) {
|
|
5833
|
+
for (const poolState of states ?? []) {
|
|
5834
|
+
await client.setPoolMerkleState(poolState);
|
|
5835
|
+
}
|
|
5836
|
+
}
|
|
5837
|
+
async function hydrateWalletAddresses(client, snapshot) {
|
|
5838
|
+
for (const record of snapshot.walletPrivateAddressRecords ?? []) {
|
|
5839
|
+
await client.saveWalletPrivateAddressRecord(record);
|
|
5840
|
+
}
|
|
5841
|
+
for (const scalar of snapshot.walletPrivateAddressScalars ?? []) {
|
|
5842
|
+
await client.saveWalletPrivateAddressScalar(scalar);
|
|
5843
|
+
}
|
|
5844
|
+
for (const entry of snapshot.walletDefaultPrivateAddressNonces ?? []) {
|
|
5845
|
+
await client.setWalletDefaultPrivateAddressNonce(entry);
|
|
5846
|
+
}
|
|
5847
|
+
}
|
|
5848
|
+
async function hydrateStellarPrivacyState(client, snapshot) {
|
|
5849
|
+
if (snapshot.assets && snapshot.assets.length > 0) {
|
|
5850
|
+
await client.replaceAssets(snapshot.assets);
|
|
5851
|
+
}
|
|
5852
|
+
await hydratePoolMerkleStates(client, snapshot.poolMerkleStates);
|
|
5853
|
+
if (snapshot.privateRecords && snapshot.privateRecords.length > 0) {
|
|
5854
|
+
await client.upsertPrivateRecords(snapshot.privateRecords);
|
|
5855
|
+
}
|
|
5856
|
+
await hydrateWalletAddresses(client, snapshot);
|
|
5857
|
+
}
|
|
5858
|
+
|
|
5522
5859
|
// src/client/client.ts
|
|
5523
5860
|
function createStellarPrivacyClientInstance(config) {
|
|
5524
5861
|
const composed = composeStellarPrivacyClient(config);
|
|
5862
|
+
const stateDelegates = createStateDelegates(composed.state);
|
|
5525
5863
|
return {
|
|
5526
5864
|
state: composed.state,
|
|
5527
|
-
...
|
|
5865
|
+
...stateDelegates,
|
|
5866
|
+
hydrateState: (snapshot) => hydrateStellarPrivacyState(stateDelegates, snapshot),
|
|
5528
5867
|
deposit: (intent) => composed.operations.deposit(intent),
|
|
5529
5868
|
transfer: (intent) => composed.operations.transfer(intent),
|
|
5530
5869
|
withdraw: (intent) => composed.operations.withdraw(intent),
|
|
@@ -5845,7 +6184,8 @@ async function buildSpendProofContextAtExecute(input) {
|
|
|
5845
6184
|
input.prepared.intent.asset
|
|
5846
6185
|
);
|
|
5847
6186
|
const coin = requireCoinNoteFromRecord(primaryRecord);
|
|
5848
|
-
const
|
|
6187
|
+
const merkleState = await loadMerkleState(input.environment, walletPublicKey);
|
|
6188
|
+
const commitments = merkleState.commitments;
|
|
5849
6189
|
const leafIndex = findCommitmentLeafIndex(commitments, coin.commitment);
|
|
5850
6190
|
if (leafIndex < 0) {
|
|
5851
6191
|
throw new Error("Coin commitment not found in on-chain Merkle state.");
|
|
@@ -5862,6 +6202,7 @@ async function buildSpendProofContextAtExecute(input) {
|
|
|
5862
6202
|
tokenAddress,
|
|
5863
6203
|
coin,
|
|
5864
6204
|
commitments,
|
|
6205
|
+
merkleState,
|
|
5865
6206
|
ephemeral,
|
|
5866
6207
|
senderPrivKeyScalarHex,
|
|
5867
6208
|
recipientPrivateAddressStpl1: input.recipientPrivateAddressStpl1
|
|
@@ -6363,7 +6704,7 @@ async function buildSingleTransferProofAtExecute(input) {
|
|
|
6363
6704
|
const changeStroops = BigInt(context.coin.value) - input.prepared.intent.amount - (feeOutput?.requiredFee ?? 0n);
|
|
6364
6705
|
const proof = await prepareConfidentialTransferProof({
|
|
6365
6706
|
coin: context.coin,
|
|
6366
|
-
state:
|
|
6707
|
+
state: context.merkleState,
|
|
6367
6708
|
senderPrivKeyScalarHex: context.senderPrivKeyScalarHex,
|
|
6368
6709
|
depositorEphemeralKey: serializeEphemeralKeyString({
|
|
6369
6710
|
xHex: context.ephemeral.xHex,
|
|
@@ -6400,7 +6741,7 @@ async function buildDualTransferProofAtExecute(input) {
|
|
|
6400
6741
|
const proof = await prepareConfidentialTransferProofDual({
|
|
6401
6742
|
coinA: context.coin,
|
|
6402
6743
|
coinB: secondary.coin,
|
|
6403
|
-
state:
|
|
6744
|
+
state: context.merkleState,
|
|
6404
6745
|
senderPrivKeyScalarHex: context.senderPrivKeyScalarHex,
|
|
6405
6746
|
ephemeralAKey: serializeEphemeralKeyString({
|
|
6406
6747
|
xHex: context.ephemeral.xHex,
|
|
@@ -6648,7 +6989,7 @@ async function finalizeSingleWithdrawAtExecute(prepared, environment, poolServic
|
|
|
6648
6989
|
});
|
|
6649
6990
|
const proof = await poolService.prepareWithdrawTransactProof({
|
|
6650
6991
|
coin: context.coin,
|
|
6651
|
-
state:
|
|
6992
|
+
state: context.merkleState,
|
|
6652
6993
|
destinationStellarAddress: prepared.intent.to,
|
|
6653
6994
|
privKeyScalarHex: context.senderPrivKeyScalarHex,
|
|
6654
6995
|
depositorEphemeralKey: serializeEphemeralKeyString({
|
|
@@ -6701,7 +7042,7 @@ async function finalizeDualWithdrawAtExecute(prepared, environment, poolService,
|
|
|
6701
7042
|
const proof = await poolService.prepareWithdrawTransactProofDual({
|
|
6702
7043
|
coinA: context.coin,
|
|
6703
7044
|
coinB: secondary.coin,
|
|
6704
|
-
state:
|
|
7045
|
+
state: context.merkleState,
|
|
6705
7046
|
destinationStellarAddress: prepared.intent.to,
|
|
6706
7047
|
privKeyScalarHex: context.senderPrivKeyScalarHex,
|
|
6707
7048
|
...dualWithdrawEphemeralKeys({ context, secondary }),
|