@arcanetech/privacy-sdk-stellar 0.5.2 → 0.5.4
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 +28 -5
- package/dist/index.js +708 -226
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +1 -0
- package/dist/node.js +693 -219
- package/dist/node.js.map +1 -1
- package/dist/testing/index.d.ts +1 -0
- package/dist/transact/index.d.ts +28 -5
- package/dist/transact/index.js +677 -217
- package/dist/transact/index.js.map +1 -1
- package/package.json +6 -6
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) {
|
|
@@ -292,14 +274,144 @@ function requireChangeRecipientWhenPartial(changeStroops, selfPrivateAddressStpl
|
|
|
292
274
|
}
|
|
293
275
|
}
|
|
294
276
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
277
|
+
|
|
278
|
+
// src/transact/fees/quote-request-body.ts
|
|
279
|
+
function presentInstructedAmount(amount) {
|
|
280
|
+
const trimmed = amount?.trim() ?? "";
|
|
281
|
+
if (!trimmed || trimmed === "0") {
|
|
282
|
+
return void 0;
|
|
283
|
+
}
|
|
284
|
+
return trimmed;
|
|
285
|
+
}
|
|
286
|
+
function feeQuoteRequestBody(request) {
|
|
287
|
+
const publicDepositAmount = presentInstructedAmount(request.publicDepositAmount);
|
|
288
|
+
const transferInstructedAmount = presentInstructedAmount(
|
|
289
|
+
request.transferInstructedAmount
|
|
290
|
+
);
|
|
291
|
+
const publicWithdrawalAmount = presentInstructedAmount(
|
|
292
|
+
request.publicWithdrawalAmount
|
|
293
|
+
);
|
|
294
|
+
return {
|
|
295
|
+
feeAsset: request.feeAsset,
|
|
296
|
+
spendsNotes: request.spendsNotes,
|
|
297
|
+
...publicDepositAmount === void 0 ? {} : { publicDepositAmount },
|
|
298
|
+
...transferInstructedAmount === void 0 ? {} : { transferInstructedAmount },
|
|
299
|
+
...publicWithdrawalAmount === void 0 ? {} : { publicWithdrawalAmount }
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// src/transact/fees/quote-required-fee.ts
|
|
304
|
+
function quoteHeaders(inspectAuthorization) {
|
|
305
|
+
const token = inspectAuthorization?.trim();
|
|
306
|
+
return {
|
|
307
|
+
"content-type": "application/json",
|
|
308
|
+
...token ? { authorization: `Bearer ${token}` } : {}
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
function parseRequiredFee(raw) {
|
|
312
|
+
const text = `${raw ?? ""}`.trim();
|
|
313
|
+
if (!/^\d+$/u.test(text)) {
|
|
314
|
+
throw new Error("Fee Quote Required Fee must be an integer minor-unit string.");
|
|
315
|
+
}
|
|
316
|
+
return BigInt(text);
|
|
317
|
+
}
|
|
318
|
+
function requireQuoteString(raw, field) {
|
|
319
|
+
const text = `${raw ?? ""}`.trim();
|
|
320
|
+
if (!text) {
|
|
321
|
+
throw new Error(`Fee Quote is missing ${field}.`);
|
|
322
|
+
}
|
|
323
|
+
return text;
|
|
324
|
+
}
|
|
325
|
+
function parseQuotePayload(payload) {
|
|
326
|
+
return {
|
|
327
|
+
requiredFee: parseRequiredFee(payload.requiredFee),
|
|
328
|
+
feeAsset: requireQuoteString(payload.feeAsset, "Fee Asset"),
|
|
329
|
+
feeCollectorPrivateAddress: requireQuoteString(
|
|
330
|
+
payload.feeCollectorPrivateAddress,
|
|
331
|
+
"Fee Collector Private Address"
|
|
332
|
+
),
|
|
333
|
+
feeRate: requireQuoteString(payload.feeRate, "Fee Rate")
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
async function quoteRequiredFee(input) {
|
|
337
|
+
const response = await fetch(
|
|
338
|
+
`${input.transactEnvironment.kyt.apiBaseUrl}/kyt/fees/quote`,
|
|
339
|
+
{
|
|
340
|
+
method: "POST",
|
|
341
|
+
headers: quoteHeaders(input.transactEnvironment.kyt.inspectAuthorization),
|
|
342
|
+
body: JSON.stringify(feeQuoteRequestBody(input.request))
|
|
343
|
+
}
|
|
344
|
+
);
|
|
345
|
+
const payload = await response.json();
|
|
346
|
+
if (!response.ok) {
|
|
347
|
+
throw new Error(`Fee Quote failed: ${JSON.stringify(payload)}`);
|
|
348
|
+
}
|
|
349
|
+
return parseQuotePayload(payload);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// src/transact/fees/should-attach-fee-output.ts
|
|
353
|
+
function shouldAttachFeeOutput(input) {
|
|
354
|
+
if (input.spendSource === "escrow" && input.escrowSend !== true) {
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
return input.kind === "deposit" || input.kind === "transfer" || input.kind === "withdraw";
|
|
358
|
+
}
|
|
359
|
+
function feeOutputKindFromPrepared(prepared) {
|
|
360
|
+
return {
|
|
361
|
+
kind: prepared.kind,
|
|
362
|
+
...prepared.transactArtifacts?.spendSource ? { spendSource: prepared.transactArtifacts.spendSource } : {},
|
|
363
|
+
...prepared.transactArtifacts?.escrowSend ? { escrowSend: true } : {}
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// src/transact/fees/quote-fee-output-for-prepared.ts
|
|
368
|
+
function instructedMinorUnits(prepared) {
|
|
369
|
+
return prepared.intent.amount.toString();
|
|
370
|
+
}
|
|
371
|
+
function quoteRequestForPrepared(input) {
|
|
372
|
+
const amount = instructedMinorUnits(input.prepared);
|
|
373
|
+
if (input.prepared.kind === "deposit") {
|
|
374
|
+
return {
|
|
375
|
+
feeAsset: input.tokenAddress,
|
|
376
|
+
publicDepositAmount: amount,
|
|
377
|
+
spendsNotes: false
|
|
378
|
+
};
|
|
298
379
|
}
|
|
299
|
-
if (
|
|
300
|
-
|
|
380
|
+
if (input.prepared.kind === "withdraw") {
|
|
381
|
+
return {
|
|
382
|
+
feeAsset: input.tokenAddress,
|
|
383
|
+
publicWithdrawalAmount: amount,
|
|
384
|
+
spendsNotes: true
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
return {
|
|
388
|
+
feeAsset: input.tokenAddress,
|
|
389
|
+
transferInstructedAmount: amount,
|
|
390
|
+
spendsNotes: true
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
async function quoteFeeOutputForPrepared(input) {
|
|
394
|
+
if (!shouldAttachFeeOutput(feeOutputKindFromPrepared(input.prepared))) {
|
|
395
|
+
return void 0;
|
|
396
|
+
}
|
|
397
|
+
const quote = await quoteRequiredFee({
|
|
398
|
+
transactEnvironment: input.environment,
|
|
399
|
+
request: quoteRequestForPrepared(input)
|
|
400
|
+
});
|
|
401
|
+
if (quote.requiredFee <= 0n) {
|
|
402
|
+
return void 0;
|
|
301
403
|
}
|
|
302
|
-
return
|
|
404
|
+
return {
|
|
405
|
+
requiredFee: quote.requiredFee,
|
|
406
|
+
feeCollectorPrivateAddress: quote.feeCollectorPrivateAddress
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
function remainingAfterRequiredFee(input) {
|
|
410
|
+
const remaining = input.available - input.instructed - input.requiredFee;
|
|
411
|
+
if (remaining < 0n) {
|
|
412
|
+
throw new Error("Instructed amount and Required Fee exceed available note value");
|
|
413
|
+
}
|
|
414
|
+
return remaining;
|
|
303
415
|
}
|
|
304
416
|
|
|
305
417
|
// src/transact/audit/parameters.ts
|
|
@@ -307,7 +419,7 @@ import {
|
|
|
307
419
|
DEMO_AUDIT_PUBLIC_KEY,
|
|
308
420
|
resolveTransactionAuditParams
|
|
309
421
|
} from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
310
|
-
import { Buffer as
|
|
422
|
+
import { Buffer as Buffer4 } from "buffer";
|
|
311
423
|
var UNCOMPRESSED_PREFIX = "04";
|
|
312
424
|
var UNCOMPRESSED_HEX_LENGTH = 130;
|
|
313
425
|
var XY_HEX_LENGTH = 128;
|
|
@@ -334,7 +446,7 @@ function parseAuditPublicKeyFromEnvHex(raw) {
|
|
|
334
446
|
"Audit public key must be uncompressed 65-byte hex (04 + X + Y) or 64-byte X+Y hex"
|
|
335
447
|
);
|
|
336
448
|
}
|
|
337
|
-
const bytes =
|
|
449
|
+
const bytes = Buffer4.from(payload, "hex");
|
|
338
450
|
const auditPublicKeyXDecimal = BigInt(
|
|
339
451
|
`0x${bytes.subarray(0, X_OFFSET_END).toString("hex")}`
|
|
340
452
|
).toString(DECIMAL_RADIX);
|
|
@@ -377,13 +489,13 @@ import { ed25519PubkeyPayloadHexToWithdrawFrDecimals } from "@arcanetech/stellar
|
|
|
377
489
|
|
|
378
490
|
// src/transact/stellar/account.ts
|
|
379
491
|
import { StrKey as StrKey3 } from "@stellar/stellar-sdk";
|
|
380
|
-
import { Buffer as
|
|
492
|
+
import { Buffer as Buffer5 } from "buffer";
|
|
381
493
|
var MUXED_ACCOUNT_ID_BYTE_LENGTH = 8;
|
|
382
494
|
var ED25519_PUBLIC_KEY_BYTE_LENGTH = 32;
|
|
383
495
|
function ed25519HexFromGAddress(trimmed) {
|
|
384
496
|
try {
|
|
385
497
|
const raw = StrKey3.decodeEd25519PublicKey(trimmed);
|
|
386
|
-
return
|
|
498
|
+
return Buffer5.from(raw).toString("hex");
|
|
387
499
|
} catch {
|
|
388
500
|
return void 0;
|
|
389
501
|
}
|
|
@@ -440,6 +552,32 @@ function privKeyScalarDecimalFromRecipientScalarHex(hexInput) {
|
|
|
440
552
|
return canonicalBabyJubScalarFromInteger(value).toString(DECIMAL_RADIX2);
|
|
441
553
|
}
|
|
442
554
|
|
|
555
|
+
// src/transact/fees/append-fee-output.ts
|
|
556
|
+
function feeCoinFromSlot(slot) {
|
|
557
|
+
return {
|
|
558
|
+
commitment_hex: slot.commitment_hex,
|
|
559
|
+
coin: slot.coin,
|
|
560
|
+
depositScalarHex: slot.depositScalarHex,
|
|
561
|
+
precommitementHex: slot.precommitementHex
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
async function appendFeeOutputSlot(input) {
|
|
565
|
+
const requiredFee = input.feeOutput?.requiredFee ?? ZERO_STROOPS;
|
|
566
|
+
const collector = input.feeOutput?.feeCollectorPrivateAddress.trim() ?? "";
|
|
567
|
+
if (requiredFee <= ZERO_STROOPS || !collector) {
|
|
568
|
+
return { deposits: input.deposits };
|
|
569
|
+
}
|
|
570
|
+
const slot = await input.buildAlignedDepositSlot({
|
|
571
|
+
privateAddressStpl1: collector,
|
|
572
|
+
amountStroops: requiredFee,
|
|
573
|
+
tokenAddress: input.tokenAddress
|
|
574
|
+
});
|
|
575
|
+
return {
|
|
576
|
+
deposits: [...input.deposits, slot.deposit],
|
|
577
|
+
feeCoin: feeCoinFromSlot(slot)
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
|
|
443
581
|
// src/transact/proofs/withdraw/helpers.ts
|
|
444
582
|
function destinationWithdrawFrAndScalar(parameters) {
|
|
445
583
|
const pkHex = ed25519PublicKeyHexFromStellarAccount(
|
|
@@ -494,14 +632,15 @@ async function resolveWithdrawChangeDeposits(parameters) {
|
|
|
494
632
|
}
|
|
495
633
|
};
|
|
496
634
|
}
|
|
497
|
-
function validateDualWithdrawAmounts(withdrawAmountStroops, totalNotes, changePrivateAddressStpl1) {
|
|
635
|
+
function validateDualWithdrawAmounts(withdrawAmountStroops, totalNotes, changePrivateAddressStpl1, requiredFee) {
|
|
498
636
|
if (withdrawAmountStroops < MIN_CONFIDENTIAL_TRANSFER_STROOPS) {
|
|
499
637
|
throw new Error("Withdraw amount must be positive");
|
|
500
638
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
639
|
+
const changeStroops = remainingAfterRequiredFee({
|
|
640
|
+
available: totalNotes,
|
|
641
|
+
instructed: withdrawAmountStroops,
|
|
642
|
+
requiredFee
|
|
643
|
+
});
|
|
505
644
|
requireChangeRecipientWhenPartial(changeStroops, changePrivateAddressStpl1);
|
|
506
645
|
return changeStroops;
|
|
507
646
|
}
|
|
@@ -514,11 +653,31 @@ function buildDualWithdrawPublicInput(parameters) {
|
|
|
514
653
|
publicWithdrawalAmount: parameters.publicWithdrawalAmount
|
|
515
654
|
});
|
|
516
655
|
}
|
|
656
|
+
async function withdrawOutputsWithOptionalFee(parameters) {
|
|
657
|
+
const { deposits: changeDeposits, changeCoin } = await resolveWithdrawChangeDeposits({
|
|
658
|
+
changeStroops: parameters.changeStroops,
|
|
659
|
+
changePrivateAddressStpl1: parameters.changePrivateAddressStpl1,
|
|
660
|
+
buildAlignedDepositSlot: parameters.buildAlignedDepositSlot,
|
|
661
|
+
tokenAddress: parameters.tokenAddress
|
|
662
|
+
});
|
|
663
|
+
const withFee = await appendFeeOutputSlot({
|
|
664
|
+
deposits: changeDeposits,
|
|
665
|
+
tokenAddress: parameters.tokenAddress,
|
|
666
|
+
buildAlignedDepositSlot: parameters.buildAlignedDepositSlot,
|
|
667
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
668
|
+
});
|
|
669
|
+
return {
|
|
670
|
+
deposits: withFee.deposits,
|
|
671
|
+
...changeCoin ? { changeCoin } : {},
|
|
672
|
+
...withFee.feeCoin ? { feeCoin: withFee.feeCoin } : {}
|
|
673
|
+
};
|
|
674
|
+
}
|
|
517
675
|
async function prepareDualWithdrawProofInputs(parameters) {
|
|
518
676
|
const changeStroops = validateDualWithdrawAmounts(
|
|
519
677
|
parameters.withdrawAmountStroops,
|
|
520
678
|
BigInt(parameters.coinA.value) + BigInt(parameters.coinB.value),
|
|
521
|
-
parameters.changePrivateAddressStpl1
|
|
679
|
+
parameters.changePrivateAddressStpl1,
|
|
680
|
+
parameters.feeOutput?.requiredFee ?? 0n
|
|
522
681
|
);
|
|
523
682
|
const { legA, legB } = dualWithdrawLegsWithSharedRoot({
|
|
524
683
|
sdk: parameters.sdk,
|
|
@@ -533,11 +692,12 @@ async function prepareDualWithdrawProofInputs(parameters) {
|
|
|
533
692
|
),
|
|
534
693
|
applicationId: parameters.applicationId
|
|
535
694
|
});
|
|
536
|
-
const { deposits, changeCoin } = await
|
|
695
|
+
const { deposits, changeCoin, feeCoin } = await withdrawOutputsWithOptionalFee({
|
|
537
696
|
changeStroops,
|
|
538
697
|
changePrivateAddressStpl1: parameters.changePrivateAddressStpl1,
|
|
539
698
|
buildAlignedDepositSlot: parameters.buildAlignedDepositSlot,
|
|
540
|
-
tokenAddress: parameters.tokenAddress
|
|
699
|
+
tokenAddress: parameters.tokenAddress,
|
|
700
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
541
701
|
});
|
|
542
702
|
const publicInput = buildDualWithdrawPublicInput({
|
|
543
703
|
destinationStellarAddress: parameters.destinationStellarAddress,
|
|
@@ -556,19 +716,55 @@ async function prepareDualWithdrawProofInputs(parameters) {
|
|
|
556
716
|
audit,
|
|
557
717
|
deposits,
|
|
558
718
|
withdrawLegs: [legA.withdrawObject, legB.withdrawObject],
|
|
559
|
-
...changeCoin ? { changeCoin } : {}
|
|
719
|
+
...changeCoin ? { changeCoin } : {},
|
|
720
|
+
...feeCoin ? { feeCoin } : {}
|
|
560
721
|
};
|
|
561
722
|
}
|
|
562
723
|
|
|
724
|
+
// src/transact/proofs/withdraw/fee-deposits.ts
|
|
725
|
+
async function withdrawDepositsWithFee(parameters) {
|
|
726
|
+
const { deposits, changeCoin } = await resolveWithdrawChangeDeposits({
|
|
727
|
+
changeStroops: parameters.changeStroops,
|
|
728
|
+
changePrivateAddressStpl1: parameters.changePrivateAddressStpl1,
|
|
729
|
+
buildAlignedDepositSlot: parameters.buildAlignedDepositSlot,
|
|
730
|
+
tokenAddress: parameters.tokenAddress
|
|
731
|
+
});
|
|
732
|
+
const withFee = await appendFeeOutputSlot({
|
|
733
|
+
deposits,
|
|
734
|
+
tokenAddress: parameters.tokenAddress,
|
|
735
|
+
buildAlignedDepositSlot: parameters.buildAlignedDepositSlot,
|
|
736
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
737
|
+
});
|
|
738
|
+
return {
|
|
739
|
+
deposits: withFee.deposits,
|
|
740
|
+
...changeCoin ? { changeCoin } : {},
|
|
741
|
+
...withFee.feeCoin ? { feeCoin: withFee.feeCoin } : {}
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
function withdrawOutputApplicationIds(input) {
|
|
745
|
+
const outputIds = [];
|
|
746
|
+
if (input.hasChange) {
|
|
747
|
+
outputIds.push(input.applicationId);
|
|
748
|
+
}
|
|
749
|
+
if (input.hasFeeOutput) {
|
|
750
|
+
outputIds.push(input.applicationId);
|
|
751
|
+
}
|
|
752
|
+
if (outputIds.length === 0) {
|
|
753
|
+
outputIds.push("0");
|
|
754
|
+
}
|
|
755
|
+
return outputIds;
|
|
756
|
+
}
|
|
757
|
+
|
|
563
758
|
// src/transact/proofs/withdraw/transact-proof.ts
|
|
564
|
-
function validateSingleWithdrawAmounts(withdrawAmountStroops, noteStroops) {
|
|
759
|
+
function validateSingleWithdrawAmounts(withdrawAmountStroops, noteStroops, requiredFee) {
|
|
565
760
|
if (withdrawAmountStroops < MIN_CONFIDENTIAL_TRANSFER_STROOPS) {
|
|
566
761
|
throw new Error("Withdraw amount must be positive");
|
|
567
762
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
763
|
+
return remainingAfterRequiredFee({
|
|
764
|
+
available: noteStroops,
|
|
765
|
+
instructed: withdrawAmountStroops,
|
|
766
|
+
requiredFee
|
|
767
|
+
});
|
|
572
768
|
}
|
|
573
769
|
async function proveSingleWithdrawTransaction(parameters) {
|
|
574
770
|
return parameters.sdk.proveTransaction(
|
|
@@ -607,7 +803,8 @@ function buildPrimaryWithdrawForCoin(parameters) {
|
|
|
607
803
|
async function prepareSingleWithdrawProofInputs(parameters) {
|
|
608
804
|
const changeStroops = validateSingleWithdrawAmounts(
|
|
609
805
|
parameters.withdrawAmountStroops,
|
|
610
|
-
BigInt(parameters.coin.value)
|
|
806
|
+
BigInt(parameters.coin.value),
|
|
807
|
+
parameters.feeOutput?.requiredFee ?? 0n
|
|
611
808
|
);
|
|
612
809
|
const { witness, primaryWithdraw } = buildPrimaryWithdrawForCoin({
|
|
613
810
|
sdk: parameters.sdk,
|
|
@@ -616,11 +813,12 @@ async function prepareSingleWithdrawProofInputs(parameters) {
|
|
|
616
813
|
state: parameters.state,
|
|
617
814
|
privKeyScalarHex: parameters.privKeyScalarHex
|
|
618
815
|
});
|
|
619
|
-
const { deposits, changeCoin } = await
|
|
816
|
+
const { deposits, changeCoin, feeCoin } = await withdrawDepositsWithFee({
|
|
620
817
|
changeStroops,
|
|
621
818
|
changePrivateAddressStpl1: parameters.changePrivateAddressStpl1,
|
|
622
819
|
buildAlignedDepositSlot: parameters.buildAlignedDepositSlot,
|
|
623
|
-
tokenAddress: parameters.tokenAddress
|
|
820
|
+
tokenAddress: parameters.tokenAddress,
|
|
821
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
624
822
|
});
|
|
625
823
|
const publicInput = buildWithdrawPublicInput({
|
|
626
824
|
stateRoot: witness.stateRoot,
|
|
@@ -633,6 +831,7 @@ async function prepareSingleWithdrawProofInputs(parameters) {
|
|
|
633
831
|
primaryWithdraw,
|
|
634
832
|
deposits,
|
|
635
833
|
changeCoin,
|
|
834
|
+
feeCoin,
|
|
636
835
|
publicInput,
|
|
637
836
|
audit: buildPoolTransactionAuditParameters({
|
|
638
837
|
applicationId: parameters.applicationId,
|
|
@@ -642,7 +841,7 @@ async function prepareSingleWithdrawProofInputs(parameters) {
|
|
|
642
841
|
};
|
|
643
842
|
}
|
|
644
843
|
async function proveWithdrawTransact(parameters) {
|
|
645
|
-
const { primaryWithdraw, deposits, changeCoin, publicInput, audit } = await prepareSingleWithdrawProofInputs(parameters);
|
|
844
|
+
const { primaryWithdraw, deposits, changeCoin, feeCoin, publicInput, audit } = await prepareSingleWithdrawProofInputs(parameters);
|
|
646
845
|
const proof = await proveSingleWithdrawTransaction({
|
|
647
846
|
sdk: parameters.sdk,
|
|
648
847
|
publicInput,
|
|
@@ -657,13 +856,17 @@ async function proveWithdrawTransact(parameters) {
|
|
|
657
856
|
applicationIdsPlaintext: buildApplicationIdHints({
|
|
658
857
|
sdk: parameters.sdk,
|
|
659
858
|
inputIds: [parameters.applicationId],
|
|
660
|
-
outputIds:
|
|
859
|
+
outputIds: withdrawOutputApplicationIds({
|
|
860
|
+
applicationId: parameters.applicationId,
|
|
861
|
+
hasChange: Boolean(changeCoin),
|
|
862
|
+
hasFeeOutput: Boolean(feeCoin)
|
|
863
|
+
})
|
|
661
864
|
}),
|
|
662
865
|
...changeCoin ? { changeCoin } : {}
|
|
663
866
|
};
|
|
664
867
|
}
|
|
665
868
|
async function proveWithdrawTransactDual(parameters) {
|
|
666
|
-
const { publicInput, audit, withdrawLegs, deposits, changeCoin } = await prepareDualWithdrawProofInputs(parameters);
|
|
869
|
+
const { publicInput, audit, withdrawLegs, deposits, changeCoin, feeCoin } = await prepareDualWithdrawProofInputs(parameters);
|
|
667
870
|
const proof = await parameters.sdk.proveTransaction(
|
|
668
871
|
publicInput,
|
|
669
872
|
padPublicLegsToLayout(
|
|
@@ -682,7 +885,11 @@ async function proveWithdrawTransactDual(parameters) {
|
|
|
682
885
|
applicationIdsPlaintext: buildApplicationIdHints({
|
|
683
886
|
sdk: parameters.sdk,
|
|
684
887
|
inputIds: [audit.applicationId, audit.applicationId],
|
|
685
|
-
outputIds:
|
|
888
|
+
outputIds: withdrawOutputApplicationIds({
|
|
889
|
+
applicationId: audit.applicationId,
|
|
890
|
+
hasChange: Boolean(changeCoin),
|
|
891
|
+
hasFeeOutput: Boolean(feeCoin)
|
|
892
|
+
})
|
|
686
893
|
}),
|
|
687
894
|
...changeCoin ? { changeCoin } : {}
|
|
688
895
|
};
|
|
@@ -706,6 +913,9 @@ var DEFAULT_ZK_CONFIG_NONCE = BINDING_ZK_NONCE;
|
|
|
706
913
|
function resolveZkConfigNonce(transactEnvironment) {
|
|
707
914
|
return transactEnvironment.zkConfigNonce ?? DEFAULT_ZK_CONFIG_NONCE;
|
|
708
915
|
}
|
|
916
|
+
function transactNonceFromArtifacts(artifacts, transactEnvironment) {
|
|
917
|
+
return artifacts?.zkConfigNonce ?? resolveZkConfigNonce(transactEnvironment);
|
|
918
|
+
}
|
|
709
919
|
|
|
710
920
|
// src/transact/zk/browser-artifact-cache.ts
|
|
711
921
|
import { ZK_ARTIFACT_VERSION } from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
@@ -958,6 +1168,122 @@ async function buildAlignedDepositSlotForSdk(sdk, applicationId, parameters) {
|
|
|
958
1168
|
};
|
|
959
1169
|
}
|
|
960
1170
|
|
|
1171
|
+
// src/transact/pool/initialize-sdk.ts
|
|
1172
|
+
import { PrivacyPoolSDK as PrivacyPoolSDK2 } from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
1173
|
+
async function initializePrivacyPoolSdk(input, nonce) {
|
|
1174
|
+
const zkConfigNonce = nonce ?? input.zkConfigNonce ?? DEFAULT_ZK_CONFIG_NONCE;
|
|
1175
|
+
const zkCircuits = await materializeSelectedZkCircuit(
|
|
1176
|
+
input.zkCircuits,
|
|
1177
|
+
zkConfigNonce,
|
|
1178
|
+
input.zkArtifactBaseUrl
|
|
1179
|
+
);
|
|
1180
|
+
return PrivacyPoolSDK2.init({
|
|
1181
|
+
wasmBinary: input.assets.sdkWasm,
|
|
1182
|
+
zkCircuits,
|
|
1183
|
+
zkConfigNonce,
|
|
1184
|
+
...optionalZkArtifactBaseUrl(input.zkArtifactBaseUrl)
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
// src/transact/fees/zk-config-nonce-for-kind.ts
|
|
1189
|
+
function configuredNonceSpread(zkConfigNonce) {
|
|
1190
|
+
if (zkConfigNonce === void 0) {
|
|
1191
|
+
return {};
|
|
1192
|
+
}
|
|
1193
|
+
return { configuredNonce: zkConfigNonce };
|
|
1194
|
+
}
|
|
1195
|
+
function zkConfigNonceForFeeBearingKind(input) {
|
|
1196
|
+
if (input.configuredNonce === SIX_BY_SIX_BINDING_ZK_NONCE) {
|
|
1197
|
+
return SIX_BY_SIX_BINDING_ZK_NONCE;
|
|
1198
|
+
}
|
|
1199
|
+
if (input.kind === "transfer" && shouldAttachFeeOutput(input)) {
|
|
1200
|
+
return SIX_BY_SIX_BINDING_ZK_NONCE;
|
|
1201
|
+
}
|
|
1202
|
+
return input.configuredNonce ?? BINDING_ZK_NONCE;
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
// src/transact/pool/prepare-deposit-proof.ts
|
|
1206
|
+
import {
|
|
1207
|
+
randomFrDecimal253,
|
|
1208
|
+
scalarHexToFrDecimal as scalarHexToFrDecimal2
|
|
1209
|
+
} from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
1210
|
+
|
|
1211
|
+
// src/transact/merkle/field-decimal.ts
|
|
1212
|
+
import { Buffer as Buffer6 } from "buffer";
|
|
1213
|
+
var BN254 = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
|
|
1214
|
+
var MERKLE_ROOT_BYTE_LENGTH = 32;
|
|
1215
|
+
var DECIMAL_STRING_RADIX = 10;
|
|
1216
|
+
function merkleRootBufferToFrDecimal(root) {
|
|
1217
|
+
if (root.length !== MERKLE_ROOT_BYTE_LENGTH) {
|
|
1218
|
+
throw new Error(
|
|
1219
|
+
`expected ${MERKLE_ROOT_BYTE_LENGTH}-byte merkle root, got ${root.length}`
|
|
1220
|
+
);
|
|
1221
|
+
}
|
|
1222
|
+
const hex = Buffer6.from(root).toString("hex");
|
|
1223
|
+
return (BigInt(`0x${hex}`) % BN254).toString(DECIMAL_STRING_RADIX);
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
// src/transact/pool/prepare-deposit-proof.ts
|
|
1227
|
+
function userDepositSlot(input) {
|
|
1228
|
+
return {
|
|
1229
|
+
value: input.coin.value,
|
|
1230
|
+
nullifier: input.coin.nullifier,
|
|
1231
|
+
ephemeralKeyScalar: scalarHexToFrDecimal2(input.depositScalarHex),
|
|
1232
|
+
asset: [input.coin.asset_hi, input.coin.asset_lo],
|
|
1233
|
+
applicationId: input.applicationId,
|
|
1234
|
+
recipientPublicKeys: recipientPublicKeysDecimalFromPrivateAddress(
|
|
1235
|
+
input.privateAddressStpl1
|
|
1236
|
+
)
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
function outputApplicationIds(input) {
|
|
1240
|
+
if (input.hasFeeOutput) {
|
|
1241
|
+
return [input.applicationId, input.applicationId];
|
|
1242
|
+
}
|
|
1243
|
+
return [input.applicationId];
|
|
1244
|
+
}
|
|
1245
|
+
async function proveDepositTransact(input) {
|
|
1246
|
+
const publicDeposit = (input.publicDepositStroops ?? BigInt(input.coin.value)).toString();
|
|
1247
|
+
const withFee = await appendFeeOutputSlot({
|
|
1248
|
+
deposits: [userDepositSlot(input)],
|
|
1249
|
+
tokenAddress: input.tokenAddress,
|
|
1250
|
+
buildAlignedDepositSlot: input.buildAlignedDepositSlot,
|
|
1251
|
+
...input.feeOutput ? { feeOutput: input.feeOutput } : {}
|
|
1252
|
+
});
|
|
1253
|
+
const audit = buildPoolTransactionAuditParameters({
|
|
1254
|
+
applicationId: input.applicationId,
|
|
1255
|
+
nAuditSlots: input.sdk.getLayout().nAuditSlots,
|
|
1256
|
+
...input.auditPublicKey ? { auditPublicKey: input.auditPublicKey } : {}
|
|
1257
|
+
});
|
|
1258
|
+
const proof = await input.sdk.proveTransaction(
|
|
1259
|
+
withTokenAddressPublicInputs(
|
|
1260
|
+
{
|
|
1261
|
+
stateRoot: merkleRootBufferToFrDecimal(input.merkleRootBytes),
|
|
1262
|
+
privKeyScalar: randomFrDecimal253()
|
|
1263
|
+
},
|
|
1264
|
+
input.tokenAddress
|
|
1265
|
+
),
|
|
1266
|
+
padPublicLegsToLayout(
|
|
1267
|
+
input.sdk,
|
|
1268
|
+
buildPublicDepositLegs(input.tokenAddress, publicDeposit)
|
|
1269
|
+
),
|
|
1270
|
+
padWithdrawSlotsToLayout(input.sdk, []),
|
|
1271
|
+
padDepositSlotsToLayout(input.sdk, withFee.deposits),
|
|
1272
|
+
audit
|
|
1273
|
+
);
|
|
1274
|
+
return {
|
|
1275
|
+
...proof,
|
|
1276
|
+
applicationIdsPlaintext: buildApplicationIdHints({
|
|
1277
|
+
sdk: input.sdk,
|
|
1278
|
+
inputIds: [],
|
|
1279
|
+
outputIds: outputApplicationIds({
|
|
1280
|
+
applicationId: input.applicationId,
|
|
1281
|
+
hasFeeOutput: Boolean(withFee.feeCoin)
|
|
1282
|
+
})
|
|
1283
|
+
})
|
|
1284
|
+
};
|
|
1285
|
+
}
|
|
1286
|
+
|
|
961
1287
|
// src/transact/pool/service.ts
|
|
962
1288
|
var PrivacyPoolService = class {
|
|
963
1289
|
constructor(assets, applicationId, auditPublicKey, zkCircuits, zkConfigNonce, zkArtifactBaseUrl) {
|
|
@@ -974,42 +1300,50 @@ var PrivacyPoolService = class {
|
|
|
974
1300
|
zkCircuits;
|
|
975
1301
|
zkConfigNonce;
|
|
976
1302
|
zkArtifactBaseUrl;
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
async
|
|
980
|
-
|
|
981
|
-
|
|
1303
|
+
sdks = /* @__PURE__ */ new Map();
|
|
1304
|
+
initPromises = /* @__PURE__ */ new Map();
|
|
1305
|
+
async getInitializedSdk(nonce) {
|
|
1306
|
+
const zkConfigNonce = nonce ?? this.zkConfigNonce ?? DEFAULT_ZK_CONFIG_NONCE;
|
|
1307
|
+
const key = zkConfigNonce.toString();
|
|
1308
|
+
const existing = this.sdks.get(key);
|
|
1309
|
+
if (existing) {
|
|
1310
|
+
return existing;
|
|
982
1311
|
}
|
|
983
|
-
|
|
984
|
-
|
|
1312
|
+
const pending = this.initPromises.get(key);
|
|
1313
|
+
if (pending) {
|
|
1314
|
+
return pending;
|
|
1315
|
+
}
|
|
1316
|
+
const started = this.initializeSdk(zkConfigNonce);
|
|
1317
|
+
this.initPromises.set(key, started);
|
|
1318
|
+
try {
|
|
1319
|
+
const sdk = await started;
|
|
1320
|
+
this.sdks.set(key, sdk);
|
|
1321
|
+
return sdk;
|
|
1322
|
+
} finally {
|
|
1323
|
+
this.initPromises.delete(key);
|
|
985
1324
|
}
|
|
986
|
-
this.initPromise = (async () => {
|
|
987
|
-
if (!this.assets) {
|
|
988
|
-
throw new Error(
|
|
989
|
-
"PrivacyPoolService requires browser ZK assets before initialization."
|
|
990
|
-
);
|
|
991
|
-
}
|
|
992
|
-
const zkConfigNonce = this.zkConfigNonce ?? DEFAULT_ZK_CONFIG_NONCE;
|
|
993
|
-
const zkCircuits = await materializeSelectedZkCircuit(
|
|
994
|
-
this.zkCircuits,
|
|
995
|
-
zkConfigNonce,
|
|
996
|
-
this.zkArtifactBaseUrl
|
|
997
|
-
);
|
|
998
|
-
this.sdk = await PrivacyPoolSDK2.init({
|
|
999
|
-
wasmBinary: this.assets.sdkWasm,
|
|
1000
|
-
zkCircuits,
|
|
1001
|
-
zkConfigNonce,
|
|
1002
|
-
...optionalZkArtifactBaseUrl(this.zkArtifactBaseUrl)
|
|
1003
|
-
});
|
|
1004
|
-
})();
|
|
1005
|
-
return this.initPromise;
|
|
1006
1325
|
}
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1326
|
+
feeBearingZkConfigNonce(input) {
|
|
1327
|
+
return zkConfigNonceForFeeBearingKind({
|
|
1328
|
+
...input,
|
|
1329
|
+
...configuredNonceSpread(this.zkConfigNonce)
|
|
1330
|
+
});
|
|
1331
|
+
}
|
|
1332
|
+
async initializeSdk(nonce) {
|
|
1333
|
+
if (!this.assets) {
|
|
1334
|
+
throw new Error(
|
|
1335
|
+
"PrivacyPoolService requires browser ZK assets before initialization."
|
|
1336
|
+
);
|
|
1011
1337
|
}
|
|
1012
|
-
return
|
|
1338
|
+
return initializePrivacyPoolSdk(
|
|
1339
|
+
{
|
|
1340
|
+
assets: this.assets,
|
|
1341
|
+
...this.zkCircuits ? { zkCircuits: this.zkCircuits } : {},
|
|
1342
|
+
...this.zkConfigNonce === void 0 ? {} : { zkConfigNonce: this.zkConfigNonce },
|
|
1343
|
+
...optionalZkArtifactBaseUrl(this.zkArtifactBaseUrl)
|
|
1344
|
+
},
|
|
1345
|
+
nonce
|
|
1346
|
+
);
|
|
1013
1347
|
}
|
|
1014
1348
|
getAuditPublicKey() {
|
|
1015
1349
|
return this.auditPublicKey;
|
|
@@ -1042,65 +1376,51 @@ var PrivacyPoolService = class {
|
|
|
1042
1376
|
return { commitment_hex, coin, depositScalarHex, precommitementHex };
|
|
1043
1377
|
}
|
|
1044
1378
|
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
|
|
1379
|
+
const sdk = await this.getInitializedSdk(
|
|
1380
|
+
this.feeBearingZkConfigNonce({ kind: "deposit" })
|
|
1080
1381
|
);
|
|
1081
|
-
|
|
1382
|
+
return proveDepositTransact({
|
|
1082
1383
|
sdk,
|
|
1083
|
-
|
|
1084
|
-
|
|
1384
|
+
applicationId: this.getApplicationId(),
|
|
1385
|
+
privateAddressStpl1: parameters.privateAddressStpl1,
|
|
1386
|
+
coin: parameters.coin,
|
|
1387
|
+
depositScalarHex: parameters.depositScalarHex,
|
|
1388
|
+
merkleRootBytes: parameters.merkleRootBytes,
|
|
1389
|
+
tokenAddress: parameters.tokenAddress,
|
|
1390
|
+
buildAlignedDepositSlot: (input) => this.buildAlignedDepositSlot(input),
|
|
1391
|
+
...this.auditPublicKey ? { auditPublicKey: this.auditPublicKey } : {},
|
|
1392
|
+
...parameters.publicDepositStroops === void 0 ? {} : { publicDepositStroops: parameters.publicDepositStroops },
|
|
1393
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
1085
1394
|
});
|
|
1086
|
-
return { ...proof, applicationIdsPlaintext };
|
|
1087
1395
|
}
|
|
1088
1396
|
async calculateNullifierHash(nullifier, privKeyScalar) {
|
|
1089
1397
|
const sdk = await this.getInitializedSdk();
|
|
1090
1398
|
return sdk.calculateNullifierHash(nullifier, privKeyScalar);
|
|
1091
1399
|
}
|
|
1092
1400
|
async prepareWithdrawTransactProof(parameters) {
|
|
1093
|
-
const sdk = await this.getInitializedSdk(
|
|
1401
|
+
const sdk = await this.getInitializedSdk(
|
|
1402
|
+
this.feeBearingZkConfigNonce({ kind: "withdraw" })
|
|
1403
|
+
);
|
|
1094
1404
|
return proveWithdrawTransact({
|
|
1095
1405
|
sdk,
|
|
1096
1406
|
applicationId: this.getApplicationId(),
|
|
1097
1407
|
buildAlignedDepositSlot: (input) => this.buildAlignedDepositSlot(input),
|
|
1098
1408
|
...this.auditPublicKey ? { auditPublicKey: this.auditPublicKey } : {},
|
|
1099
|
-
|
|
1409
|
+
coin: parameters.coin,
|
|
1410
|
+
state: parameters.state,
|
|
1411
|
+
destinationStellarAddress: parameters.destinationStellarAddress,
|
|
1412
|
+
privKeyScalarHex: parameters.privKeyScalarHex,
|
|
1413
|
+
depositorEphemeralKey: parameters.depositorEphemeralKey,
|
|
1414
|
+
withdrawAmountStroops: parameters.withdrawAmountStroops,
|
|
1415
|
+
changePrivateAddressStpl1: parameters.changePrivateAddressStpl1,
|
|
1416
|
+
tokenAddress: parameters.tokenAddress,
|
|
1417
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
1100
1418
|
});
|
|
1101
1419
|
}
|
|
1102
1420
|
async prepareWithdrawTransactProofDual(parameters) {
|
|
1103
|
-
const sdk = await this.getInitializedSdk(
|
|
1421
|
+
const sdk = await this.getInitializedSdk(
|
|
1422
|
+
this.feeBearingZkConfigNonce({ kind: "withdraw" })
|
|
1423
|
+
);
|
|
1104
1424
|
return proveWithdrawTransactDual({
|
|
1105
1425
|
sdk,
|
|
1106
1426
|
applicationId: this.getApplicationId(),
|
|
@@ -1115,7 +1435,8 @@ var PrivacyPoolService = class {
|
|
|
1115
1435
|
ephemeralBKey: parameters.depositorEphemeralBKey,
|
|
1116
1436
|
withdrawAmountStroops: parameters.withdrawAmountStroops,
|
|
1117
1437
|
changePrivateAddressStpl1: parameters.changePrivateAddressStpl1,
|
|
1118
|
-
tokenAddress: parameters.tokenAddress
|
|
1438
|
+
tokenAddress: parameters.tokenAddress,
|
|
1439
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
1119
1440
|
});
|
|
1120
1441
|
}
|
|
1121
1442
|
};
|
|
@@ -1820,7 +2141,7 @@ async function requestKytPassageForPoolInteraction(input) {
|
|
|
1820
2141
|
const applicationId = resolvePoolApplicationId(
|
|
1821
2142
|
input.transactEnvironment.network.applicationId
|
|
1822
2143
|
);
|
|
1823
|
-
const zkConfigNonce = resolveZkConfigNonce(input.transactEnvironment);
|
|
2144
|
+
const zkConfigNonce = input.zkConfigNonce ?? resolveZkConfigNonce(input.transactEnvironment);
|
|
1824
2145
|
const applicationIdsPlaintext = input.applicationIdsPlaintext ?? buildApplicationIdHints2(
|
|
1825
2146
|
applicationId,
|
|
1826
2147
|
layoutForKnownNonce(zkConfigNonce).nAuditSlots
|
|
@@ -1933,6 +2254,7 @@ async function inspectRelayerSweepKyt(input) {
|
|
|
1933
2254
|
...input.prepared.transactArtifacts?.applicationIdsPlaintext ? {
|
|
1934
2255
|
applicationIdsPlaintext: input.prepared.transactArtifacts.applicationIdsPlaintext
|
|
1935
2256
|
} : {},
|
|
2257
|
+
...input.prepared.transactArtifacts?.zkConfigNonce === void 0 ? {} : { zkConfigNonce: input.prepared.transactArtifacts.zkConfigNonce },
|
|
1936
2258
|
networkPassphrase: environment.network.networkPassphrase,
|
|
1937
2259
|
sorobanRpcUrl: environment.network.rpcUrl,
|
|
1938
2260
|
transactEnvironment: environment
|
|
@@ -1945,7 +2267,10 @@ async function simulateSweepAuthEntries(input) {
|
|
|
1945
2267
|
const operation = new Contract(environment.network.poolContract).call(
|
|
1946
2268
|
"transact",
|
|
1947
2269
|
new Address3(input.relayerPublicKey).toScVal(),
|
|
1948
|
-
nativeToScVal2(
|
|
2270
|
+
nativeToScVal2(
|
|
2271
|
+
transactNonceFromArtifacts(input.prepared.transactArtifacts, environment),
|
|
2272
|
+
{ type: "u64" }
|
|
2273
|
+
),
|
|
1949
2274
|
nativeToScVal2(hexToBytes(input.artifacts.proofHex), { type: "bytes" }),
|
|
1950
2275
|
nativeToScVal2(hexToBytes(input.artifacts.publicHex), { type: "bytes" }),
|
|
1951
2276
|
nativeToScVal2(hexToBytes(input.artifacts.ciphertextHex ?? ""), { type: "bytes" }),
|
|
@@ -1982,6 +2307,7 @@ async function unsignedEscrowAuthorizationForSweep(input) {
|
|
|
1982
2307
|
});
|
|
1983
2308
|
const auth = await simulateSweepAuthEntries({
|
|
1984
2309
|
artifacts,
|
|
2310
|
+
prepared: input.prepared,
|
|
1985
2311
|
transactEnvironment: input.transactEnvironment,
|
|
1986
2312
|
relayerPublicKey,
|
|
1987
2313
|
approval
|
|
@@ -2013,15 +2339,15 @@ async function loadDefaultStellarBrowserAssets(options) {
|
|
|
2013
2339
|
}
|
|
2014
2340
|
|
|
2015
2341
|
// src/transact/private-address/temporary-recipient.ts
|
|
2016
|
-
import { PrivacyPoolSDK as
|
|
2342
|
+
import { PrivacyPoolSDK as PrivacyPoolSDK4 } from "@arcanetech/stellar-privacy-pool-zk-sdk";
|
|
2017
2343
|
var COORDINATE_HEX_LENGTH2 = 64;
|
|
2018
2344
|
async function generateRandomDepositScalarHex() {
|
|
2019
2345
|
await getPrivacyPoolService().getInitializedSdk();
|
|
2020
|
-
return
|
|
2346
|
+
return PrivacyPoolSDK4.generateRandomScalarHex32();
|
|
2021
2347
|
}
|
|
2022
2348
|
async function generateTemporaryRecipientPrivateAddress() {
|
|
2023
2349
|
await getPrivacyPoolService().getInitializedSdk();
|
|
2024
|
-
const temporaryScalarHex =
|
|
2350
|
+
const temporaryScalarHex = PrivacyPoolSDK4.generateRandomScalarHex32();
|
|
2025
2351
|
const sdk = await getPrivacyPoolService().getInitializedSdk();
|
|
2026
2352
|
const point = sdk.ecdhEphemeralPublicKeyFromScalarHex(temporaryScalarHex);
|
|
2027
2353
|
const publicKeyXHex = point.x.padStart(COORDINATE_HEX_LENGTH2, "0");
|
|
@@ -2290,6 +2616,10 @@ async function submitSorobanConfidentialTransfer(input) {
|
|
|
2290
2616
|
networkPassphrase: input.networkPassphrase,
|
|
2291
2617
|
sorobanRpcUrl: input.sorobanRpcUrl
|
|
2292
2618
|
});
|
|
2619
|
+
const nonce = transactNonceFromArtifacts(
|
|
2620
|
+
input.zkConfigNonce === void 0 ? void 0 : { zkConfigNonce: input.zkConfigNonce },
|
|
2621
|
+
input.transactEnvironment
|
|
2622
|
+
);
|
|
2293
2623
|
const approval = await requestKytPassageForPoolInteraction({
|
|
2294
2624
|
owner: input.walletPublicKey,
|
|
2295
2625
|
poolContract: input.contractId,
|
|
@@ -2298,6 +2628,7 @@ async function submitSorobanConfidentialTransfer(input) {
|
|
|
2298
2628
|
...input.ciphertextHex ? { ciphertextHex: input.ciphertextHex } : {},
|
|
2299
2629
|
...input.outputNoteEphemeralScalars ? { outputNoteEphemeralScalars: input.outputNoteEphemeralScalars } : {},
|
|
2300
2630
|
...input.applicationIdsPlaintext ? { applicationIdsPlaintext: input.applicationIdsPlaintext } : {},
|
|
2631
|
+
...input.zkConfigNonce === void 0 ? {} : { zkConfigNonce: input.zkConfigNonce },
|
|
2301
2632
|
networkPassphrase: input.networkPassphrase,
|
|
2302
2633
|
sorobanRpcUrl: input.sorobanRpcUrl,
|
|
2303
2634
|
transactEnvironment: input.transactEnvironment
|
|
@@ -2306,7 +2637,7 @@ async function submitSorobanConfidentialTransfer(input) {
|
|
|
2306
2637
|
contractClient: poolClient,
|
|
2307
2638
|
contractId: input.contractId,
|
|
2308
2639
|
from: input.walletPublicKey,
|
|
2309
|
-
nonce
|
|
2640
|
+
nonce,
|
|
2310
2641
|
proofHex: input.proofHex,
|
|
2311
2642
|
publicHex: input.publicHex,
|
|
2312
2643
|
...input.ciphertextHex ? { ciphertextHex: input.ciphertextHex } : {},
|
|
@@ -2328,9 +2659,6 @@ function escrowOutputFields(input) {
|
|
|
2328
2659
|
recipientLo: input.escrowSend.recipientLo
|
|
2329
2660
|
};
|
|
2330
2661
|
}
|
|
2331
|
-
function paddingDepositPair(recipientDeposit) {
|
|
2332
|
-
return [recipientDeposit, "dummy"];
|
|
2333
|
-
}
|
|
2334
2662
|
async function buildChangeDepositPair(parameters) {
|
|
2335
2663
|
const changeSlot = await getPrivacyPoolService().buildAlignedDepositSlot({
|
|
2336
2664
|
privateAddressStpl1: parameters.selfPrivateAddressStpl1ForChange.trim(),
|
|
@@ -2347,34 +2675,54 @@ async function buildChangeDepositPair(parameters) {
|
|
|
2347
2675
|
}
|
|
2348
2676
|
};
|
|
2349
2677
|
}
|
|
2678
|
+
function recipientOnlyDeposits(recipientDeposit, hasFeeOutput) {
|
|
2679
|
+
if (hasFeeOutput) {
|
|
2680
|
+
return [recipientDeposit];
|
|
2681
|
+
}
|
|
2682
|
+
return [recipientDeposit, "dummy"];
|
|
2683
|
+
}
|
|
2684
|
+
async function depositsWithoutFee(input) {
|
|
2685
|
+
if (input.changeStroops <= ZERO_STROOPS) {
|
|
2686
|
+
return {
|
|
2687
|
+
deposits: recipientOnlyDeposits(input.recipientDeposit, input.hasFeeOutput)
|
|
2688
|
+
};
|
|
2689
|
+
}
|
|
2690
|
+
return buildChangeDepositPair({
|
|
2691
|
+
selfPrivateAddressStpl1ForChange: input.selfPrivateAddressStpl1ForChange,
|
|
2692
|
+
changeStroops: input.changeStroops,
|
|
2693
|
+
tokenAddress: input.tokenAddress,
|
|
2694
|
+
recipientDeposit: input.recipientDeposit
|
|
2695
|
+
});
|
|
2696
|
+
}
|
|
2350
2697
|
async function buildRecipientAndOptionalChangeDeposits(parameters) {
|
|
2351
2698
|
const escrow = {
|
|
2352
2699
|
...parameters.escrowSend ? { escrowSend: parameters.escrowSend } : {},
|
|
2353
2700
|
...parameters.escrowClaimantLimbs ? { escrowClaimantLimbs: parameters.escrowClaimantLimbs } : {}
|
|
2354
2701
|
};
|
|
2355
|
-
const recipientPrivateAddress = parameters.recipientPrivateAddressStpl1.trim();
|
|
2356
2702
|
const recipientSlot = await getPrivacyPoolService().buildAlignedDepositSlot({
|
|
2357
|
-
privateAddressStpl1:
|
|
2703
|
+
privateAddressStpl1: parameters.recipientPrivateAddressStpl1.trim(),
|
|
2358
2704
|
amountStroops: parameters.transferStroops,
|
|
2359
2705
|
tokenAddress: parameters.tokenAddress,
|
|
2360
2706
|
...escrowOutputFields(escrow)
|
|
2361
2707
|
});
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
recipientSlot,
|
|
2365
|
-
deposits: paddingDepositPair(recipientSlot.deposit)
|
|
2366
|
-
};
|
|
2367
|
-
}
|
|
2368
|
-
const changeResult = await buildChangeDepositPair({
|
|
2369
|
-
selfPrivateAddressStpl1ForChange: parameters.selfPrivateAddressStpl1ForChange,
|
|
2708
|
+
const withoutFee = await depositsWithoutFee({
|
|
2709
|
+
recipientDeposit: recipientSlot.deposit,
|
|
2370
2710
|
changeStroops: parameters.changeStroops,
|
|
2711
|
+
selfPrivateAddressStpl1ForChange: parameters.selfPrivateAddressStpl1ForChange,
|
|
2371
2712
|
tokenAddress: parameters.tokenAddress,
|
|
2372
|
-
|
|
2713
|
+
hasFeeOutput: (parameters.feeOutput?.requiredFee ?? ZERO_STROOPS) > ZERO_STROOPS
|
|
2714
|
+
});
|
|
2715
|
+
const withFee = await appendFeeOutputSlot({
|
|
2716
|
+
deposits: withoutFee.deposits,
|
|
2717
|
+
tokenAddress: parameters.tokenAddress,
|
|
2718
|
+
buildAlignedDepositSlot: (aligned) => getPrivacyPoolService().buildAlignedDepositSlot(aligned),
|
|
2719
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
2373
2720
|
});
|
|
2374
2721
|
return {
|
|
2375
2722
|
recipientSlot,
|
|
2376
|
-
deposits:
|
|
2377
|
-
changeCoin:
|
|
2723
|
+
deposits: withFee.deposits,
|
|
2724
|
+
..."changeCoin" in withoutFee ? { changeCoin: withoutFee.changeCoin } : {},
|
|
2725
|
+
...withFee.feeCoin ? { feeCoin: withFee.feeCoin } : {}
|
|
2378
2726
|
};
|
|
2379
2727
|
}
|
|
2380
2728
|
|
|
@@ -2427,14 +2775,15 @@ function sweepOutputOwnerFields(parameters) {
|
|
|
2427
2775
|
return { sweepOutputOwnerPubX, sweepOutputOwnerPubY };
|
|
2428
2776
|
}
|
|
2429
2777
|
async function buildTransferDepositsAndPublicInput(parameters) {
|
|
2430
|
-
const { recipientSlot, deposits, changeCoin } = await buildRecipientAndOptionalChangeDeposits({
|
|
2778
|
+
const { recipientSlot, deposits, changeCoin, feeCoin } = await buildRecipientAndOptionalChangeDeposits({
|
|
2431
2779
|
recipientPrivateAddressStpl1: parameters.recipientPrivateAddressStpl1,
|
|
2432
2780
|
transferStroops: parameters.transferStroops,
|
|
2433
2781
|
changeStroops: parameters.changeStroops,
|
|
2434
2782
|
selfPrivateAddressStpl1ForChange: parameters.selfPrivateAddressStpl1ForChange,
|
|
2435
2783
|
tokenAddress: parameters.tokenAddress,
|
|
2436
2784
|
...parameters.escrowSend ? { escrowSend: parameters.escrowSend } : {},
|
|
2437
|
-
...parameters.escrowClaimantLimbs ? { escrowClaimantLimbs: parameters.escrowClaimantLimbs } : {}
|
|
2785
|
+
...parameters.escrowClaimantLimbs ? { escrowClaimantLimbs: parameters.escrowClaimantLimbs } : {},
|
|
2786
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
2438
2787
|
});
|
|
2439
2788
|
const publicInput = withTokenAddressPublicInputs(
|
|
2440
2789
|
{
|
|
@@ -2449,6 +2798,7 @@ async function buildTransferDepositsAndPublicInput(parameters) {
|
|
|
2449
2798
|
recipientSlot,
|
|
2450
2799
|
deposits,
|
|
2451
2800
|
...changeCoin ? { changeCoin } : {},
|
|
2801
|
+
...feeCoin ? { feeCoin } : {},
|
|
2452
2802
|
publicInput
|
|
2453
2803
|
};
|
|
2454
2804
|
}
|
|
@@ -2464,7 +2814,8 @@ async function buildSenderTransferDepositsAndPublicInput(parameters) {
|
|
|
2464
2814
|
parameters.senderPrivKeyScalarHex
|
|
2465
2815
|
),
|
|
2466
2816
|
...parameters.escrowSend ? { escrowSend: parameters.escrowSend } : {},
|
|
2467
|
-
...parameters.escrowClaimantLimbs ? { escrowClaimantLimbs: parameters.escrowClaimantLimbs } : {}
|
|
2817
|
+
...parameters.escrowClaimantLimbs ? { escrowClaimantLimbs: parameters.escrowClaimantLimbs } : {},
|
|
2818
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
2468
2819
|
});
|
|
2469
2820
|
}
|
|
2470
2821
|
|
|
@@ -2488,11 +2839,20 @@ function stampDualWithdrawLegs(legs, parameters) {
|
|
|
2488
2839
|
}
|
|
2489
2840
|
};
|
|
2490
2841
|
}
|
|
2491
|
-
function buildDualTransferApplicationIds(sdk, applicationId, changeCoin) {
|
|
2842
|
+
function buildDualTransferApplicationIds(sdk, applicationId, changeCoin, feeCoin) {
|
|
2843
|
+
const outputIds = [applicationId];
|
|
2844
|
+
if (changeCoin) {
|
|
2845
|
+
outputIds.push(applicationId);
|
|
2846
|
+
} else if (!feeCoin) {
|
|
2847
|
+
outputIds.push("0");
|
|
2848
|
+
}
|
|
2849
|
+
if (feeCoin) {
|
|
2850
|
+
outputIds.push(applicationId);
|
|
2851
|
+
}
|
|
2492
2852
|
return buildApplicationIdHints({
|
|
2493
2853
|
sdk,
|
|
2494
2854
|
inputIds: [applicationId, applicationId],
|
|
2495
|
-
outputIds
|
|
2855
|
+
outputIds
|
|
2496
2856
|
});
|
|
2497
2857
|
}
|
|
2498
2858
|
async function proveDualConfidentialTransfer(parameters) {
|
|
@@ -2512,16 +2872,24 @@ async function proveDualConfidentialTransfer(parameters) {
|
|
|
2512
2872
|
audit
|
|
2513
2873
|
);
|
|
2514
2874
|
}
|
|
2515
|
-
|
|
2875
|
+
function dualTransferChangeStroops(parameters) {
|
|
2516
2876
|
const totalNotes = BigInt(parameters.coinA.value) + BigInt(parameters.coinB.value);
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2877
|
+
if (parameters.transferStroops < MIN_CONFIDENTIAL_TRANSFER_STROOPS) {
|
|
2878
|
+
throw new Error("Transfer amount must be positive");
|
|
2879
|
+
}
|
|
2880
|
+
const changeStroops = remainingAfterRequiredFee({
|
|
2881
|
+
available: totalNotes,
|
|
2882
|
+
instructed: parameters.transferStroops,
|
|
2883
|
+
requiredFee: parameters.feeOutput?.requiredFee ?? 0n
|
|
2884
|
+
});
|
|
2521
2885
|
requireChangeRecipientWhenPartial(
|
|
2522
2886
|
changeStroops,
|
|
2523
2887
|
parameters.selfPrivateAddressStpl1ForChange
|
|
2524
2888
|
);
|
|
2889
|
+
return changeStroops;
|
|
2890
|
+
}
|
|
2891
|
+
async function buildDualTransferProofContext(parameters, applicationId, sdk) {
|
|
2892
|
+
const changeStroops = dualTransferChangeStroops(parameters);
|
|
2525
2893
|
const privKeyScalar = privKeyScalarDecimalFromRecipientScalarHex(
|
|
2526
2894
|
parameters.senderPrivKeyScalarHex
|
|
2527
2895
|
);
|
|
@@ -2548,15 +2916,21 @@ async function buildDualTransferProofContext(parameters, applicationId, sdk) {
|
|
|
2548
2916
|
selfPrivateAddressStpl1ForChange: parameters.selfPrivateAddressStpl1ForChange,
|
|
2549
2917
|
tokenAddress: parameters.tokenAddress,
|
|
2550
2918
|
stateRoot: legA.witness.stateRoot,
|
|
2551
|
-
...confidentialEscrowFields(parameters)
|
|
2919
|
+
...confidentialEscrowFields(parameters),
|
|
2920
|
+
...parameters.feeOutput ? { feeOutput: parameters.feeOutput } : {}
|
|
2552
2921
|
});
|
|
2553
2922
|
return { legA, legB, applicationId, ...transferInputs };
|
|
2554
2923
|
}
|
|
2555
2924
|
async function prepareConfidentialTransferProofDual(parameters) {
|
|
2556
2925
|
const poolService = getPrivacyPoolService();
|
|
2557
|
-
const sdk = await poolService.getInitializedSdk(
|
|
2926
|
+
const sdk = await poolService.getInitializedSdk(
|
|
2927
|
+
poolService.feeBearingZkConfigNonce({
|
|
2928
|
+
kind: "transfer",
|
|
2929
|
+
...parameters.escrowClaimantLimbs ? { spendSource: "escrow" } : {}
|
|
2930
|
+
})
|
|
2931
|
+
);
|
|
2558
2932
|
const applicationId = poolService.getApplicationId();
|
|
2559
|
-
const { legA, legB, recipientSlot, deposits, changeCoin, publicInput } = await buildDualTransferProofContext(parameters, applicationId, sdk);
|
|
2933
|
+
const { legA, legB, recipientSlot, deposits, changeCoin, feeCoin, publicInput } = await buildDualTransferProofContext(parameters, applicationId, sdk);
|
|
2560
2934
|
const auditPublicKey = poolService.getAuditPublicKey();
|
|
2561
2935
|
const proof = await (auditPublicKey ? proveDualConfidentialTransfer({
|
|
2562
2936
|
sdk,
|
|
@@ -2579,7 +2953,8 @@ async function prepareConfidentialTransferProofDual(parameters) {
|
|
|
2579
2953
|
applicationIdsPlaintext: buildDualTransferApplicationIds(
|
|
2580
2954
|
sdk,
|
|
2581
2955
|
applicationId,
|
|
2582
|
-
changeCoin
|
|
2956
|
+
changeCoin,
|
|
2957
|
+
feeCoin
|
|
2583
2958
|
),
|
|
2584
2959
|
recipientCoin: generatedOutputCoinFromSlot(recipientSlot),
|
|
2585
2960
|
...changeCoin ? { changeCoin } : {}
|
|
@@ -2587,22 +2962,32 @@ async function prepareConfidentialTransferProofDual(parameters) {
|
|
|
2587
2962
|
}
|
|
2588
2963
|
|
|
2589
2964
|
// src/transact/proofs/confidential/single.ts
|
|
2590
|
-
function validateSingleCoinTransferAmounts(transferStroops, noteStroops, selfPrivateAddressStpl1ForChange) {
|
|
2965
|
+
function validateSingleCoinTransferAmounts(transferStroops, noteStroops, selfPrivateAddressStpl1ForChange, requiredFee) {
|
|
2591
2966
|
if (transferStroops < MIN_CONFIDENTIAL_TRANSFER_STROOPS) {
|
|
2592
2967
|
throw new Error("Transfer amount must be positive");
|
|
2593
2968
|
}
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2969
|
+
const changeStroops = remainingAfterRequiredFee({
|
|
2970
|
+
available: noteStroops,
|
|
2971
|
+
instructed: transferStroops,
|
|
2972
|
+
requiredFee
|
|
2973
|
+
});
|
|
2598
2974
|
requireChangeRecipientWhenPartial(changeStroops, selfPrivateAddressStpl1ForChange);
|
|
2599
2975
|
return changeStroops;
|
|
2600
2976
|
}
|
|
2601
|
-
function buildSingleTransferApplicationIds(sdk, applicationId, changeCoin) {
|
|
2977
|
+
function buildSingleTransferApplicationIds(sdk, applicationId, changeCoin, feeCoin) {
|
|
2978
|
+
const outputIds = [applicationId];
|
|
2979
|
+
if (changeCoin) {
|
|
2980
|
+
outputIds.push(applicationId);
|
|
2981
|
+
} else if (!feeCoin) {
|
|
2982
|
+
outputIds.push("0");
|
|
2983
|
+
}
|
|
2984
|
+
if (feeCoin) {
|
|
2985
|
+
outputIds.push(applicationId);
|
|
2986
|
+
}
|
|
2602
2987
|
return buildApplicationIdHints({
|
|
2603
2988
|
sdk,
|
|
2604
2989
|
inputIds: [applicationId],
|
|
2605
|
-
outputIds
|
|
2990
|
+
outputIds
|
|
2606
2991
|
});
|
|
2607
2992
|
}
|
|
2608
2993
|
function buildTransferAuditParameters(parameters) {
|
|
@@ -2628,11 +3013,25 @@ function confidentialEscrowFields2(input) {
|
|
|
2628
3013
|
...input.escrowClaimantLimbs ? { escrowClaimantLimbs: input.escrowClaimantLimbs } : {}
|
|
2629
3014
|
};
|
|
2630
3015
|
}
|
|
3016
|
+
function transferDepositInputFromProof(input, changeStroops, stateRoot) {
|
|
3017
|
+
return {
|
|
3018
|
+
senderPrivKeyScalarHex: input.senderPrivKeyScalarHex,
|
|
3019
|
+
recipientPrivateAddressStpl1: input.recipientPrivateAddressStpl1,
|
|
3020
|
+
transferStroops: input.transferStroops,
|
|
3021
|
+
changeStroops,
|
|
3022
|
+
selfPrivateAddressStpl1ForChange: input.selfPrivateAddressStpl1ForChange,
|
|
3023
|
+
tokenAddress: input.tokenAddress,
|
|
3024
|
+
stateRoot,
|
|
3025
|
+
...confidentialEscrowFields2(input),
|
|
3026
|
+
...input.feeOutput ? { feeOutput: input.feeOutput } : {}
|
|
3027
|
+
};
|
|
3028
|
+
}
|
|
2631
3029
|
async function buildTransferProofInputs(parameters) {
|
|
2632
3030
|
const changeStroops = validateSingleCoinTransferAmounts(
|
|
2633
3031
|
parameters.input.transferStroops,
|
|
2634
3032
|
parameters.noteStroops,
|
|
2635
|
-
parameters.input.selfPrivateAddressStpl1ForChange
|
|
3033
|
+
parameters.input.selfPrivateAddressStpl1ForChange,
|
|
3034
|
+
parameters.input.feeOutput?.requiredFee ?? 0n
|
|
2636
3035
|
);
|
|
2637
3036
|
const privKeyScalar = privKeyScalarDecimalFromRecipientScalarHex(
|
|
2638
3037
|
parameters.input.senderPrivKeyScalarHex
|
|
@@ -2651,31 +3050,30 @@ async function buildTransferProofInputs(parameters) {
|
|
|
2651
3050
|
withdrawObject,
|
|
2652
3051
|
sweepWithdrawStamp(confidentialEscrowFields2(parameters.input))
|
|
2653
3052
|
);
|
|
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
|
-
});
|
|
3053
|
+
const { recipientSlot, deposits, changeCoin, feeCoin, publicInput } = await buildSenderTransferDepositsAndPublicInput(
|
|
3054
|
+
transferDepositInputFromProof(parameters.input, changeStroops, witness.stateRoot)
|
|
3055
|
+
);
|
|
2664
3056
|
return {
|
|
2665
3057
|
witness,
|
|
2666
3058
|
withdrawObject: stampedWithdraw,
|
|
2667
3059
|
recipientSlot,
|
|
2668
3060
|
deposits,
|
|
2669
3061
|
changeCoin,
|
|
3062
|
+
feeCoin,
|
|
2670
3063
|
publicInput
|
|
2671
3064
|
};
|
|
2672
3065
|
}
|
|
2673
3066
|
async function prepareConfidentialTransferProof(parameters) {
|
|
2674
3067
|
const poolService = getPrivacyPoolService();
|
|
2675
|
-
const sdk = await poolService.getInitializedSdk(
|
|
3068
|
+
const sdk = await poolService.getInitializedSdk(
|
|
3069
|
+
poolService.feeBearingZkConfigNonce({
|
|
3070
|
+
kind: "transfer",
|
|
3071
|
+
...parameters.escrowClaimantLimbs ? { spendSource: "escrow" } : {}
|
|
3072
|
+
})
|
|
3073
|
+
);
|
|
2676
3074
|
const applicationId = poolService.getApplicationId();
|
|
2677
3075
|
const noteStroops = BigInt(parameters.coin.value);
|
|
2678
|
-
const { withdrawObject, recipientSlot, deposits, changeCoin, publicInput } = await buildTransferProofInputs({
|
|
3076
|
+
const { withdrawObject, recipientSlot, deposits, changeCoin, feeCoin, publicInput } = await buildTransferProofInputs({
|
|
2679
3077
|
sdk,
|
|
2680
3078
|
applicationId,
|
|
2681
3079
|
input: parameters,
|
|
@@ -2698,7 +3096,8 @@ async function prepareConfidentialTransferProof(parameters) {
|
|
|
2698
3096
|
applicationIdsPlaintext: buildSingleTransferApplicationIds(
|
|
2699
3097
|
sdk,
|
|
2700
3098
|
applicationId,
|
|
2701
|
-
changeCoin
|
|
3099
|
+
changeCoin,
|
|
3100
|
+
feeCoin
|
|
2702
3101
|
),
|
|
2703
3102
|
recipientCoin: generatedOutputCoinFromSlot(recipientSlot),
|
|
2704
3103
|
...changeCoin ? { changeCoin } : {}
|
|
@@ -5263,7 +5662,12 @@ function proofEscrowFields(input) {
|
|
|
5263
5662
|
}
|
|
5264
5663
|
async function buildSingleTransferProofAtExecute(input) {
|
|
5265
5664
|
const context = await buildSpendProofContextAtExecute(input);
|
|
5266
|
-
const
|
|
5665
|
+
const feeOutput = await quoteFeeOutputForPrepared({
|
|
5666
|
+
prepared: input.prepared,
|
|
5667
|
+
environment: input.environment,
|
|
5668
|
+
tokenAddress: context.tokenAddress
|
|
5669
|
+
});
|
|
5670
|
+
const changeStroops = BigInt(context.coin.value) - input.prepared.intent.amount - (feeOutput?.requiredFee ?? 0n);
|
|
5267
5671
|
const proof = await prepareConfidentialTransferProof({
|
|
5268
5672
|
coin: context.coin,
|
|
5269
5673
|
state: { commitments: context.commitments },
|
|
@@ -5276,7 +5680,8 @@ async function buildSingleTransferProofAtExecute(input) {
|
|
|
5276
5680
|
recipientPrivateAddressStpl1: context.recipientPrivateAddressStpl1,
|
|
5277
5681
|
selfPrivateAddressStpl1ForChange: readChangeRecipient(input, changeStroops),
|
|
5278
5682
|
tokenAddress: context.tokenAddress,
|
|
5279
|
-
...proofEscrowFields(input)
|
|
5683
|
+
...proofEscrowFields(input),
|
|
5684
|
+
...feeOutput ? { feeOutput } : {}
|
|
5280
5685
|
});
|
|
5281
5686
|
return { context, proof };
|
|
5282
5687
|
}
|
|
@@ -5293,7 +5698,12 @@ async function buildDualTransferProofAtExecute(input) {
|
|
|
5293
5698
|
commitments: context.commitments
|
|
5294
5699
|
});
|
|
5295
5700
|
const totalNotes = BigInt(context.coin.value) + BigInt(secondary.coin.value);
|
|
5296
|
-
const
|
|
5701
|
+
const feeOutput = await quoteFeeOutputForPrepared({
|
|
5702
|
+
prepared: input.prepared,
|
|
5703
|
+
environment: input.environment,
|
|
5704
|
+
tokenAddress: context.tokenAddress
|
|
5705
|
+
});
|
|
5706
|
+
const changeStroops = totalNotes - input.prepared.intent.amount - (feeOutput?.requiredFee ?? 0n);
|
|
5297
5707
|
const proof = await prepareConfidentialTransferProofDual({
|
|
5298
5708
|
coinA: context.coin,
|
|
5299
5709
|
coinB: secondary.coin,
|
|
@@ -5311,7 +5721,8 @@ async function buildDualTransferProofAtExecute(input) {
|
|
|
5311
5721
|
recipientPrivateAddressStpl1: context.recipientPrivateAddressStpl1,
|
|
5312
5722
|
selfPrivateAddressStpl1ForChange: readChangeRecipient(input, changeStroops),
|
|
5313
5723
|
tokenAddress: context.tokenAddress,
|
|
5314
|
-
...proofEscrowFields(input)
|
|
5724
|
+
...proofEscrowFields(input),
|
|
5725
|
+
...feeOutput ? { feeOutput } : {}
|
|
5315
5726
|
});
|
|
5316
5727
|
return { context, proof };
|
|
5317
5728
|
}
|
|
@@ -5443,11 +5854,17 @@ async function runTransferFinalizeSteps(input) {
|
|
|
5443
5854
|
walletPublicKey: input.walletPublicKey,
|
|
5444
5855
|
...recipient.escrowSend ? { escrowSendPrivateAddress: recipient.recipientPrivateAddressStpl1 } : {}
|
|
5445
5856
|
});
|
|
5446
|
-
return
|
|
5447
|
-
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5857
|
+
return {
|
|
5858
|
+
...buildTransferFinalizeArtifacts({
|
|
5859
|
+
proof,
|
|
5860
|
+
context,
|
|
5861
|
+
...sweepFinalizeStamp(input.prepared, recipient)
|
|
5862
|
+
}),
|
|
5863
|
+
zkConfigNonce: zkConfigNonceForFeeBearingKind({
|
|
5864
|
+
...feeOutputKindFromPrepared(input.prepared),
|
|
5865
|
+
...configuredNonceSpread(input.environment.zkConfigNonce)
|
|
5866
|
+
})
|
|
5867
|
+
};
|
|
5451
5868
|
}
|
|
5452
5869
|
function sweepArtifactStamp(artifacts) {
|
|
5453
5870
|
return {
|
|
@@ -5475,6 +5892,24 @@ async function finalizeTransferAtExecute(prepared, environment) {
|
|
|
5475
5892
|
return runTransferFinalizeSteps({ prepared, environment, walletPublicKey });
|
|
5476
5893
|
}
|
|
5477
5894
|
|
|
5895
|
+
// src/transact/engine/withdraw-fee.ts
|
|
5896
|
+
async function withdrawFeeProofFields(input) {
|
|
5897
|
+
const feeOutput = await quoteFeeOutputForPrepared({
|
|
5898
|
+
prepared: input.prepared,
|
|
5899
|
+
environment: input.environment,
|
|
5900
|
+
tokenAddress: input.tokenAddress
|
|
5901
|
+
});
|
|
5902
|
+
const changeStroops = remainingAfterRequiredFee({
|
|
5903
|
+
available: input.available,
|
|
5904
|
+
instructed: input.prepared.intent.amount,
|
|
5905
|
+
requiredFee: feeOutput?.requiredFee ?? 0n
|
|
5906
|
+
});
|
|
5907
|
+
return {
|
|
5908
|
+
...feeOutput ? { feeOutput } : {},
|
|
5909
|
+
...changeStroops > 0n ? { changePrivateAddressStpl1: input.withdrawFrom } : {}
|
|
5910
|
+
};
|
|
5911
|
+
}
|
|
5912
|
+
|
|
5478
5913
|
// src/transact/engine/execute.ts
|
|
5479
5914
|
function enrichWithdrawOutputRecords(prepared, proof) {
|
|
5480
5915
|
if (!proof.changeCoin || prepared.outputRecords.length === 0) {
|
|
@@ -5490,7 +5925,7 @@ function enrichWithdrawOutputRecords(prepared, proof) {
|
|
|
5490
5925
|
precommitementHex: changeCoin.precommitementHex
|
|
5491
5926
|
}));
|
|
5492
5927
|
}
|
|
5493
|
-
function buildWithdrawFinalizeArtifacts(proof, context) {
|
|
5928
|
+
function buildWithdrawFinalizeArtifacts(proof, context, environment) {
|
|
5494
5929
|
return {
|
|
5495
5930
|
proofHex: proof.proof_hex,
|
|
5496
5931
|
publicHex: proof.public_hex,
|
|
@@ -5498,7 +5933,11 @@ function buildWithdrawFinalizeArtifacts(proof, context) {
|
|
|
5498
5933
|
applicationIdsPlaintext: proof.applicationIdsPlaintext,
|
|
5499
5934
|
tokenAddress: context.tokenAddress,
|
|
5500
5935
|
walletPublicKey: context.walletPublicKey,
|
|
5501
|
-
executeFinalizeRequired: false
|
|
5936
|
+
executeFinalizeRequired: false,
|
|
5937
|
+
zkConfigNonce: zkConfigNonceForFeeBearingKind({
|
|
5938
|
+
kind: "withdraw",
|
|
5939
|
+
...configuredNonceSpread(environment.zkConfigNonce)
|
|
5940
|
+
})
|
|
5502
5941
|
};
|
|
5503
5942
|
}
|
|
5504
5943
|
async function finalizeSingleWithdrawAtExecute(prepared, environment, poolService, withdrawFrom) {
|
|
@@ -5507,7 +5946,13 @@ async function finalizeSingleWithdrawAtExecute(prepared, environment, poolServic
|
|
|
5507
5946
|
environment,
|
|
5508
5947
|
recipientPrivateAddressStpl1: withdrawFrom
|
|
5509
5948
|
});
|
|
5510
|
-
const
|
|
5949
|
+
const feeFields = await withdrawFeeProofFields({
|
|
5950
|
+
prepared,
|
|
5951
|
+
environment,
|
|
5952
|
+
tokenAddress: context.tokenAddress,
|
|
5953
|
+
available: BigInt(context.coin.value),
|
|
5954
|
+
withdrawFrom
|
|
5955
|
+
});
|
|
5511
5956
|
const proof = await poolService.prepareWithdrawTransactProof({
|
|
5512
5957
|
coin: context.coin,
|
|
5513
5958
|
state: { commitments: context.commitments },
|
|
@@ -5518,11 +5963,24 @@ async function finalizeSingleWithdrawAtExecute(prepared, environment, poolServic
|
|
|
5518
5963
|
yHex: context.ephemeral.yHex
|
|
5519
5964
|
}),
|
|
5520
5965
|
withdrawAmountStroops: prepared.intent.amount,
|
|
5521
|
-
changePrivateAddressStpl1:
|
|
5522
|
-
tokenAddress: context.tokenAddress
|
|
5966
|
+
changePrivateAddressStpl1: feeFields.changePrivateAddressStpl1,
|
|
5967
|
+
tokenAddress: context.tokenAddress,
|
|
5968
|
+
...feeFields.feeOutput ? { feeOutput: feeFields.feeOutput } : {}
|
|
5523
5969
|
});
|
|
5524
5970
|
enrichWithdrawOutputRecords(prepared, proof);
|
|
5525
|
-
return buildWithdrawFinalizeArtifacts(proof, context);
|
|
5971
|
+
return buildWithdrawFinalizeArtifacts(proof, context, environment);
|
|
5972
|
+
}
|
|
5973
|
+
function dualWithdrawEphemeralKeys(input) {
|
|
5974
|
+
return {
|
|
5975
|
+
depositorEphemeralAKey: serializeEphemeralKeyString({
|
|
5976
|
+
xHex: input.context.ephemeral.xHex,
|
|
5977
|
+
yHex: input.context.ephemeral.yHex
|
|
5978
|
+
}),
|
|
5979
|
+
depositorEphemeralBKey: serializeEphemeralKeyString({
|
|
5980
|
+
xHex: input.secondary.ephemeral.xHex,
|
|
5981
|
+
yHex: input.secondary.ephemeral.yHex
|
|
5982
|
+
})
|
|
5983
|
+
};
|
|
5526
5984
|
}
|
|
5527
5985
|
async function finalizeDualWithdrawAtExecute(prepared, environment, poolService, withdrawFrom) {
|
|
5528
5986
|
const [, secondaryRecord] = prepared.consumedRecords;
|
|
@@ -5540,28 +5998,27 @@ async function finalizeDualWithdrawAtExecute(prepared, environment, poolService,
|
|
|
5540
5998
|
walletPublicKey: context.walletPublicKey,
|
|
5541
5999
|
commitments: context.commitments
|
|
5542
6000
|
});
|
|
5543
|
-
const
|
|
5544
|
-
|
|
6001
|
+
const feeFields = await withdrawFeeProofFields({
|
|
6002
|
+
prepared,
|
|
6003
|
+
environment,
|
|
6004
|
+
tokenAddress: context.tokenAddress,
|
|
6005
|
+
available: BigInt(context.coin.value) + BigInt(secondary.coin.value),
|
|
6006
|
+
withdrawFrom
|
|
6007
|
+
});
|
|
5545
6008
|
const proof = await poolService.prepareWithdrawTransactProofDual({
|
|
5546
6009
|
coinA: context.coin,
|
|
5547
6010
|
coinB: secondary.coin,
|
|
5548
6011
|
state: { commitments: context.commitments },
|
|
5549
6012
|
destinationStellarAddress: prepared.intent.to,
|
|
5550
6013
|
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
|
-
}),
|
|
6014
|
+
...dualWithdrawEphemeralKeys({ context, secondary }),
|
|
5559
6015
|
withdrawAmountStroops: prepared.intent.amount,
|
|
5560
|
-
changePrivateAddressStpl1:
|
|
5561
|
-
tokenAddress: context.tokenAddress
|
|
6016
|
+
changePrivateAddressStpl1: feeFields.changePrivateAddressStpl1,
|
|
6017
|
+
tokenAddress: context.tokenAddress,
|
|
6018
|
+
...feeFields.feeOutput ? { feeOutput: feeFields.feeOutput } : {}
|
|
5562
6019
|
});
|
|
5563
6020
|
enrichWithdrawOutputRecords(prepared, proof);
|
|
5564
|
-
return buildWithdrawFinalizeArtifacts(proof, context);
|
|
6021
|
+
return buildWithdrawFinalizeArtifacts(proof, context, environment);
|
|
5565
6022
|
}
|
|
5566
6023
|
async function finalizeWithdrawAtExecute(prepared, environment, poolService) {
|
|
5567
6024
|
if (prepared.kind !== "withdraw") {
|
|
@@ -5787,10 +6244,11 @@ function requirePreparedArtifacts(prepared) {
|
|
|
5787
6244
|
};
|
|
5788
6245
|
}
|
|
5789
6246
|
function prepareRelayTransactPackageFromPrepared(input) {
|
|
6247
|
+
const zkConfigNonce = input.zkConfigNonce ?? input.prepared.transactArtifacts?.zkConfigNonce;
|
|
5790
6248
|
return prepareRelayTransactPackage({
|
|
5791
6249
|
poolSelector: input.poolSelector,
|
|
5792
6250
|
...requirePreparedArtifacts(input.prepared),
|
|
5793
|
-
...
|
|
6251
|
+
...zkConfigNonce === void 0 ? {} : { zkConfigNonce },
|
|
5794
6252
|
...input.keyVersionHints ? { keyVersionHints: input.keyVersionHints } : {}
|
|
5795
6253
|
});
|
|
5796
6254
|
}
|
|
@@ -5900,6 +6358,7 @@ function requiredSubmissionMethod(prepared, zkConfigNonce = DEFAULT_ZK_CONFIG_NO
|
|
|
5900
6358
|
return result.method;
|
|
5901
6359
|
}
|
|
5902
6360
|
export {
|
|
6361
|
+
BINDING_ZK_NONCE,
|
|
5903
6362
|
BundledZkCircuit2 as BundledZkCircuit,
|
|
5904
6363
|
COMMITMENT_V2_ZK_NONCE,
|
|
5905
6364
|
DEFAULT_STEALTH_SIGN_NONCE as DEFAULT_PRIVATE_ADDRESS_SIGN_NONCE,
|
|
@@ -5928,6 +6387,7 @@ export {
|
|
|
5928
6387
|
RELAY_TRANSACT_PACKAGE_VERSION_V1,
|
|
5929
6388
|
RELAY_TRANSACT_SIGNAL_PREFIX_BYTES,
|
|
5930
6389
|
RELAY_TRANSACT_SUPPORTED_SIGNAL_COUNT,
|
|
6390
|
+
SIX_BY_SIX_BINDING_ZK_NONCE,
|
|
5931
6391
|
SIX_BY_SIX_ZK_NONCE,
|
|
5932
6392
|
STANDARD_ZK_CONFIG_NONCE,
|
|
5933
6393
|
SUBMISSION_METHOD,
|