@arcanetech/privacy-sdk-stellar 0.5.2 → 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/README.md +1 -0
- package/dist/index.d.ts +85 -25
- package/dist/index.js +1081 -258
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +25 -1
- package/dist/node.js +1082 -267
- 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/testing/index.d.ts +1 -0
- package/dist/transact/index.d.ts +50 -6
- package/dist/transact/index.js +975 -264
- package/dist/transact/index.js.map +1 -1
- package/package.json +7 -7
package/dist/transact/index.js
CHANGED
|
@@ -1,26 +1,8 @@
|
|
|
1
1
|
// src/transact/pool/service.ts
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
decodeDecodedEphemeralKey,
|
|
5
|
-
randomFrDecimal253,
|
|
6
|
-
scalarHexToFrDecimal as scalarHexToFrDecimal2
|
|
3
|
+
decodeDecodedEphemeralKey
|
|
7
4
|
} from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
8
5
|
|
|
9
|
-
// src/transact/merkle/field-decimal.ts
|
|
10
|
-
import { Buffer as Buffer2 } from "buffer";
|
|
11
|
-
var BN254 = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
|
|
12
|
-
var MERKLE_ROOT_BYTE_LENGTH = 32;
|
|
13
|
-
var DECIMAL_STRING_RADIX = 10;
|
|
14
|
-
function merkleRootBufferToFrDecimal(root) {
|
|
15
|
-
if (root.length !== MERKLE_ROOT_BYTE_LENGTH) {
|
|
16
|
-
throw new Error(
|
|
17
|
-
`expected ${MERKLE_ROOT_BYTE_LENGTH}-byte merkle root, got ${root.length}`
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
const hex = Buffer2.from(root).toString("hex");
|
|
21
|
-
return (BigInt(`0x${hex}`) % BN254).toString(DECIMAL_STRING_RADIX);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
6
|
// src/transact/private-address/codec.ts
|
|
25
7
|
import {
|
|
26
8
|
buildStealthAddressSignMessage,
|
|
@@ -76,18 +58,18 @@ function privateAddressSdk(sdk) {
|
|
|
76
58
|
import { withdrawObjectFromMerkleWitness as withdrawObjectFromMerkleWitness2 } from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
77
59
|
|
|
78
60
|
// src/transact/proofs/transaction-input.ts
|
|
79
|
-
import { Buffer as
|
|
61
|
+
import { Buffer as Buffer3 } from "buffer";
|
|
80
62
|
import { StrKey as StrKey2 } from "@stellar/stellar-sdk";
|
|
81
63
|
|
|
82
64
|
// src/transact/stellar/token-contract.ts
|
|
83
|
-
import { Buffer as
|
|
65
|
+
import { Buffer as Buffer2 } from "buffer";
|
|
84
66
|
import { StrKey } from "@stellar/stellar-sdk";
|
|
85
67
|
var CONTRACT_ID_BYTE_LENGTH = 32;
|
|
86
68
|
var HEX_CHARS_PER_BYTE = 2;
|
|
87
69
|
var CONTRACT_ID_HEX_CHAR_LENGTH = CONTRACT_ID_BYTE_LENGTH * HEX_CHARS_PER_BYTE;
|
|
88
70
|
var CONTRACT_ID_HEX = /^(?:0x)?([0-9a-f]{64})$/i;
|
|
89
71
|
function encodeContractFromHex(hexPayload) {
|
|
90
|
-
return StrKey.encodeContract(
|
|
72
|
+
return StrKey.encodeContract(Buffer2.from(hexPayload, "hex"));
|
|
91
73
|
}
|
|
92
74
|
function normalizeSorobanContractId(raw) {
|
|
93
75
|
const trimmed = raw.trim();
|
|
@@ -120,14 +102,14 @@ var ZERO_PUBLIC_WITHDRAW_ADDRESS = {
|
|
|
120
102
|
var CONTRACT_ADDRESS_HALF_BYTES = 16;
|
|
121
103
|
var CONTRACT_ADDRESS_BYTES = 32;
|
|
122
104
|
function bytes16ToDecimal(bytes) {
|
|
123
|
-
return BigInt(`0x${
|
|
105
|
+
return BigInt(`0x${Buffer3.from(bytes).toString("hex")}`).toString();
|
|
124
106
|
}
|
|
125
107
|
function decimalToBytes16(value) {
|
|
126
108
|
const hex = BigInt(value).toString(16).padStart(CONTRACT_ADDRESS_HALF_BYTES * 2, "0");
|
|
127
109
|
if (hex.length > CONTRACT_ADDRESS_HALF_BYTES * 2) {
|
|
128
110
|
throw new Error("Asset leg does not fit into 16 bytes.");
|
|
129
111
|
}
|
|
130
|
-
return
|
|
112
|
+
return Buffer3.from(hex, "hex");
|
|
131
113
|
}
|
|
132
114
|
function tokenAddressFrParts(tokenAddress) {
|
|
133
115
|
const normalized = resolveTokenContractId(tokenAddress);
|
|
@@ -169,7 +151,7 @@ function tokenAddressToAssetLeg(tokenAddress) {
|
|
|
169
151
|
return [hi, lo];
|
|
170
152
|
}
|
|
171
153
|
function assetLegToTokenAddress(assetHi, assetLo) {
|
|
172
|
-
const payload =
|
|
154
|
+
const payload = Buffer3.concat([decimalToBytes16(assetHi), decimalToBytes16(assetLo)]);
|
|
173
155
|
return StrKey2.encodeContract(payload);
|
|
174
156
|
}
|
|
175
157
|
function buildZeroPublicLegs(publicNInputs = 1, publicNOutputs = 1) {
|
|
@@ -246,11 +228,240 @@ function uniformApplicationIdHints(applicationId, nAuditSlots) {
|
|
|
246
228
|
|
|
247
229
|
// src/transact/proofs/confidential/helpers.ts
|
|
248
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
|
|
249
460
|
var MIN_CONFIDENTIAL_TRANSFER_STROOPS = 1n;
|
|
250
461
|
var ZERO_STROOPS = 0n;
|
|
251
462
|
function withdrawWitnessForCoin(parameters) {
|
|
252
463
|
const { sdk, coin, state } = parameters;
|
|
253
|
-
const witness = sdk
|
|
464
|
+
const witness = withdrawMerkleWitnessFromTree({ sdk, coin, state });
|
|
254
465
|
const withdrawApplicationId = coin.application_id ?? parameters.applicationId;
|
|
255
466
|
const withdrawObject = withdrawObjectFromMerkleWitness(
|
|
256
467
|
witness,
|
|
@@ -292,14 +503,144 @@ function requireChangeRecipientWhenPartial(changeStroops, selfPrivateAddressStpl
|
|
|
292
503
|
}
|
|
293
504
|
}
|
|
294
505
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
506
|
+
|
|
507
|
+
// src/transact/fees/quote-request-body.ts
|
|
508
|
+
function presentInstructedAmount(amount) {
|
|
509
|
+
const trimmed = amount?.trim() ?? "";
|
|
510
|
+
if (!trimmed || trimmed === "0") {
|
|
511
|
+
return void 0;
|
|
298
512
|
}
|
|
299
|
-
|
|
300
|
-
|
|
513
|
+
return trimmed;
|
|
514
|
+
}
|
|
515
|
+
function feeQuoteRequestBody(request) {
|
|
516
|
+
const publicDepositAmount = presentInstructedAmount(request.publicDepositAmount);
|
|
517
|
+
const transferInstructedAmount = presentInstructedAmount(
|
|
518
|
+
request.transferInstructedAmount
|
|
519
|
+
);
|
|
520
|
+
const publicWithdrawalAmount = presentInstructedAmount(
|
|
521
|
+
request.publicWithdrawalAmount
|
|
522
|
+
);
|
|
523
|
+
return {
|
|
524
|
+
feeAsset: request.feeAsset,
|
|
525
|
+
spendsNotes: request.spendsNotes,
|
|
526
|
+
...publicDepositAmount === void 0 ? {} : { publicDepositAmount },
|
|
527
|
+
...transferInstructedAmount === void 0 ? {} : { transferInstructedAmount },
|
|
528
|
+
...publicWithdrawalAmount === void 0 ? {} : { publicWithdrawalAmount }
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// src/transact/fees/quote-required-fee.ts
|
|
533
|
+
function quoteHeaders(inspectAuthorization) {
|
|
534
|
+
const token = inspectAuthorization?.trim();
|
|
535
|
+
return {
|
|
536
|
+
"content-type": "application/json",
|
|
537
|
+
...token ? { authorization: `Bearer ${token}` } : {}
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function parseRequiredFee(raw) {
|
|
541
|
+
const text = `${raw ?? ""}`.trim();
|
|
542
|
+
if (!/^\d+$/u.test(text)) {
|
|
543
|
+
throw new Error("Fee Quote Required Fee must be an integer minor-unit string.");
|
|
544
|
+
}
|
|
545
|
+
return BigInt(text);
|
|
546
|
+
}
|
|
547
|
+
function requireQuoteString(raw, field) {
|
|
548
|
+
const text = `${raw ?? ""}`.trim();
|
|
549
|
+
if (!text) {
|
|
550
|
+
throw new Error(`Fee Quote is missing ${field}.`);
|
|
551
|
+
}
|
|
552
|
+
return text;
|
|
553
|
+
}
|
|
554
|
+
function parseQuotePayload(payload) {
|
|
555
|
+
return {
|
|
556
|
+
requiredFee: parseRequiredFee(payload.requiredFee),
|
|
557
|
+
feeAsset: requireQuoteString(payload.feeAsset, "Fee Asset"),
|
|
558
|
+
feeCollectorPrivateAddress: requireQuoteString(
|
|
559
|
+
payload.feeCollectorPrivateAddress,
|
|
560
|
+
"Fee Collector Private Address"
|
|
561
|
+
),
|
|
562
|
+
feeRate: requireQuoteString(payload.feeRate, "Fee Rate")
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
async function quoteRequiredFee(input) {
|
|
566
|
+
const response = await fetch(
|
|
567
|
+
`${input.transactEnvironment.kyt.apiBaseUrl}/kyt/fees/quote`,
|
|
568
|
+
{
|
|
569
|
+
method: "POST",
|
|
570
|
+
headers: quoteHeaders(input.transactEnvironment.kyt.inspectAuthorization),
|
|
571
|
+
body: JSON.stringify(feeQuoteRequestBody(input.request))
|
|
572
|
+
}
|
|
573
|
+
);
|
|
574
|
+
const payload = await response.json();
|
|
575
|
+
if (!response.ok) {
|
|
576
|
+
throw new Error(`Fee Quote failed: ${JSON.stringify(payload)}`);
|
|
577
|
+
}
|
|
578
|
+
return parseQuotePayload(payload);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
// src/transact/fees/should-attach-fee-output.ts
|
|
582
|
+
function shouldAttachFeeOutput(input) {
|
|
583
|
+
if (input.spendSource === "escrow" && input.escrowSend !== true) {
|
|
584
|
+
return false;
|
|
301
585
|
}
|
|
302
|
-
return
|
|
586
|
+
return input.kind === "deposit" || input.kind === "transfer" || input.kind === "withdraw";
|
|
587
|
+
}
|
|
588
|
+
function feeOutputKindFromPrepared(prepared) {
|
|
589
|
+
return {
|
|
590
|
+
kind: prepared.kind,
|
|
591
|
+
...prepared.transactArtifacts?.spendSource ? { spendSource: prepared.transactArtifacts.spendSource } : {},
|
|
592
|
+
...prepared.transactArtifacts?.escrowSend ? { escrowSend: true } : {}
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// src/transact/fees/quote-fee-output-for-prepared.ts
|
|
597
|
+
function instructedMinorUnits(prepared) {
|
|
598
|
+
return prepared.intent.amount.toString();
|
|
599
|
+
}
|
|
600
|
+
function quoteRequestForPrepared(input) {
|
|
601
|
+
const amount = instructedMinorUnits(input.prepared);
|
|
602
|
+
if (input.prepared.kind === "deposit") {
|
|
603
|
+
return {
|
|
604
|
+
feeAsset: input.tokenAddress,
|
|
605
|
+
publicDepositAmount: amount,
|
|
606
|
+
spendsNotes: false
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
if (input.prepared.kind === "withdraw") {
|
|
610
|
+
return {
|
|
611
|
+
feeAsset: input.tokenAddress,
|
|
612
|
+
publicWithdrawalAmount: amount,
|
|
613
|
+
spendsNotes: true
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
return {
|
|
617
|
+
feeAsset: input.tokenAddress,
|
|
618
|
+
transferInstructedAmount: amount,
|
|
619
|
+
spendsNotes: true
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
async function quoteFeeOutputForPrepared(input) {
|
|
623
|
+
if (!shouldAttachFeeOutput(feeOutputKindFromPrepared(input.prepared))) {
|
|
624
|
+
return void 0;
|
|
625
|
+
}
|
|
626
|
+
const quote = await quoteRequiredFee({
|
|
627
|
+
transactEnvironment: input.environment,
|
|
628
|
+
request: quoteRequestForPrepared(input)
|
|
629
|
+
});
|
|
630
|
+
if (quote.requiredFee <= 0n) {
|
|
631
|
+
return void 0;
|
|
632
|
+
}
|
|
633
|
+
return {
|
|
634
|
+
requiredFee: quote.requiredFee,
|
|
635
|
+
feeCollectorPrivateAddress: quote.feeCollectorPrivateAddress
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
function remainingAfterRequiredFee(input) {
|
|
639
|
+
const remaining = input.available - input.instructed - input.requiredFee;
|
|
640
|
+
if (remaining < 0n) {
|
|
641
|
+
throw new Error("Instructed amount and Required Fee exceed available note value");
|
|
642
|
+
}
|
|
643
|
+
return remaining;
|
|
303
644
|
}
|
|
304
645
|
|
|
305
646
|
// src/transact/audit/parameters.ts
|
|
@@ -440,6 +781,32 @@ function privKeyScalarDecimalFromRecipientScalarHex(hexInput) {
|
|
|
440
781
|
return canonicalBabyJubScalarFromInteger(value).toString(DECIMAL_RADIX2);
|
|
441
782
|
}
|
|
442
783
|
|
|
784
|
+
// src/transact/fees/append-fee-output.ts
|
|
785
|
+
function feeCoinFromSlot(slot) {
|
|
786
|
+
return {
|
|
787
|
+
commitment_hex: slot.commitment_hex,
|
|
788
|
+
coin: slot.coin,
|
|
789
|
+
depositScalarHex: slot.depositScalarHex,
|
|
790
|
+
precommitementHex: slot.precommitementHex
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
async function appendFeeOutputSlot(input) {
|
|
794
|
+
const requiredFee = input.feeOutput?.requiredFee ?? ZERO_STROOPS;
|
|
795
|
+
const collector = input.feeOutput?.feeCollectorPrivateAddress.trim() ?? "";
|
|
796
|
+
if (requiredFee <= ZERO_STROOPS || !collector) {
|
|
797
|
+
return { deposits: input.deposits };
|
|
798
|
+
}
|
|
799
|
+
const slot = await input.buildAlignedDepositSlot({
|
|
800
|
+
privateAddressStpl1: collector,
|
|
801
|
+
amountStroops: requiredFee,
|
|
802
|
+
tokenAddress: input.tokenAddress
|
|
803
|
+
});
|
|
804
|
+
return {
|
|
805
|
+
deposits: [...input.deposits, slot.deposit],
|
|
806
|
+
feeCoin: feeCoinFromSlot(slot)
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
|
|
443
810
|
// src/transact/proofs/withdraw/helpers.ts
|
|
444
811
|
function destinationWithdrawFrAndScalar(parameters) {
|
|
445
812
|
const pkHex = ed25519PublicKeyHexFromStellarAccount(
|
|
@@ -494,14 +861,15 @@ async function resolveWithdrawChangeDeposits(parameters) {
|
|
|
494
861
|
}
|
|
495
862
|
};
|
|
496
863
|
}
|
|
497
|
-
function validateDualWithdrawAmounts(withdrawAmountStroops, totalNotes, changePrivateAddressStpl1) {
|
|
864
|
+
function validateDualWithdrawAmounts(withdrawAmountStroops, totalNotes, changePrivateAddressStpl1, requiredFee) {
|
|
498
865
|
if (withdrawAmountStroops < MIN_CONFIDENTIAL_TRANSFER_STROOPS) {
|
|
499
866
|
throw new Error("Withdraw amount must be positive");
|
|
500
867
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
868
|
+
const changeStroops = remainingAfterRequiredFee({
|
|
869
|
+
available: totalNotes,
|
|
870
|
+
instructed: withdrawAmountStroops,
|
|
871
|
+
requiredFee
|
|
872
|
+
});
|
|
505
873
|
requireChangeRecipientWhenPartial(changeStroops, changePrivateAddressStpl1);
|
|
506
874
|
return changeStroops;
|
|
507
875
|
}
|
|
@@ -514,11 +882,31 @@ function buildDualWithdrawPublicInput(parameters) {
|
|
|
514
882
|
publicWithdrawalAmount: parameters.publicWithdrawalAmount
|
|
515
883
|
});
|
|
516
884
|
}
|
|
885
|
+
async function withdrawOutputsWithOptionalFee(parameters) {
|
|
886
|
+
const { deposits: changeDeposits, changeCoin } = await resolveWithdrawChangeDeposits({
|
|
887
|
+
changeStroops: parameters.changeStroops,
|
|
888
|
+
changePrivateAddressStpl1: parameters.changePrivateAddressStpl1,
|
|
889
|
+
buildAlignedDepositSlot: parameters.buildAlignedDepositSlot,
|
|
890
|
+
tokenAddress: parameters.tokenAddress
|
|
891
|
+
});
|
|
892
|
+
const withFee = await appendFeeOutputSlot({
|
|
893
|
+
deposits: changeDeposits,
|
|
894
|
+
tokenAddress: parameters.tokenAddress,
|
|
895
|
+
buildAlignedDepositSlot: parameters.buildAlignedDepositSlot,
|
|
896
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
897
|
+
});
|
|
898
|
+
return {
|
|
899
|
+
deposits: withFee.deposits,
|
|
900
|
+
...changeCoin ? { changeCoin } : {},
|
|
901
|
+
...withFee.feeCoin ? { feeCoin: withFee.feeCoin } : {}
|
|
902
|
+
};
|
|
903
|
+
}
|
|
517
904
|
async function prepareDualWithdrawProofInputs(parameters) {
|
|
518
905
|
const changeStroops = validateDualWithdrawAmounts(
|
|
519
906
|
parameters.withdrawAmountStroops,
|
|
520
907
|
BigInt(parameters.coinA.value) + BigInt(parameters.coinB.value),
|
|
521
|
-
parameters.changePrivateAddressStpl1
|
|
908
|
+
parameters.changePrivateAddressStpl1,
|
|
909
|
+
parameters.feeOutput?.requiredFee ?? 0n
|
|
522
910
|
);
|
|
523
911
|
const { legA, legB } = dualWithdrawLegsWithSharedRoot({
|
|
524
912
|
sdk: parameters.sdk,
|
|
@@ -533,11 +921,12 @@ async function prepareDualWithdrawProofInputs(parameters) {
|
|
|
533
921
|
),
|
|
534
922
|
applicationId: parameters.applicationId
|
|
535
923
|
});
|
|
536
|
-
const { deposits, changeCoin } = await
|
|
924
|
+
const { deposits, changeCoin, feeCoin } = await withdrawOutputsWithOptionalFee({
|
|
537
925
|
changeStroops,
|
|
538
926
|
changePrivateAddressStpl1: parameters.changePrivateAddressStpl1,
|
|
539
927
|
buildAlignedDepositSlot: parameters.buildAlignedDepositSlot,
|
|
540
|
-
tokenAddress: parameters.tokenAddress
|
|
928
|
+
tokenAddress: parameters.tokenAddress,
|
|
929
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
541
930
|
});
|
|
542
931
|
const publicInput = buildDualWithdrawPublicInput({
|
|
543
932
|
destinationStellarAddress: parameters.destinationStellarAddress,
|
|
@@ -556,19 +945,55 @@ async function prepareDualWithdrawProofInputs(parameters) {
|
|
|
556
945
|
audit,
|
|
557
946
|
deposits,
|
|
558
947
|
withdrawLegs: [legA.withdrawObject, legB.withdrawObject],
|
|
559
|
-
...changeCoin ? { changeCoin } : {}
|
|
948
|
+
...changeCoin ? { changeCoin } : {},
|
|
949
|
+
...feeCoin ? { feeCoin } : {}
|
|
560
950
|
};
|
|
561
951
|
}
|
|
562
952
|
|
|
953
|
+
// src/transact/proofs/withdraw/fee-deposits.ts
|
|
954
|
+
async function withdrawDepositsWithFee(parameters) {
|
|
955
|
+
const { deposits, changeCoin } = await resolveWithdrawChangeDeposits({
|
|
956
|
+
changeStroops: parameters.changeStroops,
|
|
957
|
+
changePrivateAddressStpl1: parameters.changePrivateAddressStpl1,
|
|
958
|
+
buildAlignedDepositSlot: parameters.buildAlignedDepositSlot,
|
|
959
|
+
tokenAddress: parameters.tokenAddress
|
|
960
|
+
});
|
|
961
|
+
const withFee = await appendFeeOutputSlot({
|
|
962
|
+
deposits,
|
|
963
|
+
tokenAddress: parameters.tokenAddress,
|
|
964
|
+
buildAlignedDepositSlot: parameters.buildAlignedDepositSlot,
|
|
965
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
966
|
+
});
|
|
967
|
+
return {
|
|
968
|
+
deposits: withFee.deposits,
|
|
969
|
+
...changeCoin ? { changeCoin } : {},
|
|
970
|
+
...withFee.feeCoin ? { feeCoin: withFee.feeCoin } : {}
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
function withdrawOutputApplicationIds(input) {
|
|
974
|
+
const outputIds = [];
|
|
975
|
+
if (input.hasChange) {
|
|
976
|
+
outputIds.push(input.applicationId);
|
|
977
|
+
}
|
|
978
|
+
if (input.hasFeeOutput) {
|
|
979
|
+
outputIds.push(input.applicationId);
|
|
980
|
+
}
|
|
981
|
+
if (outputIds.length === 0) {
|
|
982
|
+
outputIds.push("0");
|
|
983
|
+
}
|
|
984
|
+
return outputIds;
|
|
985
|
+
}
|
|
986
|
+
|
|
563
987
|
// src/transact/proofs/withdraw/transact-proof.ts
|
|
564
|
-
function validateSingleWithdrawAmounts(withdrawAmountStroops, noteStroops) {
|
|
988
|
+
function validateSingleWithdrawAmounts(withdrawAmountStroops, noteStroops, requiredFee) {
|
|
565
989
|
if (withdrawAmountStroops < MIN_CONFIDENTIAL_TRANSFER_STROOPS) {
|
|
566
990
|
throw new Error("Withdraw amount must be positive");
|
|
567
991
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
992
|
+
return remainingAfterRequiredFee({
|
|
993
|
+
available: noteStroops,
|
|
994
|
+
instructed: withdrawAmountStroops,
|
|
995
|
+
requiredFee
|
|
996
|
+
});
|
|
572
997
|
}
|
|
573
998
|
async function proveSingleWithdrawTransaction(parameters) {
|
|
574
999
|
return parameters.sdk.proveTransaction(
|
|
@@ -586,10 +1011,11 @@ async function proveSingleWithdrawTransaction(parameters) {
|
|
|
586
1011
|
);
|
|
587
1012
|
}
|
|
588
1013
|
function buildPrimaryWithdrawForCoin(parameters) {
|
|
589
|
-
const witness =
|
|
590
|
-
parameters.
|
|
591
|
-
parameters.
|
|
592
|
-
|
|
1014
|
+
const witness = withdrawMerkleWitnessFromTree({
|
|
1015
|
+
sdk: parameters.sdk,
|
|
1016
|
+
coin: parameters.coin,
|
|
1017
|
+
state: parameters.state
|
|
1018
|
+
});
|
|
593
1019
|
const privKeyScalar = privKeyScalarDecimalFromRecipientScalarHex(
|
|
594
1020
|
parameters.privKeyScalarHex
|
|
595
1021
|
);
|
|
@@ -607,7 +1033,8 @@ function buildPrimaryWithdrawForCoin(parameters) {
|
|
|
607
1033
|
async function prepareSingleWithdrawProofInputs(parameters) {
|
|
608
1034
|
const changeStroops = validateSingleWithdrawAmounts(
|
|
609
1035
|
parameters.withdrawAmountStroops,
|
|
610
|
-
BigInt(parameters.coin.value)
|
|
1036
|
+
BigInt(parameters.coin.value),
|
|
1037
|
+
parameters.feeOutput?.requiredFee ?? 0n
|
|
611
1038
|
);
|
|
612
1039
|
const { witness, primaryWithdraw } = buildPrimaryWithdrawForCoin({
|
|
613
1040
|
sdk: parameters.sdk,
|
|
@@ -616,11 +1043,12 @@ async function prepareSingleWithdrawProofInputs(parameters) {
|
|
|
616
1043
|
state: parameters.state,
|
|
617
1044
|
privKeyScalarHex: parameters.privKeyScalarHex
|
|
618
1045
|
});
|
|
619
|
-
const { deposits, changeCoin } = await
|
|
1046
|
+
const { deposits, changeCoin, feeCoin } = await withdrawDepositsWithFee({
|
|
620
1047
|
changeStroops,
|
|
621
1048
|
changePrivateAddressStpl1: parameters.changePrivateAddressStpl1,
|
|
622
1049
|
buildAlignedDepositSlot: parameters.buildAlignedDepositSlot,
|
|
623
|
-
tokenAddress: parameters.tokenAddress
|
|
1050
|
+
tokenAddress: parameters.tokenAddress,
|
|
1051
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
624
1052
|
});
|
|
625
1053
|
const publicInput = buildWithdrawPublicInput({
|
|
626
1054
|
stateRoot: witness.stateRoot,
|
|
@@ -633,6 +1061,7 @@ async function prepareSingleWithdrawProofInputs(parameters) {
|
|
|
633
1061
|
primaryWithdraw,
|
|
634
1062
|
deposits,
|
|
635
1063
|
changeCoin,
|
|
1064
|
+
feeCoin,
|
|
636
1065
|
publicInput,
|
|
637
1066
|
audit: buildPoolTransactionAuditParameters({
|
|
638
1067
|
applicationId: parameters.applicationId,
|
|
@@ -642,7 +1071,7 @@ async function prepareSingleWithdrawProofInputs(parameters) {
|
|
|
642
1071
|
};
|
|
643
1072
|
}
|
|
644
1073
|
async function proveWithdrawTransact(parameters) {
|
|
645
|
-
const { primaryWithdraw, deposits, changeCoin, publicInput, audit } = await prepareSingleWithdrawProofInputs(parameters);
|
|
1074
|
+
const { primaryWithdraw, deposits, changeCoin, feeCoin, publicInput, audit } = await prepareSingleWithdrawProofInputs(parameters);
|
|
646
1075
|
const proof = await proveSingleWithdrawTransaction({
|
|
647
1076
|
sdk: parameters.sdk,
|
|
648
1077
|
publicInput,
|
|
@@ -657,13 +1086,17 @@ async function proveWithdrawTransact(parameters) {
|
|
|
657
1086
|
applicationIdsPlaintext: buildApplicationIdHints({
|
|
658
1087
|
sdk: parameters.sdk,
|
|
659
1088
|
inputIds: [parameters.applicationId],
|
|
660
|
-
outputIds:
|
|
1089
|
+
outputIds: withdrawOutputApplicationIds({
|
|
1090
|
+
applicationId: parameters.applicationId,
|
|
1091
|
+
hasChange: Boolean(changeCoin),
|
|
1092
|
+
hasFeeOutput: Boolean(feeCoin)
|
|
1093
|
+
})
|
|
661
1094
|
}),
|
|
662
1095
|
...changeCoin ? { changeCoin } : {}
|
|
663
1096
|
};
|
|
664
1097
|
}
|
|
665
1098
|
async function proveWithdrawTransactDual(parameters) {
|
|
666
|
-
const { publicInput, audit, withdrawLegs, deposits, changeCoin } = await prepareDualWithdrawProofInputs(parameters);
|
|
1099
|
+
const { publicInput, audit, withdrawLegs, deposits, changeCoin, feeCoin } = await prepareDualWithdrawProofInputs(parameters);
|
|
667
1100
|
const proof = await parameters.sdk.proveTransaction(
|
|
668
1101
|
publicInput,
|
|
669
1102
|
padPublicLegsToLayout(
|
|
@@ -682,7 +1115,11 @@ async function proveWithdrawTransactDual(parameters) {
|
|
|
682
1115
|
applicationIdsPlaintext: buildApplicationIdHints({
|
|
683
1116
|
sdk: parameters.sdk,
|
|
684
1117
|
inputIds: [audit.applicationId, audit.applicationId],
|
|
685
|
-
outputIds:
|
|
1118
|
+
outputIds: withdrawOutputApplicationIds({
|
|
1119
|
+
applicationId: audit.applicationId,
|
|
1120
|
+
hasChange: Boolean(changeCoin),
|
|
1121
|
+
hasFeeOutput: Boolean(feeCoin)
|
|
1122
|
+
})
|
|
686
1123
|
}),
|
|
687
1124
|
...changeCoin ? { changeCoin } : {}
|
|
688
1125
|
};
|
|
@@ -706,6 +1143,9 @@ var DEFAULT_ZK_CONFIG_NONCE = BINDING_ZK_NONCE;
|
|
|
706
1143
|
function resolveZkConfigNonce(transactEnvironment) {
|
|
707
1144
|
return transactEnvironment.zkConfigNonce ?? DEFAULT_ZK_CONFIG_NONCE;
|
|
708
1145
|
}
|
|
1146
|
+
function transactNonceFromArtifacts(artifacts, transactEnvironment) {
|
|
1147
|
+
return artifacts?.zkConfigNonce ?? resolveZkConfigNonce(transactEnvironment);
|
|
1148
|
+
}
|
|
709
1149
|
|
|
710
1150
|
// src/transact/zk/browser-artifact-cache.ts
|
|
711
1151
|
import { ZK_ARTIFACT_VERSION } from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
@@ -958,6 +1398,105 @@ async function buildAlignedDepositSlotForSdk(sdk, applicationId, parameters) {
|
|
|
958
1398
|
};
|
|
959
1399
|
}
|
|
960
1400
|
|
|
1401
|
+
// src/transact/pool/initialize-sdk.ts
|
|
1402
|
+
import { PrivacyPoolSDK as PrivacyPoolSDK2 } from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
1403
|
+
async function initializePrivacyPoolSdk(input, nonce) {
|
|
1404
|
+
const zkConfigNonce = nonce ?? input.zkConfigNonce ?? DEFAULT_ZK_CONFIG_NONCE;
|
|
1405
|
+
const zkCircuits = await materializeSelectedZkCircuit(
|
|
1406
|
+
input.zkCircuits,
|
|
1407
|
+
zkConfigNonce,
|
|
1408
|
+
input.zkArtifactBaseUrl
|
|
1409
|
+
);
|
|
1410
|
+
return PrivacyPoolSDK2.init({
|
|
1411
|
+
wasmBinary: input.assets.sdkWasm,
|
|
1412
|
+
zkCircuits,
|
|
1413
|
+
zkConfigNonce,
|
|
1414
|
+
...optionalZkArtifactBaseUrl(input.zkArtifactBaseUrl)
|
|
1415
|
+
});
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
// src/transact/fees/zk-config-nonce-for-kind.ts
|
|
1419
|
+
function configuredNonceSpread(zkConfigNonce) {
|
|
1420
|
+
if (zkConfigNonce === void 0) {
|
|
1421
|
+
return {};
|
|
1422
|
+
}
|
|
1423
|
+
return { configuredNonce: zkConfigNonce };
|
|
1424
|
+
}
|
|
1425
|
+
function zkConfigNonceForFeeBearingKind(input) {
|
|
1426
|
+
if (input.configuredNonce === SIX_BY_SIX_BINDING_ZK_NONCE) {
|
|
1427
|
+
return SIX_BY_SIX_BINDING_ZK_NONCE;
|
|
1428
|
+
}
|
|
1429
|
+
if (input.kind === "transfer" && shouldAttachFeeOutput(input)) {
|
|
1430
|
+
return SIX_BY_SIX_BINDING_ZK_NONCE;
|
|
1431
|
+
}
|
|
1432
|
+
return input.configuredNonce ?? BINDING_ZK_NONCE;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
// src/transact/pool/prepare-deposit-proof.ts
|
|
1436
|
+
import {
|
|
1437
|
+
randomFrDecimal253,
|
|
1438
|
+
scalarHexToFrDecimal as scalarHexToFrDecimal2
|
|
1439
|
+
} from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
1440
|
+
function userDepositSlot(input) {
|
|
1441
|
+
return {
|
|
1442
|
+
value: input.coin.value,
|
|
1443
|
+
nullifier: input.coin.nullifier,
|
|
1444
|
+
ephemeralKeyScalar: scalarHexToFrDecimal2(input.depositScalarHex),
|
|
1445
|
+
asset: [input.coin.asset_hi, input.coin.asset_lo],
|
|
1446
|
+
applicationId: input.applicationId,
|
|
1447
|
+
recipientPublicKeys: recipientPublicKeysDecimalFromPrivateAddress(
|
|
1448
|
+
input.privateAddressStpl1
|
|
1449
|
+
)
|
|
1450
|
+
};
|
|
1451
|
+
}
|
|
1452
|
+
function outputApplicationIds(input) {
|
|
1453
|
+
if (input.hasFeeOutput) {
|
|
1454
|
+
return [input.applicationId, input.applicationId];
|
|
1455
|
+
}
|
|
1456
|
+
return [input.applicationId];
|
|
1457
|
+
}
|
|
1458
|
+
async function proveDepositTransact(input) {
|
|
1459
|
+
const publicDeposit = (input.publicDepositStroops ?? BigInt(input.coin.value)).toString();
|
|
1460
|
+
const withFee = await appendFeeOutputSlot({
|
|
1461
|
+
deposits: [userDepositSlot(input)],
|
|
1462
|
+
tokenAddress: input.tokenAddress,
|
|
1463
|
+
buildAlignedDepositSlot: input.buildAlignedDepositSlot,
|
|
1464
|
+
...input.feeOutput ? { feeOutput: input.feeOutput } : {}
|
|
1465
|
+
});
|
|
1466
|
+
const audit = buildPoolTransactionAuditParameters({
|
|
1467
|
+
applicationId: input.applicationId,
|
|
1468
|
+
nAuditSlots: input.sdk.getLayout().nAuditSlots,
|
|
1469
|
+
...input.auditPublicKey ? { auditPublicKey: input.auditPublicKey } : {}
|
|
1470
|
+
});
|
|
1471
|
+
const proof = await input.sdk.proveTransaction(
|
|
1472
|
+
withTokenAddressPublicInputs(
|
|
1473
|
+
{
|
|
1474
|
+
stateRoot: merkleRootBufferToFrDecimal(input.merkleRootBytes),
|
|
1475
|
+
privKeyScalar: randomFrDecimal253()
|
|
1476
|
+
},
|
|
1477
|
+
input.tokenAddress
|
|
1478
|
+
),
|
|
1479
|
+
padPublicLegsToLayout(
|
|
1480
|
+
input.sdk,
|
|
1481
|
+
buildPublicDepositLegs(input.tokenAddress, publicDeposit)
|
|
1482
|
+
),
|
|
1483
|
+
padWithdrawSlotsToLayout(input.sdk, []),
|
|
1484
|
+
padDepositSlotsToLayout(input.sdk, withFee.deposits),
|
|
1485
|
+
audit
|
|
1486
|
+
);
|
|
1487
|
+
return {
|
|
1488
|
+
...proof,
|
|
1489
|
+
applicationIdsPlaintext: buildApplicationIdHints({
|
|
1490
|
+
sdk: input.sdk,
|
|
1491
|
+
inputIds: [],
|
|
1492
|
+
outputIds: outputApplicationIds({
|
|
1493
|
+
applicationId: input.applicationId,
|
|
1494
|
+
hasFeeOutput: Boolean(withFee.feeCoin)
|
|
1495
|
+
})
|
|
1496
|
+
})
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
|
|
961
1500
|
// src/transact/pool/service.ts
|
|
962
1501
|
var PrivacyPoolService = class {
|
|
963
1502
|
constructor(assets, applicationId, auditPublicKey, zkCircuits, zkConfigNonce, zkArtifactBaseUrl) {
|
|
@@ -974,42 +1513,50 @@ var PrivacyPoolService = class {
|
|
|
974
1513
|
zkCircuits;
|
|
975
1514
|
zkConfigNonce;
|
|
976
1515
|
zkArtifactBaseUrl;
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
async
|
|
980
|
-
|
|
981
|
-
|
|
1516
|
+
sdks = /* @__PURE__ */ new Map();
|
|
1517
|
+
initPromises = /* @__PURE__ */ new Map();
|
|
1518
|
+
async getInitializedSdk(nonce) {
|
|
1519
|
+
const zkConfigNonce = nonce ?? this.zkConfigNonce ?? DEFAULT_ZK_CONFIG_NONCE;
|
|
1520
|
+
const key = zkConfigNonce.toString();
|
|
1521
|
+
const existing = this.sdks.get(key);
|
|
1522
|
+
if (existing) {
|
|
1523
|
+
return existing;
|
|
982
1524
|
}
|
|
983
|
-
|
|
984
|
-
|
|
1525
|
+
const pending = this.initPromises.get(key);
|
|
1526
|
+
if (pending) {
|
|
1527
|
+
return pending;
|
|
985
1528
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
zkConfigNonce,
|
|
1002
|
-
...optionalZkArtifactBaseUrl(this.zkArtifactBaseUrl)
|
|
1003
|
-
});
|
|
1004
|
-
})();
|
|
1005
|
-
return this.initPromise;
|
|
1529
|
+
const started = this.initializeSdk(zkConfigNonce);
|
|
1530
|
+
this.initPromises.set(key, started);
|
|
1531
|
+
try {
|
|
1532
|
+
const sdk = await started;
|
|
1533
|
+
this.sdks.set(key, sdk);
|
|
1534
|
+
return sdk;
|
|
1535
|
+
} finally {
|
|
1536
|
+
this.initPromises.delete(key);
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
feeBearingZkConfigNonce(input) {
|
|
1540
|
+
return zkConfigNonceForFeeBearingKind({
|
|
1541
|
+
...input,
|
|
1542
|
+
...configuredNonceSpread(this.zkConfigNonce)
|
|
1543
|
+
});
|
|
1006
1544
|
}
|
|
1007
|
-
async
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1545
|
+
async initializeSdk(nonce) {
|
|
1546
|
+
if (!this.assets) {
|
|
1547
|
+
throw new Error(
|
|
1548
|
+
"PrivacyPoolService requires browser ZK assets before initialization."
|
|
1549
|
+
);
|
|
1011
1550
|
}
|
|
1012
|
-
return
|
|
1551
|
+
return initializePrivacyPoolSdk(
|
|
1552
|
+
{
|
|
1553
|
+
assets: this.assets,
|
|
1554
|
+
...this.zkCircuits ? { zkCircuits: this.zkCircuits } : {},
|
|
1555
|
+
...this.zkConfigNonce === void 0 ? {} : { zkConfigNonce: this.zkConfigNonce },
|
|
1556
|
+
...optionalZkArtifactBaseUrl(this.zkArtifactBaseUrl)
|
|
1557
|
+
},
|
|
1558
|
+
nonce
|
|
1559
|
+
);
|
|
1013
1560
|
}
|
|
1014
1561
|
getAuditPublicKey() {
|
|
1015
1562
|
return this.auditPublicKey;
|
|
@@ -1042,65 +1589,51 @@ var PrivacyPoolService = class {
|
|
|
1042
1589
|
return { commitment_hex, coin, depositScalarHex, precommitementHex };
|
|
1043
1590
|
}
|
|
1044
1591
|
async prepareDepositTransactProof(parameters) {
|
|
1045
|
-
const sdk = await this.getInitializedSdk(
|
|
1046
|
-
|
|
1047
|
-
const recipientPublicKeys = recipientPublicKeysDecimalFromPrivateAddress(
|
|
1048
|
-
parameters.privateAddressStpl1
|
|
1049
|
-
);
|
|
1050
|
-
const applicationId = this.getApplicationId();
|
|
1051
|
-
const audit = buildPoolTransactionAuditParameters({
|
|
1052
|
-
applicationId,
|
|
1053
|
-
nAuditSlots: sdk.getLayout().nAuditSlots,
|
|
1054
|
-
...this.auditPublicKey ? { auditPublicKey: this.auditPublicKey } : {}
|
|
1055
|
-
});
|
|
1056
|
-
const deposit = {
|
|
1057
|
-
value: parameters.coin.value,
|
|
1058
|
-
nullifier: parameters.coin.nullifier,
|
|
1059
|
-
ephemeralKeyScalar: scalarHexToFrDecimal2(parameters.depositScalarHex),
|
|
1060
|
-
asset: [parameters.coin.asset_hi, parameters.coin.asset_lo],
|
|
1061
|
-
applicationId,
|
|
1062
|
-
recipientPublicKeys
|
|
1063
|
-
};
|
|
1064
|
-
const publicInput = withTokenAddressPublicInputs(
|
|
1065
|
-
{
|
|
1066
|
-
stateRoot,
|
|
1067
|
-
privKeyScalar: randomFrDecimal253()
|
|
1068
|
-
},
|
|
1069
|
-
parameters.tokenAddress
|
|
1070
|
-
);
|
|
1071
|
-
const proof = await sdk.proveTransaction(
|
|
1072
|
-
publicInput,
|
|
1073
|
-
padPublicLegsToLayout(
|
|
1074
|
-
sdk,
|
|
1075
|
-
buildPublicDepositLegs(parameters.tokenAddress, parameters.coin.value)
|
|
1076
|
-
),
|
|
1077
|
-
padWithdrawSlotsToLayout(sdk, []),
|
|
1078
|
-
padDepositSlotsToLayout(sdk, [deposit]),
|
|
1079
|
-
audit
|
|
1592
|
+
const sdk = await this.getInitializedSdk(
|
|
1593
|
+
this.feeBearingZkConfigNonce({ kind: "deposit" })
|
|
1080
1594
|
);
|
|
1081
|
-
|
|
1595
|
+
return proveDepositTransact({
|
|
1082
1596
|
sdk,
|
|
1083
|
-
|
|
1084
|
-
|
|
1597
|
+
applicationId: this.getApplicationId(),
|
|
1598
|
+
privateAddressStpl1: parameters.privateAddressStpl1,
|
|
1599
|
+
coin: parameters.coin,
|
|
1600
|
+
depositScalarHex: parameters.depositScalarHex,
|
|
1601
|
+
merkleRootBytes: parameters.merkleRootBytes,
|
|
1602
|
+
tokenAddress: parameters.tokenAddress,
|
|
1603
|
+
buildAlignedDepositSlot: (input) => this.buildAlignedDepositSlot(input),
|
|
1604
|
+
...this.auditPublicKey ? { auditPublicKey: this.auditPublicKey } : {},
|
|
1605
|
+
...parameters.publicDepositStroops === void 0 ? {} : { publicDepositStroops: parameters.publicDepositStroops },
|
|
1606
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
1085
1607
|
});
|
|
1086
|
-
return { ...proof, applicationIdsPlaintext };
|
|
1087
1608
|
}
|
|
1088
1609
|
async calculateNullifierHash(nullifier, privKeyScalar) {
|
|
1089
1610
|
const sdk = await this.getInitializedSdk();
|
|
1090
1611
|
return sdk.calculateNullifierHash(nullifier, privKeyScalar);
|
|
1091
1612
|
}
|
|
1092
1613
|
async prepareWithdrawTransactProof(parameters) {
|
|
1093
|
-
const sdk = await this.getInitializedSdk(
|
|
1614
|
+
const sdk = await this.getInitializedSdk(
|
|
1615
|
+
this.feeBearingZkConfigNonce({ kind: "withdraw" })
|
|
1616
|
+
);
|
|
1094
1617
|
return proveWithdrawTransact({
|
|
1095
1618
|
sdk,
|
|
1096
1619
|
applicationId: this.getApplicationId(),
|
|
1097
1620
|
buildAlignedDepositSlot: (input) => this.buildAlignedDepositSlot(input),
|
|
1098
1621
|
...this.auditPublicKey ? { auditPublicKey: this.auditPublicKey } : {},
|
|
1099
|
-
|
|
1622
|
+
coin: parameters.coin,
|
|
1623
|
+
state: parameters.state,
|
|
1624
|
+
destinationStellarAddress: parameters.destinationStellarAddress,
|
|
1625
|
+
privKeyScalarHex: parameters.privKeyScalarHex,
|
|
1626
|
+
depositorEphemeralKey: parameters.depositorEphemeralKey,
|
|
1627
|
+
withdrawAmountStroops: parameters.withdrawAmountStroops,
|
|
1628
|
+
changePrivateAddressStpl1: parameters.changePrivateAddressStpl1,
|
|
1629
|
+
tokenAddress: parameters.tokenAddress,
|
|
1630
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
1100
1631
|
});
|
|
1101
1632
|
}
|
|
1102
1633
|
async prepareWithdrawTransactProofDual(parameters) {
|
|
1103
|
-
const sdk = await this.getInitializedSdk(
|
|
1634
|
+
const sdk = await this.getInitializedSdk(
|
|
1635
|
+
this.feeBearingZkConfigNonce({ kind: "withdraw" })
|
|
1636
|
+
);
|
|
1104
1637
|
return proveWithdrawTransactDual({
|
|
1105
1638
|
sdk,
|
|
1106
1639
|
applicationId: this.getApplicationId(),
|
|
@@ -1115,7 +1648,8 @@ var PrivacyPoolService = class {
|
|
|
1115
1648
|
ephemeralBKey: parameters.depositorEphemeralBKey,
|
|
1116
1649
|
withdrawAmountStroops: parameters.withdrawAmountStroops,
|
|
1117
1650
|
changePrivateAddressStpl1: parameters.changePrivateAddressStpl1,
|
|
1118
|
-
tokenAddress: parameters.tokenAddress
|
|
1651
|
+
tokenAddress: parameters.tokenAddress,
|
|
1652
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
1119
1653
|
});
|
|
1120
1654
|
}
|
|
1121
1655
|
};
|
|
@@ -1134,6 +1668,7 @@ function createPrivacyPoolService(input) {
|
|
|
1134
1668
|
var configuredPrivacyPoolService;
|
|
1135
1669
|
function configurePrivacyPoolService(service) {
|
|
1136
1670
|
configuredPrivacyPoolService = service;
|
|
1671
|
+
registerMerkleSessionSdkHost(service);
|
|
1137
1672
|
}
|
|
1138
1673
|
function getPrivacyPoolService() {
|
|
1139
1674
|
if (!configuredPrivacyPoolService) {
|
|
@@ -1820,7 +2355,7 @@ async function requestKytPassageForPoolInteraction(input) {
|
|
|
1820
2355
|
const applicationId = resolvePoolApplicationId(
|
|
1821
2356
|
input.transactEnvironment.network.applicationId
|
|
1822
2357
|
);
|
|
1823
|
-
const zkConfigNonce = resolveZkConfigNonce(input.transactEnvironment);
|
|
2358
|
+
const zkConfigNonce = input.zkConfigNonce ?? resolveZkConfigNonce(input.transactEnvironment);
|
|
1824
2359
|
const applicationIdsPlaintext = input.applicationIdsPlaintext ?? buildApplicationIdHints2(
|
|
1825
2360
|
applicationId,
|
|
1826
2361
|
layoutForKnownNonce(zkConfigNonce).nAuditSlots
|
|
@@ -1933,6 +2468,7 @@ async function inspectRelayerSweepKyt(input) {
|
|
|
1933
2468
|
...input.prepared.transactArtifacts?.applicationIdsPlaintext ? {
|
|
1934
2469
|
applicationIdsPlaintext: input.prepared.transactArtifacts.applicationIdsPlaintext
|
|
1935
2470
|
} : {},
|
|
2471
|
+
...input.prepared.transactArtifacts?.zkConfigNonce === void 0 ? {} : { zkConfigNonce: input.prepared.transactArtifacts.zkConfigNonce },
|
|
1936
2472
|
networkPassphrase: environment.network.networkPassphrase,
|
|
1937
2473
|
sorobanRpcUrl: environment.network.rpcUrl,
|
|
1938
2474
|
transactEnvironment: environment
|
|
@@ -1945,7 +2481,10 @@ async function simulateSweepAuthEntries(input) {
|
|
|
1945
2481
|
const operation = new Contract(environment.network.poolContract).call(
|
|
1946
2482
|
"transact",
|
|
1947
2483
|
new Address3(input.relayerPublicKey).toScVal(),
|
|
1948
|
-
nativeToScVal2(
|
|
2484
|
+
nativeToScVal2(
|
|
2485
|
+
transactNonceFromArtifacts(input.prepared.transactArtifacts, environment),
|
|
2486
|
+
{ type: "u64" }
|
|
2487
|
+
),
|
|
1949
2488
|
nativeToScVal2(hexToBytes(input.artifacts.proofHex), { type: "bytes" }),
|
|
1950
2489
|
nativeToScVal2(hexToBytes(input.artifacts.publicHex), { type: "bytes" }),
|
|
1951
2490
|
nativeToScVal2(hexToBytes(input.artifacts.ciphertextHex ?? ""), { type: "bytes" }),
|
|
@@ -1982,6 +2521,7 @@ async function unsignedEscrowAuthorizationForSweep(input) {
|
|
|
1982
2521
|
});
|
|
1983
2522
|
const auth = await simulateSweepAuthEntries({
|
|
1984
2523
|
artifacts,
|
|
2524
|
+
prepared: input.prepared,
|
|
1985
2525
|
transactEnvironment: input.transactEnvironment,
|
|
1986
2526
|
relayerPublicKey,
|
|
1987
2527
|
approval
|
|
@@ -2013,15 +2553,15 @@ async function loadDefaultStellarBrowserAssets(options) {
|
|
|
2013
2553
|
}
|
|
2014
2554
|
|
|
2015
2555
|
// src/transact/private-address/temporary-recipient.ts
|
|
2016
|
-
import { PrivacyPoolSDK as
|
|
2556
|
+
import { PrivacyPoolSDK as PrivacyPoolSDK4 } from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
2017
2557
|
var COORDINATE_HEX_LENGTH2 = 64;
|
|
2018
2558
|
async function generateRandomDepositScalarHex() {
|
|
2019
2559
|
await getPrivacyPoolService().getInitializedSdk();
|
|
2020
|
-
return
|
|
2560
|
+
return PrivacyPoolSDK4.generateRandomScalarHex32();
|
|
2021
2561
|
}
|
|
2022
2562
|
async function generateTemporaryRecipientPrivateAddress() {
|
|
2023
2563
|
await getPrivacyPoolService().getInitializedSdk();
|
|
2024
|
-
const temporaryScalarHex =
|
|
2564
|
+
const temporaryScalarHex = PrivacyPoolSDK4.generateRandomScalarHex32();
|
|
2025
2565
|
const sdk = await getPrivacyPoolService().getInitializedSdk();
|
|
2026
2566
|
const point = sdk.ecdhEphemeralPublicKeyFromScalarHex(temporaryScalarHex);
|
|
2027
2567
|
const publicKeyXHex = point.x.padStart(COORDINATE_HEX_LENGTH2, "0");
|
|
@@ -2290,6 +2830,10 @@ async function submitSorobanConfidentialTransfer(input) {
|
|
|
2290
2830
|
networkPassphrase: input.networkPassphrase,
|
|
2291
2831
|
sorobanRpcUrl: input.sorobanRpcUrl
|
|
2292
2832
|
});
|
|
2833
|
+
const nonce = transactNonceFromArtifacts(
|
|
2834
|
+
input.zkConfigNonce === void 0 ? void 0 : { zkConfigNonce: input.zkConfigNonce },
|
|
2835
|
+
input.transactEnvironment
|
|
2836
|
+
);
|
|
2293
2837
|
const approval = await requestKytPassageForPoolInteraction({
|
|
2294
2838
|
owner: input.walletPublicKey,
|
|
2295
2839
|
poolContract: input.contractId,
|
|
@@ -2298,6 +2842,7 @@ async function submitSorobanConfidentialTransfer(input) {
|
|
|
2298
2842
|
...input.ciphertextHex ? { ciphertextHex: input.ciphertextHex } : {},
|
|
2299
2843
|
...input.outputNoteEphemeralScalars ? { outputNoteEphemeralScalars: input.outputNoteEphemeralScalars } : {},
|
|
2300
2844
|
...input.applicationIdsPlaintext ? { applicationIdsPlaintext: input.applicationIdsPlaintext } : {},
|
|
2845
|
+
...input.zkConfigNonce === void 0 ? {} : { zkConfigNonce: input.zkConfigNonce },
|
|
2301
2846
|
networkPassphrase: input.networkPassphrase,
|
|
2302
2847
|
sorobanRpcUrl: input.sorobanRpcUrl,
|
|
2303
2848
|
transactEnvironment: input.transactEnvironment
|
|
@@ -2306,7 +2851,7 @@ async function submitSorobanConfidentialTransfer(input) {
|
|
|
2306
2851
|
contractClient: poolClient,
|
|
2307
2852
|
contractId: input.contractId,
|
|
2308
2853
|
from: input.walletPublicKey,
|
|
2309
|
-
nonce
|
|
2854
|
+
nonce,
|
|
2310
2855
|
proofHex: input.proofHex,
|
|
2311
2856
|
publicHex: input.publicHex,
|
|
2312
2857
|
...input.ciphertextHex ? { ciphertextHex: input.ciphertextHex } : {},
|
|
@@ -2328,9 +2873,6 @@ function escrowOutputFields(input) {
|
|
|
2328
2873
|
recipientLo: input.escrowSend.recipientLo
|
|
2329
2874
|
};
|
|
2330
2875
|
}
|
|
2331
|
-
function paddingDepositPair(recipientDeposit) {
|
|
2332
|
-
return [recipientDeposit, "dummy"];
|
|
2333
|
-
}
|
|
2334
2876
|
async function buildChangeDepositPair(parameters) {
|
|
2335
2877
|
const changeSlot = await getPrivacyPoolService().buildAlignedDepositSlot({
|
|
2336
2878
|
privateAddressStpl1: parameters.selfPrivateAddressStpl1ForChange.trim(),
|
|
@@ -2347,34 +2889,54 @@ async function buildChangeDepositPair(parameters) {
|
|
|
2347
2889
|
}
|
|
2348
2890
|
};
|
|
2349
2891
|
}
|
|
2892
|
+
function recipientOnlyDeposits(recipientDeposit, hasFeeOutput) {
|
|
2893
|
+
if (hasFeeOutput) {
|
|
2894
|
+
return [recipientDeposit];
|
|
2895
|
+
}
|
|
2896
|
+
return [recipientDeposit, "dummy"];
|
|
2897
|
+
}
|
|
2898
|
+
async function depositsWithoutFee(input) {
|
|
2899
|
+
if (input.changeStroops <= ZERO_STROOPS) {
|
|
2900
|
+
return {
|
|
2901
|
+
deposits: recipientOnlyDeposits(input.recipientDeposit, input.hasFeeOutput)
|
|
2902
|
+
};
|
|
2903
|
+
}
|
|
2904
|
+
return buildChangeDepositPair({
|
|
2905
|
+
selfPrivateAddressStpl1ForChange: input.selfPrivateAddressStpl1ForChange,
|
|
2906
|
+
changeStroops: input.changeStroops,
|
|
2907
|
+
tokenAddress: input.tokenAddress,
|
|
2908
|
+
recipientDeposit: input.recipientDeposit
|
|
2909
|
+
});
|
|
2910
|
+
}
|
|
2350
2911
|
async function buildRecipientAndOptionalChangeDeposits(parameters) {
|
|
2351
2912
|
const escrow = {
|
|
2352
2913
|
...parameters.escrowSend ? { escrowSend: parameters.escrowSend } : {},
|
|
2353
2914
|
...parameters.escrowClaimantLimbs ? { escrowClaimantLimbs: parameters.escrowClaimantLimbs } : {}
|
|
2354
2915
|
};
|
|
2355
|
-
const recipientPrivateAddress = parameters.recipientPrivateAddressStpl1.trim();
|
|
2356
2916
|
const recipientSlot = await getPrivacyPoolService().buildAlignedDepositSlot({
|
|
2357
|
-
privateAddressStpl1:
|
|
2917
|
+
privateAddressStpl1: parameters.recipientPrivateAddressStpl1.trim(),
|
|
2358
2918
|
amountStroops: parameters.transferStroops,
|
|
2359
2919
|
tokenAddress: parameters.tokenAddress,
|
|
2360
2920
|
...escrowOutputFields(escrow)
|
|
2361
2921
|
});
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
recipientSlot,
|
|
2365
|
-
deposits: paddingDepositPair(recipientSlot.deposit)
|
|
2366
|
-
};
|
|
2367
|
-
}
|
|
2368
|
-
const changeResult = await buildChangeDepositPair({
|
|
2369
|
-
selfPrivateAddressStpl1ForChange: parameters.selfPrivateAddressStpl1ForChange,
|
|
2922
|
+
const withoutFee = await depositsWithoutFee({
|
|
2923
|
+
recipientDeposit: recipientSlot.deposit,
|
|
2370
2924
|
changeStroops: parameters.changeStroops,
|
|
2925
|
+
selfPrivateAddressStpl1ForChange: parameters.selfPrivateAddressStpl1ForChange,
|
|
2926
|
+
tokenAddress: parameters.tokenAddress,
|
|
2927
|
+
hasFeeOutput: (parameters.feeOutput?.requiredFee ?? ZERO_STROOPS) > ZERO_STROOPS
|
|
2928
|
+
});
|
|
2929
|
+
const withFee = await appendFeeOutputSlot({
|
|
2930
|
+
deposits: withoutFee.deposits,
|
|
2371
2931
|
tokenAddress: parameters.tokenAddress,
|
|
2372
|
-
|
|
2932
|
+
buildAlignedDepositSlot: (aligned) => getPrivacyPoolService().buildAlignedDepositSlot(aligned),
|
|
2933
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
2373
2934
|
});
|
|
2374
2935
|
return {
|
|
2375
2936
|
recipientSlot,
|
|
2376
|
-
deposits:
|
|
2377
|
-
changeCoin:
|
|
2937
|
+
deposits: withFee.deposits,
|
|
2938
|
+
..."changeCoin" in withoutFee ? { changeCoin: withoutFee.changeCoin } : {},
|
|
2939
|
+
...withFee.feeCoin ? { feeCoin: withFee.feeCoin } : {}
|
|
2378
2940
|
};
|
|
2379
2941
|
}
|
|
2380
2942
|
|
|
@@ -2427,14 +2989,15 @@ function sweepOutputOwnerFields(parameters) {
|
|
|
2427
2989
|
return { sweepOutputOwnerPubX, sweepOutputOwnerPubY };
|
|
2428
2990
|
}
|
|
2429
2991
|
async function buildTransferDepositsAndPublicInput(parameters) {
|
|
2430
|
-
const { recipientSlot, deposits, changeCoin } = await buildRecipientAndOptionalChangeDeposits({
|
|
2992
|
+
const { recipientSlot, deposits, changeCoin, feeCoin } = await buildRecipientAndOptionalChangeDeposits({
|
|
2431
2993
|
recipientPrivateAddressStpl1: parameters.recipientPrivateAddressStpl1,
|
|
2432
2994
|
transferStroops: parameters.transferStroops,
|
|
2433
2995
|
changeStroops: parameters.changeStroops,
|
|
2434
2996
|
selfPrivateAddressStpl1ForChange: parameters.selfPrivateAddressStpl1ForChange,
|
|
2435
2997
|
tokenAddress: parameters.tokenAddress,
|
|
2436
2998
|
...parameters.escrowSend ? { escrowSend: parameters.escrowSend } : {},
|
|
2437
|
-
...parameters.escrowClaimantLimbs ? { escrowClaimantLimbs: parameters.escrowClaimantLimbs } : {}
|
|
2999
|
+
...parameters.escrowClaimantLimbs ? { escrowClaimantLimbs: parameters.escrowClaimantLimbs } : {},
|
|
3000
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
2438
3001
|
});
|
|
2439
3002
|
const publicInput = withTokenAddressPublicInputs(
|
|
2440
3003
|
{
|
|
@@ -2449,6 +3012,7 @@ async function buildTransferDepositsAndPublicInput(parameters) {
|
|
|
2449
3012
|
recipientSlot,
|
|
2450
3013
|
deposits,
|
|
2451
3014
|
...changeCoin ? { changeCoin } : {},
|
|
3015
|
+
...feeCoin ? { feeCoin } : {},
|
|
2452
3016
|
publicInput
|
|
2453
3017
|
};
|
|
2454
3018
|
}
|
|
@@ -2464,7 +3028,8 @@ async function buildSenderTransferDepositsAndPublicInput(parameters) {
|
|
|
2464
3028
|
parameters.senderPrivKeyScalarHex
|
|
2465
3029
|
),
|
|
2466
3030
|
...parameters.escrowSend ? { escrowSend: parameters.escrowSend } : {},
|
|
2467
|
-
...parameters.escrowClaimantLimbs ? { escrowClaimantLimbs: parameters.escrowClaimantLimbs } : {}
|
|
3031
|
+
...parameters.escrowClaimantLimbs ? { escrowClaimantLimbs: parameters.escrowClaimantLimbs } : {},
|
|
3032
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
2468
3033
|
});
|
|
2469
3034
|
}
|
|
2470
3035
|
|
|
@@ -2488,11 +3053,20 @@ function stampDualWithdrawLegs(legs, parameters) {
|
|
|
2488
3053
|
}
|
|
2489
3054
|
};
|
|
2490
3055
|
}
|
|
2491
|
-
function buildDualTransferApplicationIds(sdk, applicationId, changeCoin) {
|
|
3056
|
+
function buildDualTransferApplicationIds(sdk, applicationId, changeCoin, feeCoin) {
|
|
3057
|
+
const outputIds = [applicationId];
|
|
3058
|
+
if (changeCoin) {
|
|
3059
|
+
outputIds.push(applicationId);
|
|
3060
|
+
} else if (!feeCoin) {
|
|
3061
|
+
outputIds.push("0");
|
|
3062
|
+
}
|
|
3063
|
+
if (feeCoin) {
|
|
3064
|
+
outputIds.push(applicationId);
|
|
3065
|
+
}
|
|
2492
3066
|
return buildApplicationIdHints({
|
|
2493
3067
|
sdk,
|
|
2494
3068
|
inputIds: [applicationId, applicationId],
|
|
2495
|
-
outputIds
|
|
3069
|
+
outputIds
|
|
2496
3070
|
});
|
|
2497
3071
|
}
|
|
2498
3072
|
async function proveDualConfidentialTransfer(parameters) {
|
|
@@ -2512,16 +3086,24 @@ async function proveDualConfidentialTransfer(parameters) {
|
|
|
2512
3086
|
audit
|
|
2513
3087
|
);
|
|
2514
3088
|
}
|
|
2515
|
-
|
|
3089
|
+
function dualTransferChangeStroops(parameters) {
|
|
2516
3090
|
const totalNotes = BigInt(parameters.coinA.value) + BigInt(parameters.coinB.value);
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
3091
|
+
if (parameters.transferStroops < MIN_CONFIDENTIAL_TRANSFER_STROOPS) {
|
|
3092
|
+
throw new Error("Transfer amount must be positive");
|
|
3093
|
+
}
|
|
3094
|
+
const changeStroops = remainingAfterRequiredFee({
|
|
3095
|
+
available: totalNotes,
|
|
3096
|
+
instructed: parameters.transferStroops,
|
|
3097
|
+
requiredFee: parameters.feeOutput?.requiredFee ?? 0n
|
|
3098
|
+
});
|
|
2521
3099
|
requireChangeRecipientWhenPartial(
|
|
2522
3100
|
changeStroops,
|
|
2523
3101
|
parameters.selfPrivateAddressStpl1ForChange
|
|
2524
3102
|
);
|
|
3103
|
+
return changeStroops;
|
|
3104
|
+
}
|
|
3105
|
+
async function buildDualTransferProofContext(parameters, applicationId, sdk) {
|
|
3106
|
+
const changeStroops = dualTransferChangeStroops(parameters);
|
|
2525
3107
|
const privKeyScalar = privKeyScalarDecimalFromRecipientScalarHex(
|
|
2526
3108
|
parameters.senderPrivKeyScalarHex
|
|
2527
3109
|
);
|
|
@@ -2548,15 +3130,21 @@ async function buildDualTransferProofContext(parameters, applicationId, sdk) {
|
|
|
2548
3130
|
selfPrivateAddressStpl1ForChange: parameters.selfPrivateAddressStpl1ForChange,
|
|
2549
3131
|
tokenAddress: parameters.tokenAddress,
|
|
2550
3132
|
stateRoot: legA.witness.stateRoot,
|
|
2551
|
-
...confidentialEscrowFields(parameters)
|
|
3133
|
+
...confidentialEscrowFields(parameters),
|
|
3134
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
2552
3135
|
});
|
|
2553
3136
|
return { legA, legB, applicationId, ...transferInputs };
|
|
2554
3137
|
}
|
|
2555
3138
|
async function prepareConfidentialTransferProofDual(parameters) {
|
|
2556
3139
|
const poolService = getPrivacyPoolService();
|
|
2557
|
-
const sdk = await poolService.getInitializedSdk(
|
|
3140
|
+
const sdk = await poolService.getInitializedSdk(
|
|
3141
|
+
poolService.feeBearingZkConfigNonce({
|
|
3142
|
+
kind: "transfer",
|
|
3143
|
+
...parameters.escrowClaimantLimbs ? { spendSource: "escrow" } : {}
|
|
3144
|
+
})
|
|
3145
|
+
);
|
|
2558
3146
|
const applicationId = poolService.getApplicationId();
|
|
2559
|
-
const { legA, legB, recipientSlot, deposits, changeCoin, publicInput } = await buildDualTransferProofContext(parameters, applicationId, sdk);
|
|
3147
|
+
const { legA, legB, recipientSlot, deposits, changeCoin, feeCoin, publicInput } = await buildDualTransferProofContext(parameters, applicationId, sdk);
|
|
2560
3148
|
const auditPublicKey = poolService.getAuditPublicKey();
|
|
2561
3149
|
const proof = await (auditPublicKey ? proveDualConfidentialTransfer({
|
|
2562
3150
|
sdk,
|
|
@@ -2579,7 +3167,8 @@ async function prepareConfidentialTransferProofDual(parameters) {
|
|
|
2579
3167
|
applicationIdsPlaintext: buildDualTransferApplicationIds(
|
|
2580
3168
|
sdk,
|
|
2581
3169
|
applicationId,
|
|
2582
|
-
changeCoin
|
|
3170
|
+
changeCoin,
|
|
3171
|
+
feeCoin
|
|
2583
3172
|
),
|
|
2584
3173
|
recipientCoin: generatedOutputCoinFromSlot(recipientSlot),
|
|
2585
3174
|
...changeCoin ? { changeCoin } : {}
|
|
@@ -2587,22 +3176,32 @@ async function prepareConfidentialTransferProofDual(parameters) {
|
|
|
2587
3176
|
}
|
|
2588
3177
|
|
|
2589
3178
|
// src/transact/proofs/confidential/single.ts
|
|
2590
|
-
function validateSingleCoinTransferAmounts(transferStroops, noteStroops, selfPrivateAddressStpl1ForChange) {
|
|
3179
|
+
function validateSingleCoinTransferAmounts(transferStroops, noteStroops, selfPrivateAddressStpl1ForChange, requiredFee) {
|
|
2591
3180
|
if (transferStroops < MIN_CONFIDENTIAL_TRANSFER_STROOPS) {
|
|
2592
3181
|
throw new Error("Transfer amount must be positive");
|
|
2593
3182
|
}
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
3183
|
+
const changeStroops = remainingAfterRequiredFee({
|
|
3184
|
+
available: noteStroops,
|
|
3185
|
+
instructed: transferStroops,
|
|
3186
|
+
requiredFee
|
|
3187
|
+
});
|
|
2598
3188
|
requireChangeRecipientWhenPartial(changeStroops, selfPrivateAddressStpl1ForChange);
|
|
2599
3189
|
return changeStroops;
|
|
2600
3190
|
}
|
|
2601
|
-
function buildSingleTransferApplicationIds(sdk, applicationId, changeCoin) {
|
|
3191
|
+
function buildSingleTransferApplicationIds(sdk, applicationId, changeCoin, feeCoin) {
|
|
3192
|
+
const outputIds = [applicationId];
|
|
3193
|
+
if (changeCoin) {
|
|
3194
|
+
outputIds.push(applicationId);
|
|
3195
|
+
} else if (!feeCoin) {
|
|
3196
|
+
outputIds.push("0");
|
|
3197
|
+
}
|
|
3198
|
+
if (feeCoin) {
|
|
3199
|
+
outputIds.push(applicationId);
|
|
3200
|
+
}
|
|
2602
3201
|
return buildApplicationIdHints({
|
|
2603
3202
|
sdk,
|
|
2604
3203
|
inputIds: [applicationId],
|
|
2605
|
-
outputIds
|
|
3204
|
+
outputIds
|
|
2606
3205
|
});
|
|
2607
3206
|
}
|
|
2608
3207
|
function buildTransferAuditParameters(parameters) {
|
|
@@ -2628,11 +3227,25 @@ function confidentialEscrowFields2(input) {
|
|
|
2628
3227
|
...input.escrowClaimantLimbs ? { escrowClaimantLimbs: input.escrowClaimantLimbs } : {}
|
|
2629
3228
|
};
|
|
2630
3229
|
}
|
|
3230
|
+
function transferDepositInputFromProof(input, changeStroops, stateRoot) {
|
|
3231
|
+
return {
|
|
3232
|
+
senderPrivKeyScalarHex: input.senderPrivKeyScalarHex,
|
|
3233
|
+
recipientPrivateAddressStpl1: input.recipientPrivateAddressStpl1,
|
|
3234
|
+
transferStroops: input.transferStroops,
|
|
3235
|
+
changeStroops,
|
|
3236
|
+
selfPrivateAddressStpl1ForChange: input.selfPrivateAddressStpl1ForChange,
|
|
3237
|
+
tokenAddress: input.tokenAddress,
|
|
3238
|
+
stateRoot,
|
|
3239
|
+
...confidentialEscrowFields2(input),
|
|
3240
|
+
...input.feeOutput ? { feeOutput: input.feeOutput } : {}
|
|
3241
|
+
};
|
|
3242
|
+
}
|
|
2631
3243
|
async function buildTransferProofInputs(parameters) {
|
|
2632
3244
|
const changeStroops = validateSingleCoinTransferAmounts(
|
|
2633
3245
|
parameters.input.transferStroops,
|
|
2634
3246
|
parameters.noteStroops,
|
|
2635
|
-
parameters.input.selfPrivateAddressStpl1ForChange
|
|
3247
|
+
parameters.input.selfPrivateAddressStpl1ForChange,
|
|
3248
|
+
parameters.input.feeOutput?.requiredFee ?? 0n
|
|
2636
3249
|
);
|
|
2637
3250
|
const privKeyScalar = privKeyScalarDecimalFromRecipientScalarHex(
|
|
2638
3251
|
parameters.input.senderPrivKeyScalarHex
|
|
@@ -2651,31 +3264,30 @@ async function buildTransferProofInputs(parameters) {
|
|
|
2651
3264
|
withdrawObject,
|
|
2652
3265
|
sweepWithdrawStamp(confidentialEscrowFields2(parameters.input))
|
|
2653
3266
|
);
|
|
2654
|
-
const { recipientSlot, deposits, changeCoin, publicInput } = await buildSenderTransferDepositsAndPublicInput(
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
transferStroops: parameters.input.transferStroops,
|
|
2658
|
-
changeStroops,
|
|
2659
|
-
selfPrivateAddressStpl1ForChange: parameters.input.selfPrivateAddressStpl1ForChange,
|
|
2660
|
-
tokenAddress: parameters.input.tokenAddress,
|
|
2661
|
-
stateRoot: witness.stateRoot,
|
|
2662
|
-
...confidentialEscrowFields2(parameters.input)
|
|
2663
|
-
});
|
|
3267
|
+
const { recipientSlot, deposits, changeCoin, feeCoin, publicInput } = await buildSenderTransferDepositsAndPublicInput(
|
|
3268
|
+
transferDepositInputFromProof(parameters.input, changeStroops, witness.stateRoot)
|
|
3269
|
+
);
|
|
2664
3270
|
return {
|
|
2665
3271
|
witness,
|
|
2666
3272
|
withdrawObject: stampedWithdraw,
|
|
2667
3273
|
recipientSlot,
|
|
2668
3274
|
deposits,
|
|
2669
3275
|
changeCoin,
|
|
3276
|
+
feeCoin,
|
|
2670
3277
|
publicInput
|
|
2671
3278
|
};
|
|
2672
3279
|
}
|
|
2673
3280
|
async function prepareConfidentialTransferProof(parameters) {
|
|
2674
3281
|
const poolService = getPrivacyPoolService();
|
|
2675
|
-
const sdk = await poolService.getInitializedSdk(
|
|
3282
|
+
const sdk = await poolService.getInitializedSdk(
|
|
3283
|
+
poolService.feeBearingZkConfigNonce({
|
|
3284
|
+
kind: "transfer",
|
|
3285
|
+
...parameters.escrowClaimantLimbs ? { spendSource: "escrow" } : {}
|
|
3286
|
+
})
|
|
3287
|
+
);
|
|
2676
3288
|
const applicationId = poolService.getApplicationId();
|
|
2677
3289
|
const noteStroops = BigInt(parameters.coin.value);
|
|
2678
|
-
const { withdrawObject, recipientSlot, deposits, changeCoin, publicInput } = await buildTransferProofInputs({
|
|
3290
|
+
const { withdrawObject, recipientSlot, deposits, changeCoin, feeCoin, publicInput } = await buildTransferProofInputs({
|
|
2679
3291
|
sdk,
|
|
2680
3292
|
applicationId,
|
|
2681
3293
|
input: parameters,
|
|
@@ -2698,7 +3310,8 @@ async function prepareConfidentialTransferProof(parameters) {
|
|
|
2698
3310
|
applicationIdsPlaintext: buildSingleTransferApplicationIds(
|
|
2699
3311
|
sdk,
|
|
2700
3312
|
applicationId,
|
|
2701
|
-
changeCoin
|
|
3313
|
+
changeCoin,
|
|
3314
|
+
feeCoin
|
|
2702
3315
|
),
|
|
2703
3316
|
recipientCoin: generatedOutputCoinFromSlot(recipientSlot),
|
|
2704
3317
|
...changeCoin ? { changeCoin } : {}
|
|
@@ -2713,7 +3326,8 @@ function poolMerkleStateToCachedView(state) {
|
|
|
2713
3326
|
return {
|
|
2714
3327
|
commitments: state.commitments,
|
|
2715
3328
|
updatedAt: state.updatedAt,
|
|
2716
|
-
merkleRootHex: state.merkleRootHex
|
|
3329
|
+
merkleRootHex: state.merkleRootHex,
|
|
3330
|
+
...state.nodes ? { nodes: state.nodes } : {}
|
|
2717
3331
|
};
|
|
2718
3332
|
}
|
|
2719
3333
|
|
|
@@ -2846,6 +3460,65 @@ function reuseCachedCommitments(input) {
|
|
|
2846
3460
|
return cachedCommitments;
|
|
2847
3461
|
}
|
|
2848
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
|
+
|
|
2849
3522
|
// src/transact/merkle/fetch-contract.ts
|
|
2850
3523
|
async function fetchAndMergeMerkleState(parameters) {
|
|
2851
3524
|
const client = createPoolClient(parameters);
|
|
@@ -2938,43 +3611,6 @@ async function loadCommitments(input) {
|
|
|
2938
3611
|
});
|
|
2939
3612
|
return [...reused, ...fetched];
|
|
2940
3613
|
}
|
|
2941
|
-
async function persistFetchedMerkleState(input) {
|
|
2942
|
-
const cachedState = input.cachedState;
|
|
2943
|
-
if (cachedState && cachedMerkleUnchanged(cachedState, input.commitments, input.merkleRootHex)) {
|
|
2944
|
-
return viewFromCachedMerkle(cachedState, input.merkleRootHex);
|
|
2945
|
-
}
|
|
2946
|
-
const updatedAt = Date.now();
|
|
2947
|
-
await input.poolMerkleState?.set({
|
|
2948
|
-
poolContract: input.poolContractId,
|
|
2949
|
-
commitments: input.commitments,
|
|
2950
|
-
commitmentCount: input.commitments.length,
|
|
2951
|
-
merkleRootHex: input.merkleRootHex,
|
|
2952
|
-
updatedAt
|
|
2953
|
-
});
|
|
2954
|
-
return {
|
|
2955
|
-
commitments: input.commitments,
|
|
2956
|
-
updatedAt,
|
|
2957
|
-
merkleRootHex: input.merkleRootHex,
|
|
2958
|
-
commitmentCount: input.commitments.length
|
|
2959
|
-
};
|
|
2960
|
-
}
|
|
2961
|
-
function viewFromCachedMerkle(cachedState, merkleRootHex) {
|
|
2962
|
-
return {
|
|
2963
|
-
commitments: cachedState.commitments,
|
|
2964
|
-
updatedAt: cachedState.updatedAt,
|
|
2965
|
-
merkleRootHex: cachedState.merkleRootHex ?? merkleRootHex,
|
|
2966
|
-
commitmentCount: cachedState.commitments.length
|
|
2967
|
-
};
|
|
2968
|
-
}
|
|
2969
|
-
function cachedMerkleUnchanged(cachedState, commitments, merkleRootHex) {
|
|
2970
|
-
if (!cachedState) {
|
|
2971
|
-
return false;
|
|
2972
|
-
}
|
|
2973
|
-
if ((cachedState.merkleRootHex ?? merkleRootHex) !== merkleRootHex) {
|
|
2974
|
-
return false;
|
|
2975
|
-
}
|
|
2976
|
-
return cachedState.commitments.join(",") === commitments.join(",");
|
|
2977
|
-
}
|
|
2978
3614
|
|
|
2979
3615
|
// src/transact/encoding/fr-decimal-to-bytes.ts
|
|
2980
3616
|
var BN254_SCALAR_MOD = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
|
|
@@ -3087,13 +3723,19 @@ var walletPrivateAddressRecordSchema = z.object({
|
|
|
3087
3723
|
privateAddress: z.string().min(1),
|
|
3088
3724
|
createdAt: z.number()
|
|
3089
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
|
+
});
|
|
3090
3731
|
var poolMerkleStateSchema = z.object({
|
|
3091
3732
|
poolContract: z.string().min(1),
|
|
3092
3733
|
commitments: z.array(z.string()),
|
|
3093
3734
|
commitmentCount: z.number().int().nonnegative(),
|
|
3094
3735
|
merkleRootHex: z.string().min(1),
|
|
3095
3736
|
updatedAt: z.number(),
|
|
3096
|
-
syncedLedger: z.number().int().optional()
|
|
3737
|
+
syncedLedger: z.number().int().optional(),
|
|
3738
|
+
nodes: z.array(leanImtNodeSchema).optional()
|
|
3097
3739
|
});
|
|
3098
3740
|
var leafEphemeralSchema = z.object({
|
|
3099
3741
|
poolContract: z.string().min(1),
|
|
@@ -4506,6 +5148,7 @@ function createPoolMerkleService(context) {
|
|
|
4506
5148
|
async appendPoolCommitments(input) {
|
|
4507
5149
|
const current = await this.getPoolMerkleState(input.poolContract);
|
|
4508
5150
|
const mergedCommitments = [...current?.commitments ?? [], ...input.commitments];
|
|
5151
|
+
const nodes = input.nodes ?? (input.commitments.length === 0 ? current?.nodes : void 0);
|
|
4509
5152
|
await this.setPoolMerkleState(
|
|
4510
5153
|
withoutUndefinedFields({
|
|
4511
5154
|
poolContract: input.poolContract,
|
|
@@ -4513,7 +5156,8 @@ function createPoolMerkleService(context) {
|
|
|
4513
5156
|
commitmentCount: mergedCommitments.length,
|
|
4514
5157
|
merkleRootHex: input.merkleRootHex,
|
|
4515
5158
|
updatedAt: Date.now(),
|
|
4516
|
-
syncedLedger: input.syncedLedger ?? current?.syncedLedger
|
|
5159
|
+
syncedLedger: input.syncedLedger ?? current?.syncedLedger,
|
|
5160
|
+
nodes
|
|
4517
5161
|
})
|
|
4518
5162
|
);
|
|
4519
5163
|
}
|
|
@@ -5042,7 +5686,11 @@ async function loadMerkleState(environment, walletPublicKey) {
|
|
|
5042
5686
|
transactEnvironment: environment,
|
|
5043
5687
|
...environment.poolMerkleState ? { poolMerkleState: environment.poolMerkleState } : {}
|
|
5044
5688
|
});
|
|
5045
|
-
return {
|
|
5689
|
+
return merkleSnapshotToStateFile({
|
|
5690
|
+
commitments: merged.commitments,
|
|
5691
|
+
merkleRootHex: merged.merkleRootHex,
|
|
5692
|
+
...merged.nodes ? { nodes: merged.nodes } : {}
|
|
5693
|
+
});
|
|
5046
5694
|
}
|
|
5047
5695
|
|
|
5048
5696
|
// src/transact/escrow/require-escrow-spend-scalar.ts
|
|
@@ -5189,7 +5837,8 @@ async function buildSpendProofContextAtExecute(input) {
|
|
|
5189
5837
|
input.prepared.intent.asset
|
|
5190
5838
|
);
|
|
5191
5839
|
const coin = requireCoinNoteFromRecord(primaryRecord);
|
|
5192
|
-
const
|
|
5840
|
+
const merkleState = await loadMerkleState(input.environment, walletPublicKey);
|
|
5841
|
+
const commitments = merkleState.commitments;
|
|
5193
5842
|
const leafIndex = findCommitmentLeafIndex(commitments, coin.commitment);
|
|
5194
5843
|
if (leafIndex < 0) {
|
|
5195
5844
|
throw new Error("Coin commitment not found in on-chain Merkle state.");
|
|
@@ -5206,6 +5855,7 @@ async function buildSpendProofContextAtExecute(input) {
|
|
|
5206
5855
|
tokenAddress,
|
|
5207
5856
|
coin,
|
|
5208
5857
|
commitments,
|
|
5858
|
+
merkleState,
|
|
5209
5859
|
ephemeral,
|
|
5210
5860
|
senderPrivKeyScalarHex,
|
|
5211
5861
|
recipientPrivateAddressStpl1: input.recipientPrivateAddressStpl1
|
|
@@ -5263,10 +5913,15 @@ function proofEscrowFields(input) {
|
|
|
5263
5913
|
}
|
|
5264
5914
|
async function buildSingleTransferProofAtExecute(input) {
|
|
5265
5915
|
const context = await buildSpendProofContextAtExecute(input);
|
|
5266
|
-
const
|
|
5916
|
+
const feeOutput = await quoteFeeOutputForPrepared({
|
|
5917
|
+
prepared: input.prepared,
|
|
5918
|
+
environment: input.environment,
|
|
5919
|
+
tokenAddress: context.tokenAddress
|
|
5920
|
+
});
|
|
5921
|
+
const changeStroops = BigInt(context.coin.value) - input.prepared.intent.amount - (feeOutput?.requiredFee ?? 0n);
|
|
5267
5922
|
const proof = await prepareConfidentialTransferProof({
|
|
5268
5923
|
coin: context.coin,
|
|
5269
|
-
state:
|
|
5924
|
+
state: context.merkleState,
|
|
5270
5925
|
senderPrivKeyScalarHex: context.senderPrivKeyScalarHex,
|
|
5271
5926
|
depositorEphemeralKey: serializeEphemeralKeyString({
|
|
5272
5927
|
xHex: context.ephemeral.xHex,
|
|
@@ -5276,7 +5931,8 @@ async function buildSingleTransferProofAtExecute(input) {
|
|
|
5276
5931
|
recipientPrivateAddressStpl1: context.recipientPrivateAddressStpl1,
|
|
5277
5932
|
selfPrivateAddressStpl1ForChange: readChangeRecipient(input, changeStroops),
|
|
5278
5933
|
tokenAddress: context.tokenAddress,
|
|
5279
|
-
...proofEscrowFields(input)
|
|
5934
|
+
...proofEscrowFields(input),
|
|
5935
|
+
...feeOutput ? { feeOutput } : {}
|
|
5280
5936
|
});
|
|
5281
5937
|
return { context, proof };
|
|
5282
5938
|
}
|
|
@@ -5293,11 +5949,16 @@ async function buildDualTransferProofAtExecute(input) {
|
|
|
5293
5949
|
commitments: context.commitments
|
|
5294
5950
|
});
|
|
5295
5951
|
const totalNotes = BigInt(context.coin.value) + BigInt(secondary.coin.value);
|
|
5296
|
-
const
|
|
5952
|
+
const feeOutput = await quoteFeeOutputForPrepared({
|
|
5953
|
+
prepared: input.prepared,
|
|
5954
|
+
environment: input.environment,
|
|
5955
|
+
tokenAddress: context.tokenAddress
|
|
5956
|
+
});
|
|
5957
|
+
const changeStroops = totalNotes - input.prepared.intent.amount - (feeOutput?.requiredFee ?? 0n);
|
|
5297
5958
|
const proof = await prepareConfidentialTransferProofDual({
|
|
5298
5959
|
coinA: context.coin,
|
|
5299
5960
|
coinB: secondary.coin,
|
|
5300
|
-
state:
|
|
5961
|
+
state: context.merkleState,
|
|
5301
5962
|
senderPrivKeyScalarHex: context.senderPrivKeyScalarHex,
|
|
5302
5963
|
ephemeralAKey: serializeEphemeralKeyString({
|
|
5303
5964
|
xHex: context.ephemeral.xHex,
|
|
@@ -5311,7 +5972,8 @@ async function buildDualTransferProofAtExecute(input) {
|
|
|
5311
5972
|
recipientPrivateAddressStpl1: context.recipientPrivateAddressStpl1,
|
|
5312
5973
|
selfPrivateAddressStpl1ForChange: readChangeRecipient(input, changeStroops),
|
|
5313
5974
|
tokenAddress: context.tokenAddress,
|
|
5314
|
-
...proofEscrowFields(input)
|
|
5975
|
+
...proofEscrowFields(input),
|
|
5976
|
+
...feeOutput ? { feeOutput } : {}
|
|
5315
5977
|
});
|
|
5316
5978
|
return { context, proof };
|
|
5317
5979
|
}
|
|
@@ -5443,11 +6105,17 @@ async function runTransferFinalizeSteps(input) {
|
|
|
5443
6105
|
walletPublicKey: input.walletPublicKey,
|
|
5444
6106
|
...recipient.escrowSend ? { escrowSendPrivateAddress: recipient.recipientPrivateAddressStpl1 } : {}
|
|
5445
6107
|
});
|
|
5446
|
-
return
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
6108
|
+
return {
|
|
6109
|
+
...buildTransferFinalizeArtifacts({
|
|
6110
|
+
proof,
|
|
6111
|
+
context,
|
|
6112
|
+
...sweepFinalizeStamp(input.prepared, recipient)
|
|
6113
|
+
}),
|
|
6114
|
+
zkConfigNonce: zkConfigNonceForFeeBearingKind({
|
|
6115
|
+
...feeOutputKindFromPrepared(input.prepared),
|
|
6116
|
+
...configuredNonceSpread(input.environment.zkConfigNonce)
|
|
6117
|
+
})
|
|
6118
|
+
};
|
|
5451
6119
|
}
|
|
5452
6120
|
function sweepArtifactStamp(artifacts) {
|
|
5453
6121
|
return {
|
|
@@ -5475,6 +6143,24 @@ async function finalizeTransferAtExecute(prepared, environment) {
|
|
|
5475
6143
|
return runTransferFinalizeSteps({ prepared, environment, walletPublicKey });
|
|
5476
6144
|
}
|
|
5477
6145
|
|
|
6146
|
+
// src/transact/engine/withdraw-fee.ts
|
|
6147
|
+
async function withdrawFeeProofFields(input) {
|
|
6148
|
+
const feeOutput = await quoteFeeOutputForPrepared({
|
|
6149
|
+
prepared: input.prepared,
|
|
6150
|
+
environment: input.environment,
|
|
6151
|
+
tokenAddress: input.tokenAddress
|
|
6152
|
+
});
|
|
6153
|
+
const changeStroops = remainingAfterRequiredFee({
|
|
6154
|
+
available: input.available,
|
|
6155
|
+
instructed: input.prepared.intent.amount,
|
|
6156
|
+
requiredFee: feeOutput?.requiredFee ?? 0n
|
|
6157
|
+
});
|
|
6158
|
+
return {
|
|
6159
|
+
...feeOutput ? { feeOutput } : {},
|
|
6160
|
+
...changeStroops > 0n ? { changePrivateAddressStpl1: input.withdrawFrom } : {}
|
|
6161
|
+
};
|
|
6162
|
+
}
|
|
6163
|
+
|
|
5478
6164
|
// src/transact/engine/execute.ts
|
|
5479
6165
|
function enrichWithdrawOutputRecords(prepared, proof) {
|
|
5480
6166
|
if (!proof.changeCoin || prepared.outputRecords.length === 0) {
|
|
@@ -5490,7 +6176,7 @@ function enrichWithdrawOutputRecords(prepared, proof) {
|
|
|
5490
6176
|
precommitementHex: changeCoin.precommitementHex
|
|
5491
6177
|
}));
|
|
5492
6178
|
}
|
|
5493
|
-
function buildWithdrawFinalizeArtifacts(proof, context) {
|
|
6179
|
+
function buildWithdrawFinalizeArtifacts(proof, context, environment) {
|
|
5494
6180
|
return {
|
|
5495
6181
|
proofHex: proof.proof_hex,
|
|
5496
6182
|
publicHex: proof.public_hex,
|
|
@@ -5498,7 +6184,11 @@ function buildWithdrawFinalizeArtifacts(proof, context) {
|
|
|
5498
6184
|
applicationIdsPlaintext: proof.applicationIdsPlaintext,
|
|
5499
6185
|
tokenAddress: context.tokenAddress,
|
|
5500
6186
|
walletPublicKey: context.walletPublicKey,
|
|
5501
|
-
executeFinalizeRequired: false
|
|
6187
|
+
executeFinalizeRequired: false,
|
|
6188
|
+
zkConfigNonce: zkConfigNonceForFeeBearingKind({
|
|
6189
|
+
kind: "withdraw",
|
|
6190
|
+
...configuredNonceSpread(environment.zkConfigNonce)
|
|
6191
|
+
})
|
|
5502
6192
|
};
|
|
5503
6193
|
}
|
|
5504
6194
|
async function finalizeSingleWithdrawAtExecute(prepared, environment, poolService, withdrawFrom) {
|
|
@@ -5507,10 +6197,16 @@ async function finalizeSingleWithdrawAtExecute(prepared, environment, poolServic
|
|
|
5507
6197
|
environment,
|
|
5508
6198
|
recipientPrivateAddressStpl1: withdrawFrom
|
|
5509
6199
|
});
|
|
5510
|
-
const
|
|
6200
|
+
const feeFields = await withdrawFeeProofFields({
|
|
6201
|
+
prepared,
|
|
6202
|
+
environment,
|
|
6203
|
+
tokenAddress: context.tokenAddress,
|
|
6204
|
+
available: BigInt(context.coin.value),
|
|
6205
|
+
withdrawFrom
|
|
6206
|
+
});
|
|
5511
6207
|
const proof = await poolService.prepareWithdrawTransactProof({
|
|
5512
6208
|
coin: context.coin,
|
|
5513
|
-
state:
|
|
6209
|
+
state: context.merkleState,
|
|
5514
6210
|
destinationStellarAddress: prepared.intent.to,
|
|
5515
6211
|
privKeyScalarHex: context.senderPrivKeyScalarHex,
|
|
5516
6212
|
depositorEphemeralKey: serializeEphemeralKeyString({
|
|
@@ -5518,11 +6214,24 @@ async function finalizeSingleWithdrawAtExecute(prepared, environment, poolServic
|
|
|
5518
6214
|
yHex: context.ephemeral.yHex
|
|
5519
6215
|
}),
|
|
5520
6216
|
withdrawAmountStroops: prepared.intent.amount,
|
|
5521
|
-
changePrivateAddressStpl1:
|
|
5522
|
-
tokenAddress: context.tokenAddress
|
|
6217
|
+
changePrivateAddressStpl1: feeFields.changePrivateAddressStpl1,
|
|
6218
|
+
tokenAddress: context.tokenAddress,
|
|
6219
|
+
...feeFields.feeOutput ? { feeOutput: feeFields.feeOutput } : {}
|
|
5523
6220
|
});
|
|
5524
6221
|
enrichWithdrawOutputRecords(prepared, proof);
|
|
5525
|
-
return buildWithdrawFinalizeArtifacts(proof, context);
|
|
6222
|
+
return buildWithdrawFinalizeArtifacts(proof, context, environment);
|
|
6223
|
+
}
|
|
6224
|
+
function dualWithdrawEphemeralKeys(input) {
|
|
6225
|
+
return {
|
|
6226
|
+
depositorEphemeralAKey: serializeEphemeralKeyString({
|
|
6227
|
+
xHex: input.context.ephemeral.xHex,
|
|
6228
|
+
yHex: input.context.ephemeral.yHex
|
|
6229
|
+
}),
|
|
6230
|
+
depositorEphemeralBKey: serializeEphemeralKeyString({
|
|
6231
|
+
xHex: input.secondary.ephemeral.xHex,
|
|
6232
|
+
yHex: input.secondary.ephemeral.yHex
|
|
6233
|
+
})
|
|
6234
|
+
};
|
|
5526
6235
|
}
|
|
5527
6236
|
async function finalizeDualWithdrawAtExecute(prepared, environment, poolService, withdrawFrom) {
|
|
5528
6237
|
const [, secondaryRecord] = prepared.consumedRecords;
|
|
@@ -5540,28 +6249,27 @@ async function finalizeDualWithdrawAtExecute(prepared, environment, poolService,
|
|
|
5540
6249
|
walletPublicKey: context.walletPublicKey,
|
|
5541
6250
|
commitments: context.commitments
|
|
5542
6251
|
});
|
|
5543
|
-
const
|
|
5544
|
-
|
|
6252
|
+
const feeFields = await withdrawFeeProofFields({
|
|
6253
|
+
prepared,
|
|
6254
|
+
environment,
|
|
6255
|
+
tokenAddress: context.tokenAddress,
|
|
6256
|
+
available: BigInt(context.coin.value) + BigInt(secondary.coin.value),
|
|
6257
|
+
withdrawFrom
|
|
6258
|
+
});
|
|
5545
6259
|
const proof = await poolService.prepareWithdrawTransactProofDual({
|
|
5546
6260
|
coinA: context.coin,
|
|
5547
6261
|
coinB: secondary.coin,
|
|
5548
|
-
state:
|
|
6262
|
+
state: context.merkleState,
|
|
5549
6263
|
destinationStellarAddress: prepared.intent.to,
|
|
5550
6264
|
privKeyScalarHex: context.senderPrivKeyScalarHex,
|
|
5551
|
-
|
|
5552
|
-
xHex: context.ephemeral.xHex,
|
|
5553
|
-
yHex: context.ephemeral.yHex
|
|
5554
|
-
}),
|
|
5555
|
-
depositorEphemeralBKey: serializeEphemeralKeyString({
|
|
5556
|
-
xHex: secondary.ephemeral.xHex,
|
|
5557
|
-
yHex: secondary.ephemeral.yHex
|
|
5558
|
-
}),
|
|
6265
|
+
...dualWithdrawEphemeralKeys({ context, secondary }),
|
|
5559
6266
|
withdrawAmountStroops: prepared.intent.amount,
|
|
5560
|
-
changePrivateAddressStpl1:
|
|
5561
|
-
tokenAddress: context.tokenAddress
|
|
6267
|
+
changePrivateAddressStpl1: feeFields.changePrivateAddressStpl1,
|
|
6268
|
+
tokenAddress: context.tokenAddress,
|
|
6269
|
+
...feeFields.feeOutput ? { feeOutput: feeFields.feeOutput } : {}
|
|
5562
6270
|
});
|
|
5563
6271
|
enrichWithdrawOutputRecords(prepared, proof);
|
|
5564
|
-
return buildWithdrawFinalizeArtifacts(proof, context);
|
|
6272
|
+
return buildWithdrawFinalizeArtifacts(proof, context, environment);
|
|
5565
6273
|
}
|
|
5566
6274
|
async function finalizeWithdrawAtExecute(prepared, environment, poolService) {
|
|
5567
6275
|
if (prepared.kind !== "withdraw") {
|
|
@@ -5787,10 +6495,11 @@ function requirePreparedArtifacts(prepared) {
|
|
|
5787
6495
|
};
|
|
5788
6496
|
}
|
|
5789
6497
|
function prepareRelayTransactPackageFromPrepared(input) {
|
|
6498
|
+
const zkConfigNonce = input.zkConfigNonce ?? input.prepared.transactArtifacts?.zkConfigNonce;
|
|
5790
6499
|
return prepareRelayTransactPackage({
|
|
5791
6500
|
poolSelector: input.poolSelector,
|
|
5792
6501
|
...requirePreparedArtifacts(input.prepared),
|
|
5793
|
-
...
|
|
6502
|
+
...zkConfigNonce === void 0 ? {} : { zkConfigNonce },
|
|
5794
6503
|
...input.keyVersionHints ? { keyVersionHints: input.keyVersionHints } : {}
|
|
5795
6504
|
});
|
|
5796
6505
|
}
|
|
@@ -5900,6 +6609,7 @@ function requiredSubmissionMethod(prepared, zkConfigNonce = DEFAULT_ZK_CONFIG_NO
|
|
|
5900
6609
|
return result.method;
|
|
5901
6610
|
}
|
|
5902
6611
|
export {
|
|
6612
|
+
BINDING_ZK_NONCE,
|
|
5903
6613
|
BundledZkCircuit2 as BundledZkCircuit,
|
|
5904
6614
|
COMMITMENT_V2_ZK_NONCE,
|
|
5905
6615
|
DEFAULT_STEALTH_SIGN_NONCE as DEFAULT_PRIVATE_ADDRESS_SIGN_NONCE,
|
|
@@ -5928,6 +6638,7 @@ export {
|
|
|
5928
6638
|
RELAY_TRANSACT_PACKAGE_VERSION_V1,
|
|
5929
6639
|
RELAY_TRANSACT_SIGNAL_PREFIX_BYTES,
|
|
5930
6640
|
RELAY_TRANSACT_SUPPORTED_SIGNAL_COUNT,
|
|
6641
|
+
SIX_BY_SIX_BINDING_ZK_NONCE,
|
|
5931
6642
|
SIX_BY_SIX_ZK_NONCE,
|
|
5932
6643
|
STANDARD_ZK_CONFIG_NONCE,
|
|
5933
6644
|
SUBMISSION_METHOD,
|