@invisi-labs/protocol 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,3613 @@
1
+ import {
2
+ invisiAddressRegistryAbi,
3
+ invisiFactoryAbi,
4
+ invisiProtocolAbi
5
+ } from "./chunk-XTOQXQES.js";
6
+
7
+ // src/AddressRegistry.ts
8
+ import { getAddress as getAddress6, keccak256 as keccak2566 } from "ethers";
9
+ import {
10
+ MissingCapabilityError as MissingCapabilityError2,
11
+ ReceivingAddress as ReceivingAddress3
12
+ } from "@invisi-labs/core";
13
+
14
+ // src/RegistrationOperation.ts
15
+ import { hexlify as hexlify2, Interface as Interface5 } from "ethers";
16
+ import {
17
+ computeWalletAuthorizationDigest as computeWalletAuthorizationDigest5,
18
+ MissingCapabilityError,
19
+ ReceivingAddress as ReceivingAddress2
20
+ } from "@invisi-labs/core";
21
+
22
+ // src/registry.ts
23
+ import {
24
+ Contract,
25
+ Interface,
26
+ concat,
27
+ getAddress,
28
+ getBytes,
29
+ hexlify,
30
+ isHexString,
31
+ keccak256,
32
+ toBeHex
33
+ } from "ethers";
34
+ import {
35
+ ReceivingAddress,
36
+ computeWalletAuthorizationDigest,
37
+ decodeAddress,
38
+ walletAuthorizationTypedData
39
+ } from "@invisi-labs/core";
40
+ var MAX_NONCE = (1n << 64n) - 1n;
41
+ var MASK128 = (1n << 128n) - 1n;
42
+ function uint64(value, name) {
43
+ if (typeof value !== "bigint" || value < 0n || value > MAX_NONCE)
44
+ throw new RangeError(`${name} must be uint64`);
45
+ return value;
46
+ }
47
+ function hexBytes(value, length) {
48
+ if (typeof value !== "string" || !isHexString(value) || value.length !== 2 + length * 2)
49
+ throw new Error(`Expected ${length} hexadecimal bytes`);
50
+ return getBytes(value);
51
+ }
52
+ function normalizeKeys(walletIdentity, keys) {
53
+ const decoded = decodeAddress(
54
+ ReceivingAddress.from({
55
+ walletIdentity,
56
+ viewingPublicKey: hexBytes(keys.viewingPublicKey, 33),
57
+ clueKey: hexBytes(keys.clueKey, 32)
58
+ }).toString()
59
+ );
60
+ if (decoded.kind !== "long") throw new Error("Expected full receiving address");
61
+ return {
62
+ viewingPublicKey: hexlify(decoded.viewingPublicKey),
63
+ clueKey: hexlify(decoded.clueKey)
64
+ };
65
+ }
66
+ function normalize(context, registration, options) {
67
+ uint64(context.chainId, "chainId");
68
+ const registryAddress = getAddress(context.registryAddress);
69
+ if (BigInt(registryAddress) === 0n) throw new Error("Registry address must be nonzero");
70
+ const walletIdentity = decodeAddress(
71
+ ReceivingAddress.fromIdentity(registration.walletIdentity).toString()
72
+ ).walletIdentity;
73
+ const keys = normalizeKeys(walletIdentity, registration.keys);
74
+ const nonce = uint64(registration.nonce, "nonce"), deadline = uint64(registration.deadline, "deadline");
75
+ if (nonce === MAX_NONCE) throw new Error("Registry nonce exhausted");
76
+ if (options.update !== void 0 && typeof options.update !== "boolean")
77
+ throw new TypeError("update must be boolean");
78
+ if (!options.update && nonce !== 0n)
79
+ throw new Error("Initial registration requires nonce zero");
80
+ if (options.expectedNonce !== void 0 && uint64(options.expectedNonce, "expectedNonce") !== nonce)
81
+ throw new Error("Registry nonce mismatch");
82
+ if (context.now !== void 0 && deadline < uint64(context.now, "now"))
83
+ throw new Error("Registration expired");
84
+ return { registryAddress, registration: { walletIdentity, keys, nonce, deadline } };
85
+ }
86
+ function registrationAuthorizationRequest(context, registration, options = {}) {
87
+ const normalized = normalize(context, registration, options), r = normalized.registration;
88
+ const keysHash = BigInt(
89
+ keccak256(concat([r.keys.viewingPublicKey, r.keys.clueKey]))
90
+ );
91
+ return {
92
+ context: { chainId: context.chainId, protocolAddress: BigInt(normalized.registryAddress) },
93
+ operation: options.update ? "update-address" : "register-address",
94
+ capacity: 0,
95
+ words: [
96
+ context.chainId,
97
+ BigInt(normalized.registryAddress),
98
+ BigInt(r.walletIdentity),
99
+ r.nonce,
100
+ r.deadline,
101
+ keysHash >> 128n,
102
+ keysHash & MASK128
103
+ ]
104
+ };
105
+ }
106
+ function registrationTypedData(context, registration, options = {}) {
107
+ return walletAuthorizationTypedData(
108
+ registrationAuthorizationRequest(context, registration, options)
109
+ );
110
+ }
111
+ function registrationPublicInputs(context, registration, options = {}) {
112
+ const request = registrationAuthorizationRequest(context, registration, options);
113
+ const digest = BigInt(computeWalletAuthorizationDigest(request));
114
+ return [
115
+ toBeHex(request.words[2], 32),
116
+ toBeHex(digest >> 128n, 32),
117
+ toBeHex(digest & MASK128, 32)
118
+ ];
119
+ }
120
+ function buildRegistrationCalldata(context, registration, proof, options = {}) {
121
+ const normalized = normalize(context, registration, options);
122
+ if (typeof proof !== "string" || !isHexString(proof) || proof.length <= 2 || proof.length % 2 !== 0)
123
+ throw new Error("Registration proof must be nonempty hexadecimal bytes");
124
+ return {
125
+ to: normalized.registryAddress,
126
+ value: 0n,
127
+ callData: new Interface(invisiAddressRegistryAbi).encodeFunctionData(
128
+ options.update ? "updateKeys" : "registerKeys",
129
+ [
130
+ {
131
+ ...normalized.registration,
132
+ walletIdentity: toBeHex(BigInt(normalized.registration.walletIdentity), 32)
133
+ },
134
+ proof
135
+ ]
136
+ ),
137
+ publicInputs: registrationPublicInputs(context, normalized.registration, options)
138
+ };
139
+ }
140
+ function createRegistryReceivingKeyLookup(client, registryAddress) {
141
+ const address = getAddress(registryAddress);
142
+ if (BigInt(address) === 0n) throw new Error("Registry address must be nonzero");
143
+ return async (walletIdentity) => {
144
+ const identity = decodeAddress(
145
+ ReceivingAddress.fromIdentity(walletIdentity).toString()
146
+ ).walletIdentity;
147
+ const [keys, nonce] = await new Contract(
148
+ address,
149
+ invisiAddressRegistryAbi,
150
+ client
151
+ ).getFunction("receivingKeysOf")(toBeHex(BigInt(identity), 32));
152
+ uint64(nonce, "registry nonce");
153
+ const normalized = normalizeKeys(identity, keys);
154
+ return {
155
+ viewingPublicKey: getBytes(normalized.viewingPublicKey),
156
+ clueKey: getBytes(normalized.clueKey)
157
+ };
158
+ };
159
+ }
160
+
161
+ // src/witness.ts
162
+ import {
163
+ computeCreditCommitment,
164
+ computeCreditNullifier,
165
+ computeCreditSharedKeyHash,
166
+ computeNoteCommitment as computeNoteCommitment2,
167
+ computeNoteIdentity,
168
+ computeNoteNullifier,
169
+ computeWalletAuthorizationDigest as computeWalletAuthorizationDigest4,
170
+ normalizeCreditDeliveryState,
171
+ poseidonHash,
172
+ verifyWalletAuthorization
173
+ } from "@invisi-labs/core";
174
+ import {
175
+ LocalWitness
176
+ } from "@invisi-labs/prover";
177
+
178
+ // src/credit-create.ts
179
+ import {
180
+ AbiCoder as AbiCoder2,
181
+ dataLength as dataLength2,
182
+ getAddress as getAddress3,
183
+ Interface as Interface2,
184
+ isHexString as isHexString3,
185
+ keccak256 as keccak2563,
186
+ ParamType as ParamType2
187
+ } from "ethers";
188
+ import { computeWalletAuthorizationDigest as computeWalletAuthorizationDigest2, walletAuthorizationTypedData as walletAuthorizationTypedData2 } from "@invisi-labs/core";
189
+
190
+ // src/validation.ts
191
+ import {
192
+ AbiCoder,
193
+ dataLength,
194
+ getAddress as getAddress2,
195
+ isHexString as isHexString2,
196
+ keccak256 as keccak2562,
197
+ ParamType,
198
+ toBeHex as toBeHex2
199
+ } from "ethers";
200
+ var FIELD_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
201
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
202
+ var ZERO_WORD = toBeHex2(0n, 32);
203
+ var EMPTY_PERMIT = {
204
+ deadline: 0n,
205
+ v: 0,
206
+ r: ZERO_WORD,
207
+ s: ZERO_WORD
208
+ };
209
+ var EMPTY_FUNDING = {
210
+ payer: ZERO_ADDRESS,
211
+ amount: 0n,
212
+ sigNonce: 0n,
213
+ deadline: 0n,
214
+ signature: "0x",
215
+ permit: EMPTY_PERMIT
216
+ };
217
+ function uint(v, bits, name = "value") {
218
+ if (typeof v !== "bigint" && typeof v !== "number" && typeof v !== "string" || typeof v === "number" && !Number.isSafeInteger(v))
219
+ throw new Error(`${name} must be an integer`);
220
+ const n = BigInt(v);
221
+ if (n < 0n || n >= 1n << BigInt(bits)) throw new Error(`${name} exceeds u${bits}`);
222
+ return n;
223
+ }
224
+ function field(v, name = "field") {
225
+ const n = uint(v, 256, name);
226
+ if (n >= FIELD_MODULUS) throw new Error(`${name} is noncanonical field`);
227
+ return n;
228
+ }
229
+ var word = (v) => toBeHex2(typeof v === "bigint" ? v : BigInt(v), 32);
230
+ function dense(v, name) {
231
+ if (!Array.isArray(v)) throw new Error(`${name} must be array`);
232
+ for (let i = 0; i < v.length; i++)
233
+ if (!Object.hasOwn(v, i) || v[i] === void 0 || v[i] === null)
234
+ throw new Error(`${name} has missing or sparse entries`);
235
+ return v;
236
+ }
237
+ function known(v, keys, name = "params") {
238
+ if (!v || typeof v !== "object" || Array.isArray(v) || Object.keys(v).some((k) => !keys.includes(k)))
239
+ throw new Error(`${name} has unsupported fields`);
240
+ }
241
+ function notes(v, name) {
242
+ const r = dense(v, name).map((v2) => word(field(v2, name)));
243
+ if (r.some((v2) => BigInt(v2) === 0n) || new Set(r).size !== r.length)
244
+ throw new Error(`duplicate or zero ${name}`);
245
+ return r;
246
+ }
247
+ function envelope(v, length, version) {
248
+ if (!isHexString2(v) || !/^0x(?:[a-fA-F0-9]{2})*$/.test(v) || dataLength(v) !== length)
249
+ throw new Error(`ciphertext must be ${length} bytes`);
250
+ if (version !== void 0 && Number.parseInt(v.slice(2, 4), 16) !== version)
251
+ throw new Error("unsupported ciphertext envelope version");
252
+ return v;
253
+ }
254
+ function normalizeContext(c) {
255
+ return {
256
+ ...c,
257
+ chainId: uint(c.chainId, 64, "chainId"),
258
+ protocolAddress: getAddress2(c.protocolAddress),
259
+ tokenAddress: getAddress2(c.tokenAddress)
260
+ };
261
+ }
262
+ function checkDeadline(c, value) {
263
+ const n = uint(value, 64, "deadline");
264
+ if (c.now !== void 0 && n < uint(c.now, 64, "now")) throw new Error("deadline has expired");
265
+ return n;
266
+ }
267
+ function normalizeSources(sources, inputCount, capacity) {
268
+ dense(sources, "sources");
269
+ if (inputCount < 0 || inputCount > capacity || sources.length > inputCount || (inputCount === 0 ? sources.length !== 0 : sources.length === 0))
270
+ throw new Error("source count must be 1..inputCount, or empty for zero inputs");
271
+ let previous = 0n;
272
+ return sources.map((s) => {
273
+ known(s, ["treeId", "merkleRoot"], "source");
274
+ const treeId = uint(s.treeId, 64, "treeId"), merkleRoot = word(field(s.merkleRoot, "merkleRoot"));
275
+ if (treeId === 0n || treeId <= previous || BigInt(merkleRoot) === 0n)
276
+ throw new Error("sources must have positive roots and strictly ascending tree IDs");
277
+ previous = treeId;
278
+ return { treeId, merkleRoot };
279
+ });
280
+ }
281
+ var pad = (v, n) => [
282
+ ...v,
283
+ ...Array(n - v.length).fill(0n)
284
+ ];
285
+ function normalizeDelivery(value, options = {}) {
286
+ known(value, ["ciphertext", "clue"], "delivery");
287
+ if (options.empty) {
288
+ if (value.ciphertext !== "0x" || value.clue !== "0x")
289
+ throw new Error("absent output requires an empty delivery");
290
+ return { ciphertext: "0x", clue: "0x" };
291
+ }
292
+ const ciphertext = envelope(
293
+ value.ciphertext,
294
+ options.credit ? 400 : 158,
295
+ options.credit ? 3 : 1
296
+ );
297
+ const clue = envelope(value.clue, 68);
298
+ if (clue.slice(130, 132).toLowerCase() !== "18") throw new Error("clue precision must be 24");
299
+ return { ciphertext, clue };
300
+ }
301
+ var deliveriesHash = (v) => keccak2562(
302
+ AbiCoder.defaultAbiCoder().encode(
303
+ [
304
+ {
305
+ type: "tuple[]",
306
+ components: [
307
+ { name: "ciphertext", type: "bytes" },
308
+ { name: "clue", type: "bytes" }
309
+ ]
310
+ }
311
+ ].map((parameter) => ParamType.from(parameter)),
312
+ [dense(v, "deliveries")]
313
+ )
314
+ );
315
+ function normalizeFunding(input = {}) {
316
+ const f = { ...EMPTY_FUNDING, ...input };
317
+ getAddress2(f.payer);
318
+ uint(f.amount, 128, "depositAmount");
319
+ uint(f.sigNonce, 256, "sigNonce");
320
+ uint(f.deadline, 256, "funding deadline");
321
+ if (!isHexString2(f.signature) || !/^0x(?:[a-fA-F0-9]{2})*$/.test(f.signature))
322
+ throw new Error("invalid signature bytes");
323
+ const p = f.permit;
324
+ uint(p.deadline, 256);
325
+ uint(p.v, 8);
326
+ for (const v of [p.r, p.s])
327
+ if (!isHexString2(v) || dataLength(v) !== 32) throw new Error("permit r/s must be bytes32");
328
+ if (f.amount === 0n !== (BigInt(f.payer) === 0n))
329
+ throw new Error("deposit amount and payer must both be zero or positive");
330
+ if (f.amount === 0n && (f.sigNonce !== 0n || f.deadline !== 0n || f.signature !== "0x" || p.deadline !== 0n || p.v !== 0 || BigInt(p.r) !== 0n || BigInt(p.s) !== 0n))
331
+ throw new Error("zero funding must be entirely empty");
332
+ return { ...f, payer: getAddress2(f.payer) };
333
+ }
334
+ function validateFundingSubmission(f, caller, now) {
335
+ if (f.signature !== "0x" && now !== void 0 && uint(now, 64, "now") > f.deadline)
336
+ throw new Error("funding authorization has expired");
337
+ if (f.signature === "0x" && (f.sigNonce !== 0n || f.deadline !== 0n || caller !== void 0 && f.amount > 0n && getAddress2(caller) !== f.payer))
338
+ throw new Error("direct funding requires payer caller and zero nonce/deadline");
339
+ }
340
+ var getEIP712Domain = (c) => ({
341
+ name: "InvisibleProtocol",
342
+ version: "1",
343
+ chainId: uint(c.chainId, 64),
344
+ verifyingContract: getAddress2(c.protocolAddress)
345
+ });
346
+ var fundingFields = [
347
+ { name: "requestHash", type: "bytes32" },
348
+ { name: "payer", type: "address" },
349
+ { name: "amount", type: "uint256" },
350
+ { name: "sigNonce", type: "uint256" },
351
+ { name: "deadline", type: "uint256" }
352
+ ];
353
+
354
+ // src/credit-create.ts
355
+ var creationTuple = [
356
+ "(address token,(uint256 treeId,bytes32 merkleRoot)[] sources,bytes32[] nullifiers,bytes32 creditCommitment,bytes32 changeCommitment,address owner,uint256 expiry,uint256 deadline)"
357
+ ][0];
358
+ var CREATE_CREDIT_FIELDS = [
359
+ "token",
360
+ "sources",
361
+ "nullifiers",
362
+ "creditCommitment",
363
+ "changeCommitment",
364
+ "owner",
365
+ "expiry",
366
+ "deadline"
367
+ ];
368
+ function validateCreateCreditRequest(c, p, cs, funding = {}) {
369
+ known(p, CREATE_CREDIT_FIELDS);
370
+ if (getAddress3(p.token) !== getAddress3(c.tokenAddress))
371
+ throw new Error("request token mismatch");
372
+ const ctx = normalizeContext(c), ns = notes(p.nullifiers, "nullifiers"), sources = normalizeSources(p.sources, ns.length, 10), creditCommitment = word(field(p.creditCommitment)), changeCommitment = word(field(p.changeCommitment)), owner = getAddress3(p.owner), expiry = uint(p.expiry, 64, "expiry"), deadline = checkDeadline(c, p.deadline), f = normalizeFunding(funding);
373
+ if (BigInt(creditCommitment) === 0n || creditCommitment === changeCommitment)
374
+ throw new Error("zero or duplicate commitment");
375
+ if (BigInt(owner) === 0n || expiry === 0n || c.now !== void 0 && expiry <= c.now)
376
+ throw new Error("owner must be nonzero and expiry future");
377
+ if (dense(cs, "deliveries").length !== 3) throw new Error("deliveries count mismatch");
378
+ const deliveries = cs.map(
379
+ (v, i) => normalizeDelivery(v, { credit: i < 2, empty: i === 2 && BigInt(changeCommitment) === 0n })
380
+ );
381
+ if (ns.length === 0 && f.amount === 0n)
382
+ throw new Error("empty inputs require positive funding");
383
+ return {
384
+ ...ctx,
385
+ sources,
386
+ nullifiers: ns,
387
+ actualCount: ns.length,
388
+ sourceCount: sources.length,
389
+ creditCommitment,
390
+ changeCommitment,
391
+ owner,
392
+ expiry,
393
+ deadline,
394
+ deliveries,
395
+ funding: f
396
+ };
397
+ }
398
+ function createCreditBaseInputs(c, p, cs, f = {}) {
399
+ const r = validateCreateCreditRequest(c, p, cs, f), h = BigInt(deliveriesHash(cs));
400
+ return [
401
+ r.chainId,
402
+ BigInt(r.protocolAddress),
403
+ BigInt(r.tokenAddress),
404
+ BigInt(r.owner),
405
+ BigInt(r.actualCount),
406
+ BigInt(r.sourceCount),
407
+ ...pad(
408
+ r.sources.map((s) => s.treeId),
409
+ 10
410
+ ),
411
+ ...pad(
412
+ r.sources.map((s) => BigInt(s.merkleRoot)),
413
+ 10
414
+ ),
415
+ ...pad(r.nullifiers.map(BigInt), 10),
416
+ BigInt(r.creditCommitment),
417
+ BigInt(r.changeCommitment),
418
+ h >> 128n,
419
+ h & (1n << 128n) - 1n,
420
+ r.expiry,
421
+ r.deadline,
422
+ r.funding.amount,
423
+ BigInt(r.funding.payer)
424
+ ].map(word);
425
+ }
426
+ function createCreditPublicInputs(c, p, deliveries, funding = {}) {
427
+ const base = createCreditBaseInputs(c, p, deliveries, funding);
428
+ const digest = BigInt(
429
+ computeWalletAuthorizationDigest2({
430
+ context: { chainId: c.chainId, protocolAddress: BigInt(c.protocolAddress) },
431
+ operation: "create-credit",
432
+ capacity: 10,
433
+ words: base.map(BigInt)
434
+ })
435
+ );
436
+ return [...base, word(digest >> 128n), word(digest & (1n << 128n) - 1n)];
437
+ }
438
+ var hashContext = {
439
+ chainId: 0n,
440
+ protocolAddress: ZERO_ADDRESS,
441
+ tokenAddress: ZERO_ADDRESS
442
+ };
443
+ function createCreditRequestHash(p, cs, f = {}) {
444
+ const r = validateCreateCreditRequest({ ...hashContext, tokenAddress: p.token }, p, cs, f);
445
+ return keccak2563(
446
+ AbiCoder2.defaultAbiCoder().encode(
447
+ [
448
+ { type: "bytes32" },
449
+ creationTuple,
450
+ { type: "bytes32" },
451
+ { type: "address" },
452
+ { type: "uint256" }
453
+ ].map((parameter) => ParamType2.from(parameter)),
454
+ [
455
+ keccak2563(new TextEncoder().encode("InvisiCreateCredit")),
456
+ p,
457
+ deliveriesHash(cs),
458
+ r.funding.payer,
459
+ r.funding.amount
460
+ ]
461
+ )
462
+ );
463
+ }
464
+ function encodeCreateCreditTypedData(c, p, deliveries, funding = {}) {
465
+ return walletAuthorizationTypedData2({
466
+ context: { chainId: c.chainId, protocolAddress: BigInt(c.protocolAddress) },
467
+ operation: "create-credit",
468
+ capacity: 10,
469
+ words: createCreditBaseInputs(c, p, deliveries, funding).map(BigInt)
470
+ });
471
+ }
472
+ function encodeCreateCreditFundingTypedData(c, p, cs, f) {
473
+ const r = validateCreateCreditRequest(c, p, cs, f);
474
+ if (r.funding.amount === 0n) throw new Error("funding authorization requires positive deposit");
475
+ return {
476
+ domain: getEIP712Domain(c),
477
+ primaryType: "FundTransact",
478
+ types: { FundTransact: fundingFields },
479
+ message: {
480
+ requestHash: createCreditRequestHash(p, cs, f),
481
+ payer: r.funding.payer,
482
+ amount: r.funding.amount,
483
+ sigNonce: r.funding.sigNonce,
484
+ deadline: r.funding.deadline
485
+ }
486
+ };
487
+ }
488
+ function buildCreateCreditCalldata(p) {
489
+ const r = validateCreateCreditRequest(p.context, p.params, p.deliveries, p.funding);
490
+ validateFundingSubmission(r.funding, p.caller, p.context.now);
491
+ return {
492
+ data: new Interface2(invisiProtocolAbi).encodeFunctionData("createCredit", [
493
+ encodeCreditProof(p.proof),
494
+ p.params,
495
+ p.deliveries,
496
+ r.funding
497
+ ]),
498
+ approveAmount: r.funding.amount
499
+ };
500
+ }
501
+ function encodeCreditProof(proof) {
502
+ if (!isHexString3(proof) || !/^0x(?:[a-fA-F0-9]{2})*$/.test(proof) || dataLength2(proof) === 0)
503
+ throw new Error("empty or malformed Credit proof");
504
+ return AbiCoder2.defaultAbiCoder().encode(
505
+ ["uint8", "bytes"].map((parameter) => ParamType2.from(parameter)),
506
+ [0, proof]
507
+ );
508
+ }
509
+
510
+ // src/credit-lifecycle.ts
511
+ import { AbiCoder as AbiCoder3, getAddress as getAddress4, Interface as Interface3, keccak256 as keccak2564, ParamType as ParamType3 } from "ethers";
512
+ import {
513
+ computeWalletAuthorizationDigest as computeWalletAuthorizationDigest3,
514
+ walletAuthorizationTypedData as walletAuthorizationTypedData3
515
+ } from "@invisi-labs/core";
516
+ var CREDIT_DRAW_CAPACITIES = [1, 12, 50, 120];
517
+ function selectCreditDrawCircuit(count) {
518
+ if (!Number.isInteger(count) || count < 1 || count > 120)
519
+ throw new Error("draw requires 1..120 credits");
520
+ const maxSize = CREDIT_DRAW_CAPACITIES.find((n) => count <= n);
521
+ return {
522
+ name: `credit_draw_slots${maxSize}`,
523
+ maxSize,
524
+ publicInputCount: 6 * maxSize + 12,
525
+ totalBits: 126 + Math.ceil(Math.log2(maxSize))
526
+ };
527
+ }
528
+ function validateCreditDrawRequest(c, p, cs) {
529
+ known(p, [
530
+ "token",
531
+ "sources",
532
+ "nullifiers",
533
+ "remainderCommitments",
534
+ "expiries",
535
+ "recoveryAmounts",
536
+ "spender",
537
+ "totalAmount",
538
+ "deadline"
539
+ ]);
540
+ if (getAddress4(p.token) !== getAddress4(c.tokenAddress))
541
+ throw new Error("request token mismatch");
542
+ const ctx = normalizeContext(c), ns = notes(p.nullifiers, "nullifiers"), profile = selectCreditDrawCircuit(ns.length), sources = normalizeSources(p.sources, ns.length, profile.maxSize);
543
+ for (const [key, v] of Object.entries({
544
+ remainderCommitments: p.remainderCommitments,
545
+ expiries: p.expiries,
546
+ recoveryAmounts: p.recoveryAmounts
547
+ }))
548
+ if (dense(v, key).length !== ns.length) throw new Error(`${key} count mismatch`);
549
+ const remainderCommitments = p.remainderCommitments.map((v) => word(field(v))), recoveryAmounts = p.recoveryAmounts.map((v) => word(field(v))), expiries = p.expiries.map((v) => uint(v, 64, "expiry")), positives = remainderCommitments.filter((v) => BigInt(v) !== 0n);
550
+ if (new Set(positives).size !== positives.length)
551
+ throw new Error("duplicate remainder commitment");
552
+ for (let i = 0; i < ns.length; i++) {
553
+ if (expiries[i] === 0n || c.now !== void 0 && expiries[i] <= c.now)
554
+ throw new Error("expiry must be future");
555
+ if (BigInt(remainderCommitments[i]) === 0n && BigInt(recoveryAmounts[i]) !== 0n)
556
+ throw new Error("full draw requires zero recovery amount");
557
+ }
558
+ const spender = getAddress4(p.spender), totalAmount = uint(p.totalAmount, profile.totalBits, "totalAmount");
559
+ if (BigInt(spender) === 0n || totalAmount === 0n)
560
+ throw new Error("spender and total amount must be positive");
561
+ if (dense(cs, "deliveries").length !== 2 * ns.length)
562
+ throw new Error("deliveries count mismatch");
563
+ const deliveries = cs.map(
564
+ (v, i) => BigInt(remainderCommitments[Math.floor(i / 2)]) === 0n ? normalizeDelivery(v, { empty: true }) : normalizeDelivery(v, { credit: true })
565
+ );
566
+ return {
567
+ ...ctx,
568
+ sources,
569
+ nullifiers: ns,
570
+ remainderCommitments,
571
+ recoveryAmounts,
572
+ expiries,
573
+ spender,
574
+ totalAmount,
575
+ deadline: checkDeadline(c, p.deadline),
576
+ deliveries,
577
+ profile
578
+ };
579
+ }
580
+ function creditDrawBaseInputs(c, p, cs) {
581
+ const r = validateCreditDrawRequest(c, p, cs), n = r.profile.maxSize, h = BigInt(deliveriesHash(cs));
582
+ return [
583
+ r.chainId,
584
+ BigInt(r.protocolAddress),
585
+ BigInt(r.tokenAddress),
586
+ BigInt(r.spender),
587
+ BigInt(r.nullifiers.length),
588
+ BigInt(r.sources.length),
589
+ ...pad(
590
+ r.sources.map((s) => s.treeId),
591
+ n
592
+ ),
593
+ ...pad(
594
+ r.sources.map((s) => BigInt(s.merkleRoot)),
595
+ n
596
+ ),
597
+ ...pad(r.nullifiers.map(BigInt), n),
598
+ ...pad(r.remainderCommitments.map(BigInt), n),
599
+ ...pad(r.expiries, n),
600
+ r.totalAmount,
601
+ r.deadline,
602
+ h >> 128n,
603
+ h & (1n << 128n) - 1n,
604
+ ...pad(r.recoveryAmounts.map(BigInt), n)
605
+ ].map(word);
606
+ }
607
+ function validateCancelCreditRequest(c, p) {
608
+ known(p, ["token", "source", "nullifier", "owner", "amount", "deadline"]);
609
+ if (getAddress4(p.token) !== getAddress4(c.tokenAddress))
610
+ throw new Error("request token mismatch");
611
+ const ctx = normalizeContext(c), source = normalizeSources([p.source], 1, 1)[0], nullifier = notes([p.nullifier], "nullifier")[0], owner = getAddress4(p.owner), amount = uint(p.amount, 126, "amount");
612
+ if (BigInt(owner) === 0n || amount === 0n) throw new Error("owner and amount must be positive");
613
+ return {
614
+ ...ctx,
615
+ source,
616
+ nullifier,
617
+ owner,
618
+ amount,
619
+ deadline: checkDeadline(c, p.deadline)
620
+ };
621
+ }
622
+ function cancelCreditBaseInputs(c, p) {
623
+ const r = validateCancelCreditRequest(c, p);
624
+ return [
625
+ r.chainId,
626
+ BigInt(r.protocolAddress),
627
+ BigInt(r.tokenAddress),
628
+ BigInt(r.owner),
629
+ r.source.treeId,
630
+ BigInt(r.source.merkleRoot),
631
+ BigInt(r.nullifier),
632
+ r.amount,
633
+ r.deadline
634
+ ].map(word);
635
+ }
636
+ function validateTopUpCreditRequest(c, p, cs, funding = {}) {
637
+ known(p, ["token", "creation", "creditSource", "creditNullifier", "previousExpiry"]);
638
+ const creation = validateCreateCreditRequest(c, p.creation, cs, funding), creditSource = normalizeSources([p.creditSource], 1, 1)[0], creditNullifier = notes([p.creditNullifier], "creditNullifier")[0], previousExpiry = uint(p.previousExpiry, 64, "previousExpiry");
639
+ if (previousExpiry === 0n || c.now !== void 0 && previousExpiry <= c.now)
640
+ throw new Error("previous Credit has expired");
641
+ if (creation.expiry < previousExpiry) throw new Error("expiry must not decrease");
642
+ if (creation.nullifiers.includes(creditNullifier))
643
+ throw new Error("duplicate credit and ordinary nullifier");
644
+ return { creation, creditSource, creditNullifier, previousExpiry };
645
+ }
646
+ function topUpCreditBaseInputs(c, p, cs, f = {}) {
647
+ const r = validateTopUpCreditRequest(c, p, cs, f);
648
+ return [
649
+ ...createCreditBaseInputs(c, p.creation, cs, f),
650
+ word(r.creditSource.treeId),
651
+ r.creditSource.merkleRoot,
652
+ r.creditNullifier,
653
+ word(r.previousExpiry)
654
+ ];
655
+ }
656
+ var cancelTuple = [
657
+ "(address token,(uint256 treeId,bytes32 merkleRoot) source,bytes32 nullifier,address owner,uint256 amount,uint256 deadline)"
658
+ ][0];
659
+ var topTuple = [
660
+ "((address token,(uint256 treeId,bytes32 merkleRoot)[] sources,bytes32[] nullifiers,bytes32 creditCommitment,bytes32 changeCommitment,address owner,uint256 expiry,uint256 deadline) creation,(uint256 treeId,bytes32 merkleRoot) creditSource,bytes32 creditNullifier,uint256 previousExpiry)"
661
+ ][0];
662
+ var hashContext2 = {
663
+ chainId: 0n,
664
+ protocolAddress: ZERO_ADDRESS,
665
+ tokenAddress: ZERO_ADDRESS
666
+ };
667
+ function cancelCreditRequestHash(p) {
668
+ validateCancelCreditRequest({ ...hashContext2, tokenAddress: p.token }, p);
669
+ return keccak2564(
670
+ AbiCoder3.defaultAbiCoder().encode(
671
+ [{ type: "bytes32" }, cancelTuple].map((parameter) => ParamType3.from(parameter)),
672
+ [keccak2564(new TextEncoder().encode("InvisiCancelCredit")), p]
673
+ )
674
+ );
675
+ }
676
+ function topUpCreditRequestHash(p, cs, f = {}) {
677
+ const r = validateTopUpCreditRequest(
678
+ { ...hashContext2, tokenAddress: p.creation.token },
679
+ p,
680
+ cs,
681
+ f
682
+ );
683
+ return keccak2564(
684
+ AbiCoder3.defaultAbiCoder().encode(
685
+ [
686
+ { type: "bytes32" },
687
+ topTuple,
688
+ { type: "bytes32" },
689
+ { type: "address" },
690
+ { type: "uint256" }
691
+ ].map((parameter) => ParamType3.from(parameter)),
692
+ [
693
+ keccak2564(new TextEncoder().encode("InvisiTopUpCredit")),
694
+ p,
695
+ deliveriesHash(cs),
696
+ r.creation.funding.payer,
697
+ r.creation.funding.amount
698
+ ]
699
+ )
700
+ );
701
+ }
702
+ function authorize(c, operation, capacity, words) {
703
+ return walletAuthorizationTypedData3({
704
+ context: { chainId: c.chainId, protocolAddress: BigInt(c.protocolAddress) },
705
+ operation,
706
+ capacity,
707
+ words: words.map(BigInt)
708
+ });
709
+ }
710
+ function appendDigest(c, operation, capacity, words) {
711
+ const digest = BigInt(
712
+ computeWalletAuthorizationDigest3({
713
+ context: { chainId: c.chainId, protocolAddress: BigInt(c.protocolAddress) },
714
+ operation,
715
+ capacity,
716
+ words: words.map(BigInt)
717
+ })
718
+ );
719
+ return [...words, word(digest >> 128n), word(digest & (1n << 128n) - 1n)];
720
+ }
721
+ function encodeCancelCreditTypedData(c, p) {
722
+ return authorize(c, "cancel-credit", 1, cancelCreditBaseInputs(c, p));
723
+ }
724
+ function encodeTopUpCreditTypedData(c, p, deliveries, funding = {}) {
725
+ return authorize(c, "top-up-credit", 10, topUpCreditBaseInputs(c, p, deliveries, funding));
726
+ }
727
+ function encodeCreditDrawTypedData(c, p, deliveries) {
728
+ return authorize(
729
+ c,
730
+ "credit-draw",
731
+ selectCreditDrawCircuit(p.nullifiers.length).maxSize,
732
+ creditDrawBaseInputs(c, p, deliveries)
733
+ );
734
+ }
735
+ function creditDrawPublicInputs(c, p, deliveries) {
736
+ return appendDigest(
737
+ c,
738
+ "credit-draw",
739
+ selectCreditDrawCircuit(p.nullifiers.length).maxSize,
740
+ creditDrawBaseInputs(c, p, deliveries)
741
+ );
742
+ }
743
+ function cancelCreditPublicInputs(c, p) {
744
+ return appendDigest(c, "cancel-credit", 1, cancelCreditBaseInputs(c, p));
745
+ }
746
+ function topUpCreditPublicInputs(c, p, deliveries, funding = {}) {
747
+ return appendDigest(c, "top-up-credit", 10, topUpCreditBaseInputs(c, p, deliveries, funding));
748
+ }
749
+ function encodeTopUpCreditFundingTypedData(c, p, cs, f) {
750
+ const r = validateTopUpCreditRequest(c, p, cs, f), funding = r.creation.funding;
751
+ if (funding.amount === 0n) throw new Error("funding authorization requires positive deposit");
752
+ return {
753
+ domain: getEIP712Domain(c),
754
+ primaryType: "FundTransact",
755
+ types: { FundTransact: fundingFields },
756
+ message: {
757
+ requestHash: topUpCreditRequestHash(p, cs, f),
758
+ payer: funding.payer,
759
+ amount: funding.amount,
760
+ sigNonce: funding.sigNonce,
761
+ deadline: funding.deadline
762
+ }
763
+ };
764
+ }
765
+ function buildCreditDrawCalldata(p) {
766
+ validateCreditDrawRequest(p.context, p.params, p.deliveries);
767
+ return {
768
+ data: new Interface3(invisiProtocolAbi).encodeFunctionData("creditDraw", [
769
+ encodeCreditProof(p.proof),
770
+ p.params,
771
+ p.deliveries
772
+ ]),
773
+ nullifiers: p.params.nullifiers,
774
+ totalAmount: p.params.totalAmount
775
+ };
776
+ }
777
+ function buildCancelCreditCalldata(p) {
778
+ validateCancelCreditRequest(p.context, p.params);
779
+ return {
780
+ data: new Interface3(invisiProtocolAbi).encodeFunctionData("cancelCredit", [
781
+ encodeCreditProof(p.proof),
782
+ p.params
783
+ ])
784
+ };
785
+ }
786
+ function buildTopUpCreditCalldata(p) {
787
+ const r = validateTopUpCreditRequest(p.context, p.params, p.deliveries, p.funding);
788
+ validateFundingSubmission(r.creation.funding, p.caller, p.context.now);
789
+ return {
790
+ data: new Interface3(invisiProtocolAbi).encodeFunctionData("topUpCredit", [
791
+ encodeCreditProof(p.proof),
792
+ p.params,
793
+ p.deliveries,
794
+ r.creation.funding
795
+ ]),
796
+ approveAmount: r.creation.funding.amount
797
+ };
798
+ }
799
+
800
+ // src/funds.ts
801
+ import { AbiCoder as AbiCoder4, getAddress as getAddress5, Interface as Interface4, keccak256 as keccak2565, ParamType as ParamType4, TypedDataEncoder } from "ethers";
802
+ import { computeNoteCommitment, walletAuthorizationTypedData as walletAuthorizationTypedData4 } from "@invisi-labs/core";
803
+ var TRANSACT_CAPACITIES = [14, 56, 112, 168];
804
+ function selectTransactCapacity(inputs, outputs) {
805
+ if (!Number.isInteger(inputs) || !Number.isInteger(outputs) || inputs < 0 || outputs < 0 || inputs + outputs < 1 || inputs === 0 && outputs < 2 || inputs + outputs > 168)
806
+ throw new Error("unsupported transact shape");
807
+ return TRANSACT_CAPACITIES.find((n) => inputs + outputs <= n);
808
+ }
809
+ function normalizeTransactRequest(c, p, cs, funding = {}) {
810
+ const ctx = normalizeContext(c);
811
+ if (getAddress5(p.token) !== ctx.tokenAddress)
812
+ throw new Error("request token mismatch");
813
+ known(p, [
814
+ "token",
815
+ "sources",
816
+ "nullifiers",
817
+ "outputCommitments",
818
+ "withdrawalAddress",
819
+ "withdrawalAmount",
820
+ "deadline"
821
+ ]);
822
+ const ns = notes(p.nullifiers, "nullifiers"), os = notes(p.outputCommitments, "outputCommitments"), capacity = selectTransactCapacity(ns.length, os.length);
823
+ const sources = normalizeSources(p.sources, ns.length, capacity), deliveries = dense(cs, "deliveries").map((v) => normalizeDelivery(v));
824
+ if (deliveries.length !== os.length) throw new Error("deliveries count mismatch");
825
+ const withdrawalAmount = uint(p.withdrawalAmount, 128, "withdrawalAmount"), withdrawalAddress = getAddress5(p.withdrawalAddress), f = normalizeFunding(funding);
826
+ if (withdrawalAmount === 0n !== (BigInt(withdrawalAddress) === 0n) || os.length === 0 && withdrawalAmount === 0n)
827
+ throw new Error("invalid withdrawal");
828
+ if (ns.length === 0 && (f.amount === 0n || withdrawalAmount !== 0n))
829
+ throw new Error("zero inputs require positive funding and zero withdrawal");
830
+ return {
831
+ ...ctx,
832
+ capacity,
833
+ sources,
834
+ nullifiers: ns,
835
+ outputCommitments: os,
836
+ inputCount: ns.length,
837
+ outputCount: os.length,
838
+ sourceCount: sources.length,
839
+ inputTreeIds: pad(
840
+ sources.map((s) => s.treeId),
841
+ capacity
842
+ ),
843
+ merkleRoots: pad(
844
+ sources.map((s) => BigInt(s.merkleRoot)),
845
+ capacity
846
+ ),
847
+ slotValues: pad([...ns, ...os].map(BigInt), capacity),
848
+ deliveries,
849
+ deliveriesHash: deliveriesHash(deliveries),
850
+ withdrawalAddress,
851
+ withdrawalAmount,
852
+ deadline: checkDeadline(c, p.deadline),
853
+ depositAmount: f.amount,
854
+ depositPayer: f.payer,
855
+ funding: f
856
+ };
857
+ }
858
+ function transactPublicInputs(c, p, cs, f = {}) {
859
+ const r = normalizeTransactRequest(c, p, cs, f), h = BigInt(r.deliveriesHash);
860
+ return [
861
+ r.chainId,
862
+ BigInt(r.protocolAddress),
863
+ BigInt(r.tokenAddress),
864
+ BigInt(r.inputCount),
865
+ BigInt(r.outputCount),
866
+ BigInt(r.sourceCount),
867
+ ...r.inputTreeIds,
868
+ ...r.merkleRoots,
869
+ ...r.slotValues,
870
+ h >> 128n,
871
+ h & (1n << 128n) - 1n,
872
+ BigInt(r.withdrawalAddress),
873
+ r.withdrawalAmount,
874
+ r.deadline,
875
+ r.depositAmount,
876
+ BigInt(r.depositPayer)
877
+ ].map(word);
878
+ }
879
+ function encodeTransactTypedData(c, p, deliveries, f = {}) {
880
+ const r = normalizeTransactRequest(c, p, deliveries, f);
881
+ return walletAuthorizationTypedData4({
882
+ context: { chainId: r.chainId, protocolAddress: BigInt(r.protocolAddress) },
883
+ operation: "transact",
884
+ capacity: r.capacity,
885
+ words: transactPublicInputs(c, p, deliveries, f).map(BigInt)
886
+ });
887
+ }
888
+ var singleTuple = [
889
+ "(address token,bytes32 merkleRoot,bytes32[] nullifiers,bytes32[] outputCommitments,uint256 inputTreeId,address withdrawalAddress,uint256 withdrawalAmount,uint256 deadline)"
890
+ ][0];
891
+ var crossTuple = [
892
+ "(address token,(uint256 treeId,bytes32 merkleRoot)[] sources,bytes32[] nullifiers,bytes32[] outputCommitments,address withdrawalAddress,uint256 withdrawalAmount,uint256 deadline)"
893
+ ][0];
894
+ function transactFundingRequestHash(proof, p, cs) {
895
+ const single = {
896
+ token: p.token,
897
+ merkleRoot: p.sources[0]?.merkleRoot ?? word(0n),
898
+ nullifiers: p.nullifiers,
899
+ outputCommitments: p.outputCommitments,
900
+ inputTreeId: p.sources[0]?.treeId ?? 0n,
901
+ withdrawalAddress: p.withdrawalAddress,
902
+ withdrawalAmount: p.withdrawalAmount,
903
+ deadline: p.deadline
904
+ };
905
+ return p.sources.length > 1 ? keccak2565(
906
+ AbiCoder4.defaultAbiCoder().encode(
907
+ [{ type: "bytes32" }, { type: "bytes32" }, crossTuple, { type: "bytes32" }].map(
908
+ (parameter) => ParamType4.from(parameter)
909
+ ),
910
+ [
911
+ keccak2565(new TextEncoder().encode("InvisiCrossTreeTransact")),
912
+ keccak2565(proof),
913
+ p,
914
+ deliveriesHash(cs)
915
+ ]
916
+ )
917
+ ) : keccak2565(
918
+ AbiCoder4.defaultAbiCoder().encode(
919
+ [{ type: "bytes32" }, singleTuple, { type: "bytes32" }].map(
920
+ (parameter) => ParamType4.from(parameter)
921
+ ),
922
+ [keccak2565(proof), single, deliveriesHash(cs)]
923
+ )
924
+ );
925
+ }
926
+ function encodeTransactFundingTypedData(c, proof, p, cs, funding) {
927
+ normalizeTransactRequest(c, p, cs, funding);
928
+ const f = normalizeFunding(funding);
929
+ if (f.amount === 0n) throw new Error("funding authorization requires positive deposit");
930
+ return {
931
+ domain: getEIP712Domain(c),
932
+ primaryType: "FundTransact",
933
+ types: { FundTransact: fundingFields },
934
+ message: {
935
+ requestHash: transactFundingRequestHash(proof, p, cs),
936
+ payer: f.payer,
937
+ amount: f.amount,
938
+ sigNonce: f.sigNonce,
939
+ deadline: f.deadline
940
+ }
941
+ };
942
+ }
943
+ function buildTransactCalldata(p) {
944
+ const r = normalizeTransactRequest(p.context, p.params, p.deliveries, p.funding);
945
+ validateFundingSubmission(r.funding, p.caller, p.context.now);
946
+ const request = {
947
+ params: {
948
+ token: r.tokenAddress,
949
+ sources: r.sources,
950
+ nullifiers: r.nullifiers,
951
+ outputCommitments: r.outputCommitments,
952
+ withdrawalAddress: r.withdrawalAddress,
953
+ withdrawalAmount: r.withdrawalAmount,
954
+ deadline: r.deadline
955
+ },
956
+ deliveries: p.deliveries,
957
+ funding: r.funding
958
+ };
959
+ const abi = invisiProtocolAbi.filter(
960
+ (item) => item.type === "function" && item.name === "transact" && item.inputs.length === 2 && item.inputs[1]?.type === "tuple"
961
+ );
962
+ const data = new Interface4(abi).encodeFunctionData("transact", [p.proof, request]);
963
+ return { data, capacity: r.capacity, approveAmount: r.depositAmount };
964
+ }
965
+ function buildTransactAggregateCalldata(p) {
966
+ if (![4, 8, 12].includes(dense(p.requests, "requests").length))
967
+ throw new Error("aggregate requires 4, 8 or 12 requests");
968
+ for (const request of p.requests) {
969
+ const r = normalizeTransactRequest(
970
+ { ...p.context, tokenAddress: request.params.token },
971
+ request.params,
972
+ request.deliveries,
973
+ request.funding
974
+ );
975
+ if (r.capacity !== 14) throw new Error("aggregate supports only capacity 14");
976
+ validateFundingSubmission(r.funding, p.caller, p.context.now);
977
+ }
978
+ return {
979
+ data: new Interface4(
980
+ invisiProtocolAbi.filter(
981
+ (item) => item.type === "function" && item.name === "transact" && item.inputs[1]?.type === "tuple[]"
982
+ )
983
+ ).encodeFunctionData("transact", [p.proof, p.requests]),
984
+ capacity: 14
985
+ };
986
+ }
987
+ async function validateShieldRequest(p) {
988
+ normalizeContext(p.context);
989
+ if (getAddress5(p.params.token) !== getAddress5(p.context.tokenAddress))
990
+ throw new Error("request token mismatch");
991
+ known(p.params, ["token", "outputCommitments", "deadline"]);
992
+ checkDeadline(p.context, p.params.deadline);
993
+ const outputs = dense(p.outputs, "outputs"), commitments = notes(p.params.outputCommitments, "outputCommitments"), cs = dense(p.deliveries, "deliveries"), f = normalizeFunding(p.funding);
994
+ if (outputs.length < 1 || outputs.length > 10 || commitments.length !== outputs.length || cs.length !== outputs.length)
995
+ throw new Error("shield requires 1..10 outputs and matching deliveries");
996
+ let total = 0n;
997
+ for (const [i, o] of outputs.entries()) {
998
+ known(o, ["identity", "amount"], "output");
999
+ uint(o.amount, 128, "amount");
1000
+ if (o.amount === 0n) throw new Error("amount must be positive");
1001
+ field(o.identity);
1002
+ normalizeDelivery(cs[i]);
1003
+ if (await computeNoteCommitment(
1004
+ p.context.chainId,
1005
+ o.identity,
1006
+ BigInt(p.context.tokenAddress),
1007
+ o.amount
1008
+ ) !== commitments[i])
1009
+ throw new Error("output commitment mismatch");
1010
+ total += o.amount;
1011
+ }
1012
+ if (total !== f.amount) throw new Error("funding must equal output total");
1013
+ return f;
1014
+ }
1015
+ function shieldFundingRequestHash(params, outputs, cs) {
1016
+ const outputHash = keccak2565(
1017
+ AbiCoder4.defaultAbiCoder().encode(
1018
+ ["(bytes32 identity,uint256 amount)[]"].map((parameter) => ParamType4.from(parameter)),
1019
+ [outputs]
1020
+ )
1021
+ );
1022
+ return keccak2565(
1023
+ AbiCoder4.defaultAbiCoder().encode(
1024
+ [
1025
+ "bytes32",
1026
+ "(address token,bytes32[] outputCommitments,uint256 deadline)",
1027
+ "bytes32",
1028
+ "bytes32"
1029
+ ].map((parameter) => ParamType4.from(parameter)),
1030
+ [
1031
+ keccak2565(new TextEncoder().encode("InvisiShield")),
1032
+ params,
1033
+ outputHash,
1034
+ deliveriesHash(cs)
1035
+ ]
1036
+ )
1037
+ );
1038
+ }
1039
+ async function encodeShieldFundingTypedData(p) {
1040
+ const f = await validateShieldRequest(p);
1041
+ return {
1042
+ domain: getEIP712Domain(p.context),
1043
+ primaryType: "FundShield",
1044
+ types: { FundShield: fundingFields },
1045
+ message: {
1046
+ requestHash: shieldFundingRequestHash(p.params, p.outputs, p.deliveries),
1047
+ payer: f.payer,
1048
+ amount: f.amount,
1049
+ sigNonce: f.sigNonce,
1050
+ deadline: f.deadline
1051
+ }
1052
+ };
1053
+ }
1054
+ async function buildShieldCalldata(p) {
1055
+ const f = await validateShieldRequest(p);
1056
+ validateFundingSubmission(f, p.caller, p.context.now);
1057
+ return {
1058
+ data: new Interface4(invisiProtocolAbi).encodeFunctionData("shield", [
1059
+ p.params,
1060
+ p.outputs,
1061
+ p.deliveries,
1062
+ f
1063
+ ]),
1064
+ approveAmount: f.amount
1065
+ };
1066
+ }
1067
+ function transactUserPublicInputs(c, p, cs, f = {}) {
1068
+ const words = transactPublicInputs(c, p, cs, f), digest = BigInt(
1069
+ ((typed) => TypedDataEncoder.hash(
1070
+ typed.domain,
1071
+ Object.fromEntries(
1072
+ Object.entries(typed.types).map(([name, fields]) => [
1073
+ name,
1074
+ [...fields]
1075
+ ])
1076
+ ),
1077
+ typed.message
1078
+ ))(encodeTransactTypedData(c, p, cs, f))
1079
+ );
1080
+ return [...words, word(digest >> 128n), word(digest & (1n << 128n) - 1n)];
1081
+ }
1082
+ function aggregateMemberRequestHash(c, r) {
1083
+ const capacity = selectTransactCapacity(
1084
+ r.params.nullifiers.length,
1085
+ r.params.outputCommitments.length
1086
+ );
1087
+ if (capacity !== 14) throw new Error("aggregate supports only capacity 14");
1088
+ return keccak2565(
1089
+ AbiCoder4.defaultAbiCoder().encode(
1090
+ ["bytes32", "uint256", "bytes32[]"].map((parameter) => ParamType4.from(parameter)),
1091
+ [
1092
+ keccak2565(new TextEncoder().encode("InvisiAtomicBatchMemberV1")),
1093
+ BigInt(capacity),
1094
+ transactPublicInputs(c, r.params, r.deliveries, r.funding)
1095
+ ]
1096
+ )
1097
+ );
1098
+ }
1099
+ function aggregatePublicInputs(c, requests) {
1100
+ if (![4, 8, 12].includes(dense(requests, "requests").length))
1101
+ throw new Error("aggregate requires 4, 8 or 12 requests");
1102
+ return requests.flatMap((r) => {
1103
+ const context = { ...c, tokenAddress: r.params.token };
1104
+ aggregateMemberRequestHash(context, r);
1105
+ return [word(14n), ...transactPublicInputs(context, r.params, r.deliveries, r.funding)];
1106
+ });
1107
+ }
1108
+ function encodeAggregateFundingTypedData(c, r) {
1109
+ const f = normalizeFunding(r.funding);
1110
+ if (f.amount === 0n) throw new Error("funding authorization requires positive deposit");
1111
+ return {
1112
+ domain: getEIP712Domain(c),
1113
+ primaryType: "FundTransact",
1114
+ types: { FundTransact: fundingFields },
1115
+ message: {
1116
+ requestHash: aggregateMemberRequestHash(c, r),
1117
+ payer: f.payer,
1118
+ amount: f.amount,
1119
+ sigNonce: f.sigNonce,
1120
+ deadline: f.deadline
1121
+ }
1122
+ };
1123
+ }
1124
+
1125
+ // src/witness-layouts.json
1126
+ var witness_layouts_default = {
1127
+ transact_user_slots14: {
1128
+ artifactSha256: "486a749ae3944ae83a7ff2d298e7469b18737d88553a7d99c4782f22f7332996",
1129
+ keys: {
1130
+ evm: "7b3e65d5201246e733a1816489d80acb219a98e8606e1b81e6d48ff0c1fd537a",
1131
+ "noir-recursive": "148957e28e6339a8ce1121851fb7a232e31f4c5b741e415733b8d627f4b62649"
1132
+ },
1133
+ publicInputCount: 57,
1134
+ public: [
1135
+ {
1136
+ name: "chain_id",
1137
+ count: 1,
1138
+ array: false
1139
+ },
1140
+ {
1141
+ name: "protocol_address",
1142
+ count: 1,
1143
+ array: false
1144
+ },
1145
+ {
1146
+ name: "token_address",
1147
+ count: 1,
1148
+ array: false
1149
+ },
1150
+ {
1151
+ name: "input_count",
1152
+ count: 1,
1153
+ array: false
1154
+ },
1155
+ {
1156
+ name: "output_count",
1157
+ count: 1,
1158
+ array: false
1159
+ },
1160
+ {
1161
+ name: "source_count",
1162
+ count: 1,
1163
+ array: false
1164
+ },
1165
+ {
1166
+ name: "input_tree_ids",
1167
+ count: 14,
1168
+ array: true
1169
+ },
1170
+ {
1171
+ name: "merkle_roots",
1172
+ count: 14,
1173
+ array: true
1174
+ },
1175
+ {
1176
+ name: "slot_values",
1177
+ count: 14,
1178
+ array: true
1179
+ },
1180
+ {
1181
+ name: "delivery_hash_high",
1182
+ count: 1,
1183
+ array: false
1184
+ },
1185
+ {
1186
+ name: "delivery_hash_low",
1187
+ count: 1,
1188
+ array: false
1189
+ },
1190
+ {
1191
+ name: "withdrawal_address",
1192
+ count: 1,
1193
+ array: false
1194
+ },
1195
+ {
1196
+ name: "withdrawal_amount",
1197
+ count: 1,
1198
+ array: false
1199
+ },
1200
+ {
1201
+ name: "deadline",
1202
+ count: 1,
1203
+ array: false
1204
+ },
1205
+ {
1206
+ name: "deposit_amount",
1207
+ count: 1,
1208
+ array: false
1209
+ },
1210
+ {
1211
+ name: "deposit_payer",
1212
+ count: 1,
1213
+ array: false
1214
+ },
1215
+ {
1216
+ name: "auth_digest_high",
1217
+ count: 1,
1218
+ array: false
1219
+ },
1220
+ {
1221
+ name: "auth_digest_low",
1222
+ count: 1,
1223
+ array: false
1224
+ }
1225
+ ],
1226
+ private: [
1227
+ "wallet_identity",
1228
+ "public_key_x",
1229
+ "public_key_y",
1230
+ "signature",
1231
+ "output_wallet_identities",
1232
+ "amounts",
1233
+ "nonces",
1234
+ "leaf_indices",
1235
+ "merkle_paths",
1236
+ "input_source_indices"
1237
+ ]
1238
+ },
1239
+ transact_user_slots56: {
1240
+ artifactSha256: "169db2ff23c15adb14756edf9bb99bbd343df807b3e1c7f1f510070897e653cf",
1241
+ keys: {
1242
+ evm: "cbf54de94bff266bf846f9722c0f3ffa1fb7a0f9f478466f193de0e9123ce7f5"
1243
+ },
1244
+ publicInputCount: 183,
1245
+ public: [
1246
+ {
1247
+ name: "chain_id",
1248
+ count: 1,
1249
+ array: false
1250
+ },
1251
+ {
1252
+ name: "protocol_address",
1253
+ count: 1,
1254
+ array: false
1255
+ },
1256
+ {
1257
+ name: "token_address",
1258
+ count: 1,
1259
+ array: false
1260
+ },
1261
+ {
1262
+ name: "input_count",
1263
+ count: 1,
1264
+ array: false
1265
+ },
1266
+ {
1267
+ name: "output_count",
1268
+ count: 1,
1269
+ array: false
1270
+ },
1271
+ {
1272
+ name: "source_count",
1273
+ count: 1,
1274
+ array: false
1275
+ },
1276
+ {
1277
+ name: "input_tree_ids",
1278
+ count: 56,
1279
+ array: true
1280
+ },
1281
+ {
1282
+ name: "merkle_roots",
1283
+ count: 56,
1284
+ array: true
1285
+ },
1286
+ {
1287
+ name: "slot_values",
1288
+ count: 56,
1289
+ array: true
1290
+ },
1291
+ {
1292
+ name: "delivery_hash_high",
1293
+ count: 1,
1294
+ array: false
1295
+ },
1296
+ {
1297
+ name: "delivery_hash_low",
1298
+ count: 1,
1299
+ array: false
1300
+ },
1301
+ {
1302
+ name: "withdrawal_address",
1303
+ count: 1,
1304
+ array: false
1305
+ },
1306
+ {
1307
+ name: "withdrawal_amount",
1308
+ count: 1,
1309
+ array: false
1310
+ },
1311
+ {
1312
+ name: "deadline",
1313
+ count: 1,
1314
+ array: false
1315
+ },
1316
+ {
1317
+ name: "deposit_amount",
1318
+ count: 1,
1319
+ array: false
1320
+ },
1321
+ {
1322
+ name: "deposit_payer",
1323
+ count: 1,
1324
+ array: false
1325
+ },
1326
+ {
1327
+ name: "auth_digest_high",
1328
+ count: 1,
1329
+ array: false
1330
+ },
1331
+ {
1332
+ name: "auth_digest_low",
1333
+ count: 1,
1334
+ array: false
1335
+ }
1336
+ ],
1337
+ private: [
1338
+ "wallet_identity",
1339
+ "public_key_x",
1340
+ "public_key_y",
1341
+ "signature",
1342
+ "output_wallet_identities",
1343
+ "amounts",
1344
+ "nonces",
1345
+ "leaf_indices",
1346
+ "merkle_paths",
1347
+ "input_source_indices"
1348
+ ]
1349
+ },
1350
+ transact_user_slots112: {
1351
+ artifactSha256: "221bbbd6ff0c7d7dec74677e52484f082b3e176bb0fa47f3236064e396d73739",
1352
+ keys: {
1353
+ evm: "67b2d361b023f193ecdb5a9aefbe2840349ee5ce848ab4101416734f3a7e91e9"
1354
+ },
1355
+ publicInputCount: 351,
1356
+ public: [
1357
+ {
1358
+ name: "chain_id",
1359
+ count: 1,
1360
+ array: false
1361
+ },
1362
+ {
1363
+ name: "protocol_address",
1364
+ count: 1,
1365
+ array: false
1366
+ },
1367
+ {
1368
+ name: "token_address",
1369
+ count: 1,
1370
+ array: false
1371
+ },
1372
+ {
1373
+ name: "input_count",
1374
+ count: 1,
1375
+ array: false
1376
+ },
1377
+ {
1378
+ name: "output_count",
1379
+ count: 1,
1380
+ array: false
1381
+ },
1382
+ {
1383
+ name: "source_count",
1384
+ count: 1,
1385
+ array: false
1386
+ },
1387
+ {
1388
+ name: "input_tree_ids",
1389
+ count: 112,
1390
+ array: true
1391
+ },
1392
+ {
1393
+ name: "merkle_roots",
1394
+ count: 112,
1395
+ array: true
1396
+ },
1397
+ {
1398
+ name: "slot_values",
1399
+ count: 112,
1400
+ array: true
1401
+ },
1402
+ {
1403
+ name: "delivery_hash_high",
1404
+ count: 1,
1405
+ array: false
1406
+ },
1407
+ {
1408
+ name: "delivery_hash_low",
1409
+ count: 1,
1410
+ array: false
1411
+ },
1412
+ {
1413
+ name: "withdrawal_address",
1414
+ count: 1,
1415
+ array: false
1416
+ },
1417
+ {
1418
+ name: "withdrawal_amount",
1419
+ count: 1,
1420
+ array: false
1421
+ },
1422
+ {
1423
+ name: "deadline",
1424
+ count: 1,
1425
+ array: false
1426
+ },
1427
+ {
1428
+ name: "deposit_amount",
1429
+ count: 1,
1430
+ array: false
1431
+ },
1432
+ {
1433
+ name: "deposit_payer",
1434
+ count: 1,
1435
+ array: false
1436
+ },
1437
+ {
1438
+ name: "auth_digest_high",
1439
+ count: 1,
1440
+ array: false
1441
+ },
1442
+ {
1443
+ name: "auth_digest_low",
1444
+ count: 1,
1445
+ array: false
1446
+ }
1447
+ ],
1448
+ private: [
1449
+ "wallet_identity",
1450
+ "public_key_x",
1451
+ "public_key_y",
1452
+ "signature",
1453
+ "output_wallet_identities",
1454
+ "amounts",
1455
+ "nonces",
1456
+ "leaf_indices",
1457
+ "merkle_paths",
1458
+ "input_source_indices"
1459
+ ]
1460
+ },
1461
+ transact_user_slots168: {
1462
+ artifactSha256: "d479253eaaacc973806a84e142e2362d873bba0f150ce050d32b8d9b2947adc8",
1463
+ keys: {
1464
+ evm: "c50e72b0718c6393f82f5a67e248ba093d0db56ece42bbf092da93e9369c2624"
1465
+ },
1466
+ publicInputCount: 519,
1467
+ public: [
1468
+ {
1469
+ name: "chain_id",
1470
+ count: 1,
1471
+ array: false
1472
+ },
1473
+ {
1474
+ name: "protocol_address",
1475
+ count: 1,
1476
+ array: false
1477
+ },
1478
+ {
1479
+ name: "token_address",
1480
+ count: 1,
1481
+ array: false
1482
+ },
1483
+ {
1484
+ name: "input_count",
1485
+ count: 1,
1486
+ array: false
1487
+ },
1488
+ {
1489
+ name: "output_count",
1490
+ count: 1,
1491
+ array: false
1492
+ },
1493
+ {
1494
+ name: "source_count",
1495
+ count: 1,
1496
+ array: false
1497
+ },
1498
+ {
1499
+ name: "input_tree_ids",
1500
+ count: 168,
1501
+ array: true
1502
+ },
1503
+ {
1504
+ name: "merkle_roots",
1505
+ count: 168,
1506
+ array: true
1507
+ },
1508
+ {
1509
+ name: "slot_values",
1510
+ count: 168,
1511
+ array: true
1512
+ },
1513
+ {
1514
+ name: "delivery_hash_high",
1515
+ count: 1,
1516
+ array: false
1517
+ },
1518
+ {
1519
+ name: "delivery_hash_low",
1520
+ count: 1,
1521
+ array: false
1522
+ },
1523
+ {
1524
+ name: "withdrawal_address",
1525
+ count: 1,
1526
+ array: false
1527
+ },
1528
+ {
1529
+ name: "withdrawal_amount",
1530
+ count: 1,
1531
+ array: false
1532
+ },
1533
+ {
1534
+ name: "deadline",
1535
+ count: 1,
1536
+ array: false
1537
+ },
1538
+ {
1539
+ name: "deposit_amount",
1540
+ count: 1,
1541
+ array: false
1542
+ },
1543
+ {
1544
+ name: "deposit_payer",
1545
+ count: 1,
1546
+ array: false
1547
+ },
1548
+ {
1549
+ name: "auth_digest_high",
1550
+ count: 1,
1551
+ array: false
1552
+ },
1553
+ {
1554
+ name: "auth_digest_low",
1555
+ count: 1,
1556
+ array: false
1557
+ }
1558
+ ],
1559
+ private: [
1560
+ "wallet_identity",
1561
+ "public_key_x",
1562
+ "public_key_y",
1563
+ "signature",
1564
+ "output_wallet_identities",
1565
+ "amounts",
1566
+ "nonces",
1567
+ "leaf_indices",
1568
+ "merkle_paths",
1569
+ "input_source_indices"
1570
+ ]
1571
+ },
1572
+ transact_aggregate_14_4: {
1573
+ artifactSha256: "4fe7c63fb80cba35af4c4525fbabcfb75033286e681afbdcb3fb043c03456246",
1574
+ keys: {
1575
+ evm: "664d4ff0de6b8c876ce990ea368d7a59cee411463c24dd5621d64c8949554674"
1576
+ },
1577
+ publicInputCount: 229,
1578
+ public: [
1579
+ {
1580
+ name: "statements",
1581
+ count: 4,
1582
+ array: true
1583
+ },
1584
+ {
1585
+ name: "inner_vk_commitment",
1586
+ count: 1,
1587
+ array: false
1588
+ }
1589
+ ],
1590
+ private: [
1591
+ "verification_key",
1592
+ "key_hash",
1593
+ "proofs"
1594
+ ]
1595
+ },
1596
+ transact_aggregate_14_8: {
1597
+ artifactSha256: "0a266ad4bb4c6dce42b1e851fcbb34b1becae1edd6bf6af82d7b9ed7184576df",
1598
+ keys: {
1599
+ evm: "042139122d0eee8beeaa9c18397276fa5a2872218495fa16ca438fbdd80fa3e1"
1600
+ },
1601
+ publicInputCount: 457,
1602
+ public: [
1603
+ {
1604
+ name: "statements",
1605
+ count: 8,
1606
+ array: true
1607
+ },
1608
+ {
1609
+ name: "inner_vk_commitment",
1610
+ count: 1,
1611
+ array: false
1612
+ }
1613
+ ],
1614
+ private: [
1615
+ "verification_key",
1616
+ "key_hash",
1617
+ "proofs"
1618
+ ]
1619
+ },
1620
+ transact_aggregate_14_12: {
1621
+ artifactSha256: "738849e83eb4a78eb69cb6e20a86f6f27ba3784d04a83abd338f84de5c20d7d2",
1622
+ keys: {
1623
+ evm: "539928b264aea4d07a41e772d5d5a7b7666a6883decb985c27ca7422e7f8ea1f"
1624
+ },
1625
+ publicInputCount: 685,
1626
+ public: [
1627
+ {
1628
+ name: "statements",
1629
+ count: 12,
1630
+ array: true
1631
+ },
1632
+ {
1633
+ name: "inner_vk_commitment",
1634
+ count: 1,
1635
+ array: false
1636
+ }
1637
+ ],
1638
+ private: [
1639
+ "verification_key",
1640
+ "key_hash",
1641
+ "proofs"
1642
+ ]
1643
+ },
1644
+ create_credit: {
1645
+ artifactSha256: "078c6d2da1ed2d6bd27fab28af9970261fe626a0b22ae56ad170e5d15b1b05ba",
1646
+ keys: {
1647
+ evm: "8285456447e92833a4fa9c330b9c667a3a1b9e48649578082041b9738f037c8f"
1648
+ },
1649
+ publicInputCount: 46,
1650
+ public: [
1651
+ {
1652
+ name: "chain_id",
1653
+ count: 1,
1654
+ array: false
1655
+ },
1656
+ {
1657
+ name: "protocol_address",
1658
+ count: 1,
1659
+ array: false
1660
+ },
1661
+ {
1662
+ name: "token_address",
1663
+ count: 1,
1664
+ array: false
1665
+ },
1666
+ {
1667
+ name: "owner_address",
1668
+ count: 1,
1669
+ array: false
1670
+ },
1671
+ {
1672
+ name: "actual_count",
1673
+ count: 1,
1674
+ array: false
1675
+ },
1676
+ {
1677
+ name: "source_count",
1678
+ count: 1,
1679
+ array: false
1680
+ },
1681
+ {
1682
+ name: "input_tree_ids",
1683
+ count: 10,
1684
+ array: true
1685
+ },
1686
+ {
1687
+ name: "merkle_roots",
1688
+ count: 10,
1689
+ array: true
1690
+ },
1691
+ {
1692
+ name: "nullifiers",
1693
+ count: 10,
1694
+ array: true
1695
+ },
1696
+ {
1697
+ name: "credit_commitment",
1698
+ count: 1,
1699
+ array: false
1700
+ },
1701
+ {
1702
+ name: "change_commitment",
1703
+ count: 1,
1704
+ array: false
1705
+ },
1706
+ {
1707
+ name: "delivery_hash_high",
1708
+ count: 1,
1709
+ array: false
1710
+ },
1711
+ {
1712
+ name: "delivery_hash_low",
1713
+ count: 1,
1714
+ array: false
1715
+ },
1716
+ {
1717
+ name: "expiry",
1718
+ count: 1,
1719
+ array: false
1720
+ },
1721
+ {
1722
+ name: "deadline",
1723
+ count: 1,
1724
+ array: false
1725
+ },
1726
+ {
1727
+ name: "deposit_amount",
1728
+ count: 1,
1729
+ array: false
1730
+ },
1731
+ {
1732
+ name: "deposit_payer",
1733
+ count: 1,
1734
+ array: false
1735
+ },
1736
+ {
1737
+ name: "auth_digest_high",
1738
+ count: 1,
1739
+ array: false
1740
+ },
1741
+ {
1742
+ name: "auth_digest_low",
1743
+ count: 1,
1744
+ array: false
1745
+ }
1746
+ ],
1747
+ private: [
1748
+ "input_amounts",
1749
+ "input_nonces",
1750
+ "leaf_indices",
1751
+ "merkle_paths",
1752
+ "input_source_indices",
1753
+ "public_key_x",
1754
+ "public_key_y",
1755
+ "signature",
1756
+ "spender_payout",
1757
+ "spender_wallet_identity",
1758
+ "owner_wallet_identity",
1759
+ "credit_amount",
1760
+ "credit_nonce",
1761
+ "credit_shared_key",
1762
+ "change_amount",
1763
+ "change_nonce"
1764
+ ]
1765
+ },
1766
+ credit_draw_slots1: {
1767
+ artifactSha256: "2b9da9d3d1dbd411d9be1bbe2b34305ac5dce7c7d18e3857d8e2be7dd9bf7c21",
1768
+ keys: {
1769
+ evm: "613699a440f50a0937e4c57e5152b5fdea42c31b10157d6b93226fef313df553"
1770
+ },
1771
+ publicInputCount: 18,
1772
+ public: [
1773
+ {
1774
+ name: "chain_id",
1775
+ count: 1,
1776
+ array: false
1777
+ },
1778
+ {
1779
+ name: "protocol_address",
1780
+ count: 1,
1781
+ array: false
1782
+ },
1783
+ {
1784
+ name: "token_address",
1785
+ count: 1,
1786
+ array: false
1787
+ },
1788
+ {
1789
+ name: "spender_address",
1790
+ count: 1,
1791
+ array: false
1792
+ },
1793
+ {
1794
+ name: "actual_count",
1795
+ count: 1,
1796
+ array: false
1797
+ },
1798
+ {
1799
+ name: "source_count",
1800
+ count: 1,
1801
+ array: false
1802
+ },
1803
+ {
1804
+ name: "tree_ids",
1805
+ count: 1,
1806
+ array: true
1807
+ },
1808
+ {
1809
+ name: "roots",
1810
+ count: 1,
1811
+ array: true
1812
+ },
1813
+ {
1814
+ name: "nullifiers",
1815
+ count: 1,
1816
+ array: true
1817
+ },
1818
+ {
1819
+ name: "remainder_commitments",
1820
+ count: 1,
1821
+ array: true
1822
+ },
1823
+ {
1824
+ name: "expiries",
1825
+ count: 1,
1826
+ array: true
1827
+ },
1828
+ {
1829
+ name: "total_amount",
1830
+ count: 1,
1831
+ array: false
1832
+ },
1833
+ {
1834
+ name: "deadline",
1835
+ count: 1,
1836
+ array: false
1837
+ },
1838
+ {
1839
+ name: "delivery_hash_high",
1840
+ count: 1,
1841
+ array: false
1842
+ },
1843
+ {
1844
+ name: "delivery_hash_low",
1845
+ count: 1,
1846
+ array: false
1847
+ },
1848
+ {
1849
+ name: "recovery_amounts",
1850
+ count: 1,
1851
+ array: true
1852
+ },
1853
+ {
1854
+ name: "auth_digest_high",
1855
+ count: 1,
1856
+ array: false
1857
+ },
1858
+ {
1859
+ name: "auth_digest_low",
1860
+ count: 1,
1861
+ array: false
1862
+ }
1863
+ ],
1864
+ private: [
1865
+ "public_key_x",
1866
+ "public_key_y",
1867
+ "signature",
1868
+ "spender_wallet_identity",
1869
+ "owner_payouts",
1870
+ "owner_wallet_identities",
1871
+ "input_amounts",
1872
+ "input_nonces",
1873
+ "credit_shared_keys",
1874
+ "leaf_indices",
1875
+ "merkle_paths",
1876
+ "input_source_indices",
1877
+ "draw_amounts"
1878
+ ]
1879
+ },
1880
+ credit_draw_slots12: {
1881
+ artifactSha256: "92b741e161a99c05b8810bc24cee6bafc1cebc85347ea47fe511ee6c8f7065be",
1882
+ keys: {
1883
+ evm: "a5ae214784fe6e523977ef4e283a6d217fc3f4ec0c5a40effb275693a74ee5ce"
1884
+ },
1885
+ publicInputCount: 84,
1886
+ public: [
1887
+ {
1888
+ name: "chain_id",
1889
+ count: 1,
1890
+ array: false
1891
+ },
1892
+ {
1893
+ name: "protocol_address",
1894
+ count: 1,
1895
+ array: false
1896
+ },
1897
+ {
1898
+ name: "token_address",
1899
+ count: 1,
1900
+ array: false
1901
+ },
1902
+ {
1903
+ name: "spender_address",
1904
+ count: 1,
1905
+ array: false
1906
+ },
1907
+ {
1908
+ name: "actual_count",
1909
+ count: 1,
1910
+ array: false
1911
+ },
1912
+ {
1913
+ name: "source_count",
1914
+ count: 1,
1915
+ array: false
1916
+ },
1917
+ {
1918
+ name: "tree_ids",
1919
+ count: 12,
1920
+ array: true
1921
+ },
1922
+ {
1923
+ name: "roots",
1924
+ count: 12,
1925
+ array: true
1926
+ },
1927
+ {
1928
+ name: "nullifiers",
1929
+ count: 12,
1930
+ array: true
1931
+ },
1932
+ {
1933
+ name: "remainder_commitments",
1934
+ count: 12,
1935
+ array: true
1936
+ },
1937
+ {
1938
+ name: "expiries",
1939
+ count: 12,
1940
+ array: true
1941
+ },
1942
+ {
1943
+ name: "total_amount",
1944
+ count: 1,
1945
+ array: false
1946
+ },
1947
+ {
1948
+ name: "deadline",
1949
+ count: 1,
1950
+ array: false
1951
+ },
1952
+ {
1953
+ name: "delivery_hash_high",
1954
+ count: 1,
1955
+ array: false
1956
+ },
1957
+ {
1958
+ name: "delivery_hash_low",
1959
+ count: 1,
1960
+ array: false
1961
+ },
1962
+ {
1963
+ name: "recovery_amounts",
1964
+ count: 12,
1965
+ array: true
1966
+ },
1967
+ {
1968
+ name: "auth_digest_high",
1969
+ count: 1,
1970
+ array: false
1971
+ },
1972
+ {
1973
+ name: "auth_digest_low",
1974
+ count: 1,
1975
+ array: false
1976
+ }
1977
+ ],
1978
+ private: [
1979
+ "public_key_x",
1980
+ "public_key_y",
1981
+ "signature",
1982
+ "spender_wallet_identity",
1983
+ "owner_payouts",
1984
+ "owner_wallet_identities",
1985
+ "input_amounts",
1986
+ "input_nonces",
1987
+ "credit_shared_keys",
1988
+ "leaf_indices",
1989
+ "merkle_paths",
1990
+ "input_source_indices",
1991
+ "draw_amounts"
1992
+ ]
1993
+ },
1994
+ credit_draw_slots50: {
1995
+ artifactSha256: "9c6a23d5dbca3a1aeed461c908f228e89642550775cbc519d633bb1c984a3d04",
1996
+ keys: {
1997
+ evm: "f0b192e2cb312148c7a16fae3acaed9efb01b0c6a1b381ce03468f00b4ef0f2a"
1998
+ },
1999
+ publicInputCount: 312,
2000
+ public: [
2001
+ {
2002
+ name: "chain_id",
2003
+ count: 1,
2004
+ array: false
2005
+ },
2006
+ {
2007
+ name: "protocol_address",
2008
+ count: 1,
2009
+ array: false
2010
+ },
2011
+ {
2012
+ name: "token_address",
2013
+ count: 1,
2014
+ array: false
2015
+ },
2016
+ {
2017
+ name: "spender_address",
2018
+ count: 1,
2019
+ array: false
2020
+ },
2021
+ {
2022
+ name: "actual_count",
2023
+ count: 1,
2024
+ array: false
2025
+ },
2026
+ {
2027
+ name: "source_count",
2028
+ count: 1,
2029
+ array: false
2030
+ },
2031
+ {
2032
+ name: "tree_ids",
2033
+ count: 50,
2034
+ array: true
2035
+ },
2036
+ {
2037
+ name: "roots",
2038
+ count: 50,
2039
+ array: true
2040
+ },
2041
+ {
2042
+ name: "nullifiers",
2043
+ count: 50,
2044
+ array: true
2045
+ },
2046
+ {
2047
+ name: "remainder_commitments",
2048
+ count: 50,
2049
+ array: true
2050
+ },
2051
+ {
2052
+ name: "expiries",
2053
+ count: 50,
2054
+ array: true
2055
+ },
2056
+ {
2057
+ name: "total_amount",
2058
+ count: 1,
2059
+ array: false
2060
+ },
2061
+ {
2062
+ name: "deadline",
2063
+ count: 1,
2064
+ array: false
2065
+ },
2066
+ {
2067
+ name: "delivery_hash_high",
2068
+ count: 1,
2069
+ array: false
2070
+ },
2071
+ {
2072
+ name: "delivery_hash_low",
2073
+ count: 1,
2074
+ array: false
2075
+ },
2076
+ {
2077
+ name: "recovery_amounts",
2078
+ count: 50,
2079
+ array: true
2080
+ },
2081
+ {
2082
+ name: "auth_digest_high",
2083
+ count: 1,
2084
+ array: false
2085
+ },
2086
+ {
2087
+ name: "auth_digest_low",
2088
+ count: 1,
2089
+ array: false
2090
+ }
2091
+ ],
2092
+ private: [
2093
+ "public_key_x",
2094
+ "public_key_y",
2095
+ "signature",
2096
+ "spender_wallet_identity",
2097
+ "owner_payouts",
2098
+ "owner_wallet_identities",
2099
+ "input_amounts",
2100
+ "input_nonces",
2101
+ "credit_shared_keys",
2102
+ "leaf_indices",
2103
+ "merkle_paths",
2104
+ "input_source_indices",
2105
+ "draw_amounts"
2106
+ ]
2107
+ },
2108
+ credit_draw_slots120: {
2109
+ artifactSha256: "69686a4f0a8a98d8cef06485b0de1804ca2e8f47ce0244287a03ceef4d67625a",
2110
+ keys: {
2111
+ evm: "6f32ca89775f332a9193af9b1e25641ef14fda9fbdd2685c33ee775d3c170b92"
2112
+ },
2113
+ publicInputCount: 732,
2114
+ public: [
2115
+ {
2116
+ name: "chain_id",
2117
+ count: 1,
2118
+ array: false
2119
+ },
2120
+ {
2121
+ name: "protocol_address",
2122
+ count: 1,
2123
+ array: false
2124
+ },
2125
+ {
2126
+ name: "token_address",
2127
+ count: 1,
2128
+ array: false
2129
+ },
2130
+ {
2131
+ name: "spender_address",
2132
+ count: 1,
2133
+ array: false
2134
+ },
2135
+ {
2136
+ name: "actual_count",
2137
+ count: 1,
2138
+ array: false
2139
+ },
2140
+ {
2141
+ name: "source_count",
2142
+ count: 1,
2143
+ array: false
2144
+ },
2145
+ {
2146
+ name: "tree_ids",
2147
+ count: 120,
2148
+ array: true
2149
+ },
2150
+ {
2151
+ name: "roots",
2152
+ count: 120,
2153
+ array: true
2154
+ },
2155
+ {
2156
+ name: "nullifiers",
2157
+ count: 120,
2158
+ array: true
2159
+ },
2160
+ {
2161
+ name: "remainder_commitments",
2162
+ count: 120,
2163
+ array: true
2164
+ },
2165
+ {
2166
+ name: "expiries",
2167
+ count: 120,
2168
+ array: true
2169
+ },
2170
+ {
2171
+ name: "total_amount",
2172
+ count: 1,
2173
+ array: false
2174
+ },
2175
+ {
2176
+ name: "deadline",
2177
+ count: 1,
2178
+ array: false
2179
+ },
2180
+ {
2181
+ name: "delivery_hash_high",
2182
+ count: 1,
2183
+ array: false
2184
+ },
2185
+ {
2186
+ name: "delivery_hash_low",
2187
+ count: 1,
2188
+ array: false
2189
+ },
2190
+ {
2191
+ name: "recovery_amounts",
2192
+ count: 120,
2193
+ array: true
2194
+ },
2195
+ {
2196
+ name: "auth_digest_high",
2197
+ count: 1,
2198
+ array: false
2199
+ },
2200
+ {
2201
+ name: "auth_digest_low",
2202
+ count: 1,
2203
+ array: false
2204
+ }
2205
+ ],
2206
+ private: [
2207
+ "public_key_x",
2208
+ "public_key_y",
2209
+ "signature",
2210
+ "spender_wallet_identity",
2211
+ "owner_payouts",
2212
+ "owner_wallet_identities",
2213
+ "input_amounts",
2214
+ "input_nonces",
2215
+ "credit_shared_keys",
2216
+ "leaf_indices",
2217
+ "merkle_paths",
2218
+ "input_source_indices",
2219
+ "draw_amounts"
2220
+ ]
2221
+ },
2222
+ credit_cancel: {
2223
+ artifactSha256: "ff278a04f22d2886c9f27f7785a0b8fc317dd242fd4aa9d0d9398d18b7513daf",
2224
+ keys: {
2225
+ evm: "1f8a3c20cb081d6a90962556da3124919cc4e5675e59ad31562af39299da02fb"
2226
+ },
2227
+ publicInputCount: 11,
2228
+ public: [
2229
+ {
2230
+ name: "chain_id",
2231
+ count: 1,
2232
+ array: false
2233
+ },
2234
+ {
2235
+ name: "protocol_address",
2236
+ count: 1,
2237
+ array: false
2238
+ },
2239
+ {
2240
+ name: "token_address",
2241
+ count: 1,
2242
+ array: false
2243
+ },
2244
+ {
2245
+ name: "owner_address",
2246
+ count: 1,
2247
+ array: false
2248
+ },
2249
+ {
2250
+ name: "tree_id",
2251
+ count: 1,
2252
+ array: false
2253
+ },
2254
+ {
2255
+ name: "merkle_root",
2256
+ count: 1,
2257
+ array: false
2258
+ },
2259
+ {
2260
+ name: "nullifier",
2261
+ count: 1,
2262
+ array: false
2263
+ },
2264
+ {
2265
+ name: "amount",
2266
+ count: 1,
2267
+ array: false
2268
+ },
2269
+ {
2270
+ name: "deadline",
2271
+ count: 1,
2272
+ array: false
2273
+ },
2274
+ {
2275
+ name: "auth_digest_high",
2276
+ count: 1,
2277
+ array: false
2278
+ },
2279
+ {
2280
+ name: "auth_digest_low",
2281
+ count: 1,
2282
+ array: false
2283
+ }
2284
+ ],
2285
+ private: [
2286
+ "public_key_x",
2287
+ "public_key_y",
2288
+ "signature",
2289
+ "spender_payout",
2290
+ "spender_wallet_identity",
2291
+ "owner_wallet_identity",
2292
+ "input_nonce",
2293
+ "expiry",
2294
+ "credit_shared_key",
2295
+ "leaf_index",
2296
+ "merkle_path"
2297
+ ]
2298
+ },
2299
+ credit_top_up: {
2300
+ artifactSha256: "fbe662363d9814983f7940f74369117cd6c84783945fbf527b0ed48d011b58a4",
2301
+ keys: {
2302
+ evm: "44436f31414497a708355426da051ee48ba63fdebcb6cfd72347c37c34c98c50"
2303
+ },
2304
+ publicInputCount: 50,
2305
+ public: [
2306
+ {
2307
+ name: "chain_id",
2308
+ count: 1,
2309
+ array: false
2310
+ },
2311
+ {
2312
+ name: "protocol_address",
2313
+ count: 1,
2314
+ array: false
2315
+ },
2316
+ {
2317
+ name: "token_address",
2318
+ count: 1,
2319
+ array: false
2320
+ },
2321
+ {
2322
+ name: "owner_address",
2323
+ count: 1,
2324
+ array: false
2325
+ },
2326
+ {
2327
+ name: "actual_count",
2328
+ count: 1,
2329
+ array: false
2330
+ },
2331
+ {
2332
+ name: "source_count",
2333
+ count: 1,
2334
+ array: false
2335
+ },
2336
+ {
2337
+ name: "input_tree_ids",
2338
+ count: 10,
2339
+ array: true
2340
+ },
2341
+ {
2342
+ name: "merkle_roots",
2343
+ count: 10,
2344
+ array: true
2345
+ },
2346
+ {
2347
+ name: "nullifiers",
2348
+ count: 10,
2349
+ array: true
2350
+ },
2351
+ {
2352
+ name: "credit_commitment",
2353
+ count: 1,
2354
+ array: false
2355
+ },
2356
+ {
2357
+ name: "change_commitment",
2358
+ count: 1,
2359
+ array: false
2360
+ },
2361
+ {
2362
+ name: "delivery_hash_high",
2363
+ count: 1,
2364
+ array: false
2365
+ },
2366
+ {
2367
+ name: "delivery_hash_low",
2368
+ count: 1,
2369
+ array: false
2370
+ },
2371
+ {
2372
+ name: "expiry",
2373
+ count: 1,
2374
+ array: false
2375
+ },
2376
+ {
2377
+ name: "deadline",
2378
+ count: 1,
2379
+ array: false
2380
+ },
2381
+ {
2382
+ name: "deposit_amount",
2383
+ count: 1,
2384
+ array: false
2385
+ },
2386
+ {
2387
+ name: "deposit_payer",
2388
+ count: 1,
2389
+ array: false
2390
+ },
2391
+ {
2392
+ name: "credit_tree_id",
2393
+ count: 1,
2394
+ array: false
2395
+ },
2396
+ {
2397
+ name: "credit_merkle_root",
2398
+ count: 1,
2399
+ array: false
2400
+ },
2401
+ {
2402
+ name: "credit_nullifier",
2403
+ count: 1,
2404
+ array: false
2405
+ },
2406
+ {
2407
+ name: "previous_expiry",
2408
+ count: 1,
2409
+ array: false
2410
+ },
2411
+ {
2412
+ name: "auth_digest_high",
2413
+ count: 1,
2414
+ array: false
2415
+ },
2416
+ {
2417
+ name: "auth_digest_low",
2418
+ count: 1,
2419
+ array: false
2420
+ }
2421
+ ],
2422
+ private: [
2423
+ "input_amounts",
2424
+ "input_nonces",
2425
+ "leaf_indices",
2426
+ "merkle_paths",
2427
+ "input_source_indices",
2428
+ "public_key_x",
2429
+ "public_key_y",
2430
+ "signature",
2431
+ "spender_payout",
2432
+ "spender_wallet_identity",
2433
+ "owner_wallet_identity",
2434
+ "credit_amount",
2435
+ "credit_nonce",
2436
+ "credit_shared_key",
2437
+ "change_amount",
2438
+ "change_nonce",
2439
+ "previous_credit_amount",
2440
+ "previous_credit_nonce",
2441
+ "previous_credit_leaf_index",
2442
+ "previous_credit_merkle_path"
2443
+ ]
2444
+ },
2445
+ wallet_registration: {
2446
+ artifactSha256: "65c3d429f6bc9735af3136f7c383214c2eb222cd32655791f37f7ae5dd428048",
2447
+ keys: {
2448
+ evm: "b8171bdb558489c75293ee71f64c1ac534f533ae3b3f71107378e46dbd93dd48"
2449
+ },
2450
+ publicInputCount: 3,
2451
+ public: [
2452
+ {
2453
+ name: "wallet_identity",
2454
+ count: 1,
2455
+ array: false
2456
+ },
2457
+ {
2458
+ name: "auth_digest_high",
2459
+ count: 1,
2460
+ array: false
2461
+ },
2462
+ {
2463
+ name: "auth_digest_low",
2464
+ count: 1,
2465
+ array: false
2466
+ }
2467
+ ],
2468
+ private: [
2469
+ "public_key_x",
2470
+ "public_key_y",
2471
+ "signature"
2472
+ ]
2473
+ }
2474
+ };
2475
+
2476
+ // src/witness.ts
2477
+ var pad2 = (values, count, zero) => {
2478
+ if (values.length > count) throw new Error("witness capacity exceeded");
2479
+ return [...values, ...Array.from({ length: count - values.length }, zero)];
2480
+ };
2481
+ var zeros = () => Array(16).fill(0n);
2482
+ var zeroAuthority = () => ({
2483
+ public_key_x: Array(32).fill(0),
2484
+ public_key_y: Array(32).fill(0),
2485
+ signature: Array(64).fill(0)
2486
+ });
2487
+ function check(ok, message) {
2488
+ if (!ok) throw new Error(message);
2489
+ }
2490
+ function provingRequest(circuitName, privateInputs, expectedPublicInputs, target = "evm") {
2491
+ const schema = witness_layouts_default[circuitName], key = schema.keys[target];
2492
+ check(typeof key === "string", "unpublished proof target");
2493
+ check(
2494
+ expectedPublicInputs.length === schema.publicInputCount,
2495
+ "public input order/width mismatch"
2496
+ );
2497
+ check(
2498
+ Object.keys(privateInputs).length === schema.private.length && schema.private.every((name) => Object.hasOwn(privateInputs, name)),
2499
+ "private witness schema mismatch"
2500
+ );
2501
+ let offset = 0;
2502
+ const publicInputs = {};
2503
+ for (const entry of schema.public) {
2504
+ const values = expectedPublicInputs.slice(offset, offset + entry.count).map((value) => {
2505
+ const n = BigInt(value);
2506
+ check(n >= 0n && n < FIELD_MODULUS, "noncanonical public input");
2507
+ return n;
2508
+ });
2509
+ publicInputs[entry.name] = entry.array ? values : values[0];
2510
+ offset += entry.count;
2511
+ }
2512
+ check(offset === expectedPublicInputs.length, "public input layout mismatch");
2513
+ return {
2514
+ circuitName,
2515
+ target,
2516
+ artifactSha256: schema.artifactSha256,
2517
+ vkSha256: key,
2518
+ expectedPublicInputs: [...expectedPublicInputs],
2519
+ witness: new LocalWitness({ ...privateInputs, ...publicInputs })
2520
+ };
2521
+ }
2522
+ var WitnessBuilder = class {
2523
+ #protocol;
2524
+ constructor(protocol) {
2525
+ this.#protocol = protocol;
2526
+ }
2527
+ static statement(circuitName, expectedPublicInputs, target = "evm") {
2528
+ const schema = witness_layouts_default[circuitName], key = schema.keys[target];
2529
+ check(
2530
+ typeof key === "string" && expectedPublicInputs.length === schema.publicInputCount,
2531
+ "unpublished target or statement width mismatch"
2532
+ );
2533
+ return {
2534
+ circuitName,
2535
+ target,
2536
+ artifactSha256: schema.artifactSha256,
2537
+ vkSha256: key,
2538
+ expectedPublicInputs: [...expectedPublicInputs]
2539
+ };
2540
+ }
2541
+ context(note) {
2542
+ const c = this.#protocol.context;
2543
+ check(
2544
+ note.chainId === c.chainId && note.protocolAddress === BigInt(c.protocolAddress) && note.tokenAddress === BigInt(c.tokenAddress),
2545
+ "note context mismatch"
2546
+ );
2547
+ }
2548
+ async authority(operation, capacity, words, signed, identity) {
2549
+ check(!!signed, "private wallet authorization required");
2550
+ const c = this.#protocol.context, request = {
2551
+ context: { chainId: c.chainId, protocolAddress: BigInt(c.protocolAddress) },
2552
+ operation,
2553
+ capacity,
2554
+ words: words.slice(0, -2).map(BigInt)
2555
+ };
2556
+ check(
2557
+ signed.walletIdentity === identity && signed.digest === computeWalletAuthorizationDigest4(request),
2558
+ "authorization statement mismatch"
2559
+ );
2560
+ const witness = signed.withWitness((value) => value);
2561
+ check(
2562
+ await verifyWalletAuthorization(
2563
+ identity,
2564
+ Uint8Array.from([4, ...witness.public_key_x, ...witness.public_key_y]),
2565
+ Uint8Array.from(witness.signature),
2566
+ request
2567
+ ),
2568
+ "invalid wallet authorization"
2569
+ );
2570
+ return witness;
2571
+ }
2572
+ async membership(leaf, input, sources) {
2573
+ const source = sources.findIndex((value) => value.treeId === input.treeId);
2574
+ check(
2575
+ source >= 0 && Number.isInteger(input.leafIndex) && input.leafIndex >= 0 && input.leafIndex < 65536 && input.path.length === 16,
2576
+ "invalid membership position"
2577
+ );
2578
+ let root = BigInt(leaf);
2579
+ for (let level = 0; level < 16; level++)
2580
+ root = BigInt(
2581
+ await poseidonHash(
2582
+ input.leafIndex >> level & 1 ? [input.path[level], root] : [root, input.path[level]]
2583
+ )
2584
+ );
2585
+ check(root === BigInt(sources[source].merkleRoot), "membership root mismatch");
2586
+ return source;
2587
+ }
2588
+ async noteLeaf(note) {
2589
+ this.context(note);
2590
+ return computeNoteCommitment2(
2591
+ note.chainId,
2592
+ await computeNoteIdentity(BigInt(note.walletIdentity), note.nonce),
2593
+ note.tokenAddress,
2594
+ note.amount
2595
+ );
2596
+ }
2597
+ async creditLeaf(note) {
2598
+ this.context(note);
2599
+ return computeCreditCommitment(
2600
+ note.chainId,
2601
+ note.spenderWalletIdentity,
2602
+ note.ownerWalletIdentity,
2603
+ note.spenderPayout,
2604
+ note.ownerPayout,
2605
+ note.tokenAddress,
2606
+ note.amount,
2607
+ note.nonce,
2608
+ note.expiry,
2609
+ await computeCreditSharedKeyHash(note.creditSharedKey)
2610
+ );
2611
+ }
2612
+ async noteInputs(inputs, sources, nullifiers, identity, authority) {
2613
+ check(inputs.length === nullifiers.length, "input count mismatch");
2614
+ return Promise.all(
2615
+ inputs.map(async (input, i) => {
2616
+ check(input.note.walletIdentity === identity, "input wallet mismatch");
2617
+ const leaf = await this.noteLeaf(input.note);
2618
+ check(
2619
+ await computeNoteNullifier(input.note.chainId, input.note.nonce, leaf) === nullifiers[i],
2620
+ "input nullifier mismatch"
2621
+ );
2622
+ return BigInt(await this.membership(leaf, input, sources));
2623
+ })
2624
+ );
2625
+ }
2626
+ async transact(p) {
2627
+ const c = this.#protocol.context, n = normalizeTransactRequest(c, p.params, p.deliveries, p.funding), words = transactUserPublicInputs(c, p.params, p.deliveries, p.funding);
2628
+ check(
2629
+ p.inputs.length === n.inputCount && p.outputs.length === n.outputCount,
2630
+ "note count mismatch"
2631
+ );
2632
+ const identity = p.inputs[0]?.note.walletIdentity;
2633
+ const unsignedSweep = !!identity && !p.authorization && n.outputCount === 0 && n.depositAmount === 0n && BigInt(p.params.withdrawalAddress) === BigInt(identity);
2634
+ const authority = identity && !unsignedSweep ? await this.authority("transact", n.capacity, words, p.authorization, identity) : zeroAuthority();
2635
+ const sources = await this.noteInputs(
2636
+ p.inputs,
2637
+ p.params.sources,
2638
+ p.params.nullifiers,
2639
+ identity ?? "0x" + "00".repeat(32),
2640
+ authority
2641
+ );
2642
+ for (const [i, note] of p.outputs.entries())
2643
+ check(
2644
+ await this.noteLeaf(note) === p.params.outputCommitments[i],
2645
+ "output commitment mismatch"
2646
+ );
2647
+ const all = [...p.inputs.map((input) => input.note), ...p.outputs];
2648
+ return provingRequest(
2649
+ `transact_user_slots${n.capacity}`,
2650
+ {
2651
+ wallet_identity: identity ? BigInt(identity) : 0n,
2652
+ ...authority,
2653
+ output_wallet_identities: pad2(
2654
+ [
2655
+ ...p.inputs.map(() => 0n),
2656
+ ...p.outputs.map((note) => BigInt(note.walletIdentity))
2657
+ ],
2658
+ n.capacity,
2659
+ () => 0n
2660
+ ),
2661
+ amounts: pad2(
2662
+ all.map((note) => note.amount),
2663
+ n.capacity,
2664
+ () => 0n
2665
+ ),
2666
+ nonces: pad2(
2667
+ all.map((note) => note.nonce),
2668
+ n.capacity,
2669
+ () => 0n
2670
+ ),
2671
+ leaf_indices: pad2(
2672
+ p.inputs.map((input) => BigInt(input.leafIndex)),
2673
+ n.capacity,
2674
+ () => 0n
2675
+ ),
2676
+ merkle_paths: pad2(
2677
+ p.inputs.map((input) => [...input.path]),
2678
+ n.capacity,
2679
+ zeros
2680
+ ),
2681
+ input_source_indices: pad2(sources, n.capacity, () => 0n)
2682
+ },
2683
+ words,
2684
+ p.target
2685
+ );
2686
+ }
2687
+ async creation(p, operation, words) {
2688
+ const state = normalizeCreditDeliveryState(p.state), note = state.note;
2689
+ check(
2690
+ await this.creditLeaf(note) === p.params.creditCommitment && note.ownerPayout === BigInt(p.params.owner) && note.expiry === p.params.expiry,
2691
+ "Credit creation mismatch"
2692
+ );
2693
+ const authority = await this.authority(
2694
+ operation,
2695
+ 10,
2696
+ words,
2697
+ p.authorization,
2698
+ note.ownerWalletIdentity
2699
+ );
2700
+ const sources = await this.noteInputs(
2701
+ p.inputs,
2702
+ p.params.sources,
2703
+ p.params.nullifiers,
2704
+ note.ownerWalletIdentity,
2705
+ authority
2706
+ );
2707
+ if (p.change)
2708
+ check(
2709
+ p.change.walletIdentity === note.ownerWalletIdentity && await this.noteLeaf(p.change) === p.params.changeCommitment,
2710
+ "change commitment mismatch"
2711
+ );
2712
+ else check(BigInt(p.params.changeCommitment) === 0n, "missing change note");
2713
+ return {
2714
+ ...authority,
2715
+ input_amounts: pad2(
2716
+ p.inputs.map((input) => input.note.amount),
2717
+ 10,
2718
+ () => 0n
2719
+ ),
2720
+ input_nonces: pad2(
2721
+ p.inputs.map((input) => input.note.nonce),
2722
+ 10,
2723
+ () => 0n
2724
+ ),
2725
+ leaf_indices: pad2(
2726
+ p.inputs.map((input) => BigInt(input.leafIndex)),
2727
+ 10,
2728
+ () => 0n
2729
+ ),
2730
+ merkle_paths: pad2(
2731
+ p.inputs.map((input) => [...input.path]),
2732
+ 10,
2733
+ zeros
2734
+ ),
2735
+ input_source_indices: pad2(sources, 10, () => 0n),
2736
+ spender_payout: note.spenderPayout,
2737
+ spender_wallet_identity: BigInt(note.spenderWalletIdentity),
2738
+ owner_wallet_identity: BigInt(note.ownerWalletIdentity),
2739
+ credit_amount: note.amount,
2740
+ credit_nonce: note.nonce,
2741
+ credit_shared_key: note.creditSharedKey,
2742
+ change_amount: p.change?.amount ?? 0n,
2743
+ change_nonce: p.change?.nonce ?? 0n
2744
+ };
2745
+ }
2746
+ async createCredit(p) {
2747
+ const words = createCreditPublicInputs(
2748
+ this.#protocol.context,
2749
+ p.params,
2750
+ p.deliveries,
2751
+ p.funding
2752
+ );
2753
+ return provingRequest(
2754
+ "create_credit",
2755
+ await this.creation(p, "create-credit", words),
2756
+ words
2757
+ );
2758
+ }
2759
+ async cancelCredit(p) {
2760
+ const note = normalizeCreditDeliveryState(p.input.state).note, leaf = await this.creditLeaf(note), c = this.#protocol.context;
2761
+ check(
2762
+ await computeCreditNullifier(c.chainId, note.creditSharedKey, leaf) === p.params.nullifier && note.amount === p.params.amount && note.ownerPayout === BigInt(p.params.owner),
2763
+ "Credit cancellation mismatch"
2764
+ );
2765
+ await this.membership(leaf, p.input, [p.params.source]);
2766
+ const words = cancelCreditPublicInputs(c, p.params), authority = await this.authority(
2767
+ "cancel-credit",
2768
+ 1,
2769
+ words,
2770
+ p.authorization,
2771
+ note.ownerWalletIdentity
2772
+ );
2773
+ return provingRequest(
2774
+ "credit_cancel",
2775
+ {
2776
+ ...authority,
2777
+ spender_payout: note.spenderPayout,
2778
+ spender_wallet_identity: BigInt(note.spenderWalletIdentity),
2779
+ owner_wallet_identity: BigInt(note.ownerWalletIdentity),
2780
+ input_nonce: note.nonce,
2781
+ expiry: note.expiry,
2782
+ credit_shared_key: note.creditSharedKey,
2783
+ leaf_index: BigInt(p.input.leafIndex),
2784
+ merkle_path: [...p.input.path]
2785
+ },
2786
+ words
2787
+ );
2788
+ }
2789
+ async drawCredit(p) {
2790
+ const c = this.#protocol.context, profile = selectCreditDrawCircuit(p.inputs.length), capacity = profile.maxSize;
2791
+ check(
2792
+ p.inputs.length === p.amounts.length && p.inputs.length === p.params.nullifiers.length,
2793
+ "draw input count mismatch"
2794
+ );
2795
+ const notes2 = p.inputs.map((input) => normalizeCreditDeliveryState(input.state).note), identity = notes2[0].spenderWalletIdentity;
2796
+ const words = creditDrawPublicInputs(c, p.params, p.deliveries), authority = await this.authority(
2797
+ "credit-draw",
2798
+ capacity,
2799
+ words,
2800
+ p.authorization,
2801
+ identity
2802
+ );
2803
+ const sourceIndices = await Promise.all(
2804
+ notes2.map(async (note, i) => {
2805
+ const leaf = await this.creditLeaf(note);
2806
+ check(
2807
+ note.spenderWalletIdentity === identity && note.spenderPayout === BigInt(p.params.spender) && note.expiry === p.params.expiries[i] && p.amounts[i] > 0n && p.amounts[i] <= note.amount && await computeCreditNullifier(c.chainId, note.creditSharedKey, leaf) === p.params.nullifiers[i],
2808
+ "Credit draw mismatch"
2809
+ );
2810
+ return BigInt(await this.membership(leaf, p.inputs[i], p.params.sources));
2811
+ })
2812
+ );
2813
+ return provingRequest(
2814
+ profile.name,
2815
+ {
2816
+ ...authority,
2817
+ spender_wallet_identity: BigInt(identity),
2818
+ owner_payouts: pad2(
2819
+ notes2.map((note) => note.ownerPayout),
2820
+ capacity,
2821
+ () => 0n
2822
+ ),
2823
+ owner_wallet_identities: pad2(
2824
+ notes2.map((note) => BigInt(note.ownerWalletIdentity)),
2825
+ capacity,
2826
+ () => 0n
2827
+ ),
2828
+ input_amounts: pad2(
2829
+ notes2.map((note) => note.amount),
2830
+ capacity,
2831
+ () => 0n
2832
+ ),
2833
+ input_nonces: pad2(
2834
+ notes2.map((note) => note.nonce),
2835
+ capacity,
2836
+ () => 0n
2837
+ ),
2838
+ credit_shared_keys: pad2(
2839
+ notes2.map((note) => note.creditSharedKey),
2840
+ capacity,
2841
+ () => 0n
2842
+ ),
2843
+ leaf_indices: pad2(
2844
+ p.inputs.map((input) => BigInt(input.leafIndex)),
2845
+ capacity,
2846
+ () => 0n
2847
+ ),
2848
+ merkle_paths: pad2(
2849
+ p.inputs.map((input) => [...input.path]),
2850
+ capacity,
2851
+ zeros
2852
+ ),
2853
+ input_source_indices: pad2(sourceIndices, capacity, () => 0n),
2854
+ draw_amounts: pad2(p.amounts, capacity, () => 0n)
2855
+ },
2856
+ words
2857
+ );
2858
+ }
2859
+ async topUpCredit(p) {
2860
+ const c = this.#protocol.context, previous = normalizeCreditDeliveryState(p.previous.state), next = normalizeCreditDeliveryState(p.state), old = previous.note, note = next.note, leaf = await this.creditLeaf(old);
2861
+ for (const field2 of [
2862
+ "spenderWalletIdentity",
2863
+ "ownerWalletIdentity",
2864
+ "spenderPayout",
2865
+ "ownerPayout",
2866
+ "creditSharedKey"
2867
+ ])
2868
+ check(old[field2] === note[field2], "Credit role or payout changed");
2869
+ check(
2870
+ JSON.stringify(previous.ownerReceivingKeys) === JSON.stringify(next.ownerReceivingKeys) && JSON.stringify(previous.spenderReceivingKeys) === JSON.stringify(next.spenderReceivingKeys),
2871
+ "Credit receiving snapshots changed"
2872
+ );
2873
+ check(
2874
+ old.amount < note.amount && old.expiry <= note.expiry && old.expiry === p.params.previousExpiry && (c.now === void 0 || old.expiry > c.now),
2875
+ "invalid Credit top-up"
2876
+ );
2877
+ check(
2878
+ await computeCreditNullifier(c.chainId, old.creditSharedKey, leaf) === p.params.creditNullifier,
2879
+ "previous Credit nullifier mismatch"
2880
+ );
2881
+ await this.membership(leaf, p.previous, [p.params.creditSource]);
2882
+ const words = topUpCreditPublicInputs(c, p.params, p.deliveries, p.funding), base = await this.creation({ ...p, params: p.params.creation }, "top-up-credit", words);
2883
+ return provingRequest(
2884
+ "credit_top_up",
2885
+ {
2886
+ ...base,
2887
+ previous_credit_amount: old.amount,
2888
+ previous_credit_nonce: old.nonce,
2889
+ previous_credit_leaf_index: BigInt(p.previous.leafIndex),
2890
+ previous_credit_merkle_path: [...p.previous.path]
2891
+ },
2892
+ words
2893
+ );
2894
+ }
2895
+ static async registration(context, registration, authorization, options) {
2896
+ const request = registrationAuthorizationRequest(context, registration, options), words = registrationPublicInputs(context, registration, options);
2897
+ check(
2898
+ authorization.walletIdentity === registration.walletIdentity && authorization.digest === computeWalletAuthorizationDigest4(request),
2899
+ "registry authorization mismatch"
2900
+ );
2901
+ const witness = authorization.withWitness((value) => value);
2902
+ check(
2903
+ await verifyWalletAuthorization(
2904
+ registration.walletIdentity,
2905
+ Uint8Array.from([4, ...witness.public_key_x, ...witness.public_key_y]),
2906
+ Uint8Array.from(witness.signature),
2907
+ request
2908
+ ),
2909
+ "invalid registry authority"
2910
+ );
2911
+ return provingRequest("wallet_registration", { ...witness }, words);
2912
+ }
2913
+ };
2914
+
2915
+ // src/RegistrationOperation.ts
2916
+ function check2(ok, message) {
2917
+ if (!ok) {
2918
+ throw new Error(message);
2919
+ }
2920
+ }
2921
+ function publicProof(bundle) {
2922
+ return {
2923
+ formatVersion: bundle.formatVersion,
2924
+ bbVersion: bundle.bbVersion,
2925
+ circuitName: bundle.circuitName,
2926
+ target: bundle.target,
2927
+ artifactSha256: bundle.artifactSha256,
2928
+ vkSha256: bundle.vkSha256,
2929
+ proofHex: bundle.proofHex,
2930
+ proofSha256: bundle.proofSha256,
2931
+ publicInputs: [...bundle.publicInputs]
2932
+ };
2933
+ }
2934
+ var RegistrationOperation = class _RegistrationOperation {
2935
+ #registry;
2936
+ #runtime;
2937
+ #plan;
2938
+ #authorization;
2939
+ #proof;
2940
+ #hash;
2941
+ #anchor;
2942
+ status;
2943
+ constructor(registry, runtime, plan, status, authorization, proof, hash, anchor) {
2944
+ this.#registry = registry;
2945
+ this.#runtime = { ...runtime };
2946
+ this.#plan = structuredClone(plan);
2947
+ this.status = status;
2948
+ this.#authorization = authorization;
2949
+ this.#proof = proof ? publicProof(proof) : void 0;
2950
+ this.#hash = hash;
2951
+ this.#anchor = anchor ? { ...anchor } : void 0;
2952
+ Object.freeze(this);
2953
+ }
2954
+ static async prepare(registry, options) {
2955
+ const runtime = { ...options };
2956
+ const update = options.update ?? false;
2957
+ check2(typeof update === "boolean", "update must be boolean");
2958
+ await registry.validateDeployment(runtime.reader);
2959
+ const block = await runtime.reader.getBlock(await runtime.reader.getLatestBlockNumber());
2960
+ const context = { ...registry.context, now: block.timestamp };
2961
+ const nonce = await runtime.reader.getRegistryNonce(
2962
+ context,
2963
+ runtime.wallet.walletIdentity,
2964
+ block
2965
+ );
2966
+ check2(
2967
+ typeof nonce === "bigint" && nonce >= 0n && nonce < (1n << 64n) - 1n,
2968
+ "invalid or exhausted registry nonce"
2969
+ );
2970
+ check2(
2971
+ update ? nonce > 0n : nonce === 0n,
2972
+ update ? "wallet is not registered" : "wallet is already registered; prepare an update"
2973
+ );
2974
+ const address = ReceivingAddress2.parse(await registry.resolve(runtime.wallet.getAddress()));
2975
+ const keys = address.getReceivingKeys();
2976
+ const registration = {
2977
+ walletIdentity: runtime.wallet.walletIdentity,
2978
+ keys: {
2979
+ viewingPublicKey: hexlify2(keys.viewingPublicKey),
2980
+ clueKey: hexlify2(keys.clueKey)
2981
+ },
2982
+ nonce,
2983
+ deadline: options.deadline ?? block.timestamp + 300n
2984
+ };
2985
+ const words = registrationPublicInputs(context, registration, {
2986
+ update,
2987
+ expectedNonce: nonce
2988
+ });
2989
+ const statement = WitnessBuilder.statement("wallet_registration", words);
2990
+ check2(
2991
+ (await runtime.reader.getBlock(block.number)).hash === block.hash,
2992
+ "canonical registry block changed while preparing"
2993
+ );
2994
+ return new _RegistrationOperation(
2995
+ registry,
2996
+ runtime,
2997
+ { id: crypto.randomUUID(), context, registration, update, statement },
2998
+ "prepared"
2999
+ );
3000
+ }
3001
+ get id() {
3002
+ return this.#plan.id;
3003
+ }
3004
+ preview() {
3005
+ return {
3006
+ id: this.id,
3007
+ status: this.status,
3008
+ chainId: this.#plan.context.chainId,
3009
+ registryAddress: this.#plan.context.registryAddress,
3010
+ ...structuredClone(this.#plan.registration),
3011
+ update: this.#plan.update
3012
+ };
3013
+ }
3014
+ async authorize(options = {}) {
3015
+ check2(
3016
+ this.status === "prepared" || this.status === "authorized",
3017
+ "registry operation is not awaiting authorization"
3018
+ );
3019
+ options.signal?.throwIfAborted();
3020
+ const provider = this.#runtime.authorization ?? this.#runtime.wallet.exportAuthorization();
3021
+ const p = this.#plan;
3022
+ check2(
3023
+ provider.walletIdentity === p.registration.walletIdentity,
3024
+ "registry wallet authorization capability mismatch"
3025
+ );
3026
+ const request = registrationAuthorizationRequest(p.context, p.registration, {
3027
+ update: p.update,
3028
+ expectedNonce: p.registration.nonce
3029
+ });
3030
+ const authorization = await provider.authorize(request);
3031
+ check2(
3032
+ authorization.walletIdentity === provider.walletIdentity && authorization.digest === computeWalletAuthorizationDigest5(request),
3033
+ "registry authorization statement mismatch"
3034
+ );
3035
+ options.signal?.throwIfAborted();
3036
+ return new _RegistrationOperation(
3037
+ this.#registry,
3038
+ this.#runtime,
3039
+ p,
3040
+ "authorized",
3041
+ authorization
3042
+ );
3043
+ }
3044
+ async prove(options = {}) {
3045
+ check2(
3046
+ this.status === "authorized" && this.#authorization,
3047
+ "private registry authorization required"
3048
+ );
3049
+ const prover = this.#runtime.prover;
3050
+ if (!prover) {
3051
+ throw new MissingCapabilityError("registry prover");
3052
+ }
3053
+ const p = this.#plan;
3054
+ const request = await WitnessBuilder.registration(
3055
+ p.context,
3056
+ p.registration,
3057
+ this.#authorization,
3058
+ { update: p.update, expectedNonce: p.registration.nonce }
3059
+ );
3060
+ check2(
3061
+ JSON.stringify({ ...request, witness: void 0 }) === JSON.stringify(p.statement),
3062
+ "registry proof statement changed"
3063
+ );
3064
+ try {
3065
+ const proof = publicProof(await prover.prove(request, options));
3066
+ const expected = p.statement;
3067
+ check2(
3068
+ proof.formatVersion === 1 && proof.bbVersion === "6.0.0" && proof.circuitName === expected.circuitName && proof.target === expected.target && proof.artifactSha256 === expected.artifactSha256 && proof.vkSha256 === expected.vkSha256 && proof.publicInputs.length === 3 && proof.publicInputs.every(
3069
+ (word2, i) => word2 === expected.expectedPublicInputs[i]
3070
+ ),
3071
+ "registry proof release or public statement mismatch"
3072
+ );
3073
+ check2(/^0x(?:[a-fA-F0-9]{2})+$/.test(proof.proofHex), "malformed registry proof");
3074
+ const bytes = Uint8Array.from(
3075
+ proof.proofHex.slice(2).match(/../g),
3076
+ (byte) => parseInt(byte, 16)
3077
+ );
3078
+ const hash = hexlify2(new Uint8Array(await crypto.subtle.digest("SHA-256", bytes))).slice(2);
3079
+ check2(
3080
+ hash === proof.proofSha256 && await prover.verify(publicProof(proof), structuredClone(expected), options),
3081
+ "registry proof verification failed"
3082
+ );
3083
+ options.signal?.throwIfAborted();
3084
+ return new _RegistrationOperation(
3085
+ this.#registry,
3086
+ this.#runtime,
3087
+ p,
3088
+ "ready",
3089
+ void 0,
3090
+ proof
3091
+ );
3092
+ } catch {
3093
+ options.signal?.throwIfAborted();
3094
+ throw new Error("registry proof generation or verification failed");
3095
+ }
3096
+ }
3097
+ call() {
3098
+ check2(this.#proof, "registry proof is missing");
3099
+ const p = this.#plan;
3100
+ const result = buildRegistrationCalldata(p.context, p.registration, this.#proof.proofHex, {
3101
+ update: p.update,
3102
+ expectedNonce: p.registration.nonce
3103
+ });
3104
+ return { to: result.to, data: result.callData, value: result.value };
3105
+ }
3106
+ async exportTransaction() {
3107
+ check2(
3108
+ this.#proof && this.status !== "prepared" && this.status !== "authorized",
3109
+ "registry operation is not ready"
3110
+ );
3111
+ await this.#registry.validateDeployment(this.#runtime.reader);
3112
+ const block = await this.#runtime.reader.getBlock(
3113
+ await this.#runtime.reader.getLatestBlockNumber()
3114
+ );
3115
+ const p = this.#plan;
3116
+ check2(block.timestamp <= p.registration.deadline, "registry operation has expired");
3117
+ check2(
3118
+ await this.#runtime.reader.getRegistryNonce(
3119
+ p.context,
3120
+ p.registration.walletIdentity,
3121
+ block
3122
+ ) === p.registration.nonce,
3123
+ "registry nonce changed; prepare again"
3124
+ );
3125
+ return this.call();
3126
+ }
3127
+ /** Associate a signed/broadcast transaction; ethers owns sending and receipt waiting. */
3128
+ trackTransaction(transactionHash) {
3129
+ check2(/^0x[a-fA-F0-9]{64}$/.test(transactionHash), "invalid registry transaction hash");
3130
+ check2(
3131
+ this.#proof && ["ready", "uncertain"].includes(this.status),
3132
+ "registry operation is not ready"
3133
+ );
3134
+ return new _RegistrationOperation(
3135
+ this.#registry,
3136
+ this.#runtime,
3137
+ this.#plan,
3138
+ "uncertain",
3139
+ void 0,
3140
+ this.#proof,
3141
+ transactionHash
3142
+ );
3143
+ }
3144
+ async reconcile(options = {}) {
3145
+ options.signal?.throwIfAborted();
3146
+ const { reader } = this.#runtime;
3147
+ const p = this.#plan;
3148
+ await this.#registry.validateDeployment(reader);
3149
+ if (this.#anchor && (await reader.getBlock(this.#anchor.number)).hash !== this.#anchor.hash) {
3150
+ return new _RegistrationOperation(
3151
+ this.#registry,
3152
+ this.#runtime,
3153
+ p,
3154
+ "reorged",
3155
+ void 0,
3156
+ this.#proof,
3157
+ this.#hash
3158
+ );
3159
+ }
3160
+ const hash = options.transactionHash ?? this.#hash;
3161
+ const receipt = hash ? await reader.getReceipt(hash) : null;
3162
+ if (receipt) {
3163
+ check2(
3164
+ receipt.transactionHash === hash && (await reader.getBlock(receipt.block.number)).hash === receipt.block.hash,
3165
+ "registry receipt is not canonical"
3166
+ );
3167
+ const transaction = await reader.getTransaction(hash);
3168
+ const call = this.call();
3169
+ check2(
3170
+ transaction && transaction.transactionHash === hash && transaction.to.toLowerCase() === call.to.toLowerCase() && transaction.data.toLowerCase() === call.data.toLowerCase() && transaction.value === 0n,
3171
+ "registry transaction differs from frozen request"
3172
+ );
3173
+ check2(
3174
+ receipt.status === "success" || receipt.status === "reverted",
3175
+ "registry execution status is missing"
3176
+ );
3177
+ if (receipt.status === "success") {
3178
+ const found = receipt.logs.some((log) => {
3179
+ if (log.address.toLowerCase() !== p.context.registryAddress.toLowerCase() || log.transactionHash !== hash) {
3180
+ return false;
3181
+ }
3182
+ try {
3183
+ const event = ((decoded) => ({
3184
+ eventName: decoded.name,
3185
+ args: decoded.args.toObject()
3186
+ }))(
3187
+ new Interface5(invisiAddressRegistryAbi).parseLog({
3188
+ data: log.data,
3189
+ topics: log.topics
3190
+ })
3191
+ );
3192
+ return event.eventName === "ReceivingKeysSet" && BigInt(event.args.walletIdentity) === BigInt(p.registration.walletIdentity) && event.args.viewingPublicKey.toLowerCase() === p.registration.keys.viewingPublicKey.toLowerCase() && event.args.clueKey.toLowerCase() === p.registration.keys.clueKey.toLowerCase() && event.args.nextNonce === p.registration.nonce + 1n;
3193
+ } catch {
3194
+ return false;
3195
+ }
3196
+ });
3197
+ check2(found, "registry receipt has no matching key update event");
3198
+ check2(
3199
+ (await reader.getBlock(receipt.block.number)).hash === receipt.block.hash,
3200
+ "registry block changed during confirmation"
3201
+ );
3202
+ options.signal?.throwIfAborted();
3203
+ return new _RegistrationOperation(
3204
+ this.#registry,
3205
+ this.#runtime,
3206
+ p,
3207
+ "confirmed",
3208
+ void 0,
3209
+ this.#proof,
3210
+ hash,
3211
+ receipt.block
3212
+ );
3213
+ }
3214
+ }
3215
+ const head = await reader.getBlock(await reader.getLatestBlockNumber());
3216
+ const nonce = await reader.getRegistryNonce(p.context, p.registration.walletIdentity, head);
3217
+ check2(
3218
+ (await reader.getBlock(head.number)).hash === head.hash,
3219
+ "canonical registry block changed during reconciliation"
3220
+ );
3221
+ return new _RegistrationOperation(
3222
+ this.#registry,
3223
+ this.#runtime,
3224
+ p,
3225
+ head.timestamp > p.registration.deadline ? "expired" : nonce !== p.registration.nonce ? "failed" : "uncertain",
3226
+ void 0,
3227
+ this.#proof,
3228
+ hash
3229
+ );
3230
+ }
3231
+ toJSON() {
3232
+ return {
3233
+ id: this.id,
3234
+ kind: this.#plan.update ? "update-address" : "register-address",
3235
+ status: this.status
3236
+ };
3237
+ }
3238
+ [/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
3239
+ return this.toJSON();
3240
+ }
3241
+ };
3242
+
3243
+ // src/AddressRegistry.ts
3244
+ var AddressRegistry = class {
3245
+ context;
3246
+ #lookup;
3247
+ expectedRuntimeCodeHash;
3248
+ constructor(context, options = {}) {
3249
+ if (typeof context.chainId !== "bigint" || context.chainId < 0n || context.chainId >= 1n << 64n || BigInt(getAddress6(context.registryAddress)) === 0n) {
3250
+ throw new Error("invalid registry context");
3251
+ }
3252
+ this.context = Object.freeze({
3253
+ ...context,
3254
+ registryAddress: getAddress6(context.registryAddress)
3255
+ });
3256
+ this.#lookup = options.lookup;
3257
+ this.expectedRuntimeCodeHash = options.expectedRuntimeCodeHash?.toLowerCase();
3258
+ if (this.expectedRuntimeCodeHash && !/^0x[0-9a-f]{64}$/.test(this.expectedRuntimeCodeHash)) {
3259
+ throw new Error("invalid registry runtime profile");
3260
+ }
3261
+ Object.freeze(this);
3262
+ }
3263
+ async validateDeployment(reader) {
3264
+ if (!this.expectedRuntimeCodeHash) {
3265
+ throw new MissingCapabilityError2("trusted registry deployment profile");
3266
+ }
3267
+ if (await reader.getChainId() !== this.context.chainId) {
3268
+ throw new Error("registry chain mismatch");
3269
+ }
3270
+ const code = await reader.getCode(this.context.registryAddress);
3271
+ if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(code) || keccak2566(code) !== this.expectedRuntimeCodeHash) {
3272
+ throw new Error("registry runtime profile mismatch");
3273
+ }
3274
+ }
3275
+ prepareRegistration(options) {
3276
+ return RegistrationOperation.prepare(this, options);
3277
+ }
3278
+ async resolve(address) {
3279
+ const receiving = ReceivingAddress3.parse(address);
3280
+ if (receiving.kind === "short" && !this.#lookup) {
3281
+ throw new MissingCapabilityError2("registry reader");
3282
+ }
3283
+ return (await receiving.resolve(this.#lookup)).toString();
3284
+ }
3285
+ authorization(registration, options) {
3286
+ return registrationAuthorizationRequest(this.context, registration, options);
3287
+ }
3288
+ publicInputs(registration, options) {
3289
+ return registrationPublicInputs(this.context, registration, options);
3290
+ }
3291
+ buildCall(registration, proof, options) {
3292
+ return buildRegistrationCalldata(this.context, registration, proof, options);
3293
+ }
3294
+ };
3295
+
3296
+ // src/Protocol.ts
3297
+ import { Contract as Contract2, getAddress as getAddress7, keccak256 as keccak2568 } from "ethers";
3298
+ import {
3299
+ defineDeployment
3300
+ } from "@invisi-labs/rpc";
3301
+
3302
+ // src/TokenProtocol.ts
3303
+ import { keccak256 as keccak2567 } from "ethers";
3304
+ import { MissingCapabilityError as MissingCapabilityError3 } from "@invisi-labs/core";
3305
+ var TokenProtocol = class {
3306
+ context;
3307
+ expectedRuntimeCodeHash;
3308
+ constructor(context, options = {}) {
3309
+ const normalized = normalizeContext(context);
3310
+ if (BigInt(normalized.protocolAddress) === 0n || BigInt(normalized.tokenAddress) === 0n) {
3311
+ throw new Error("deployment addresses must be nonzero");
3312
+ }
3313
+ if (options.expectedRuntimeCodeHash && !/^0x[0-9a-fA-F]{64}$/.test(options.expectedRuntimeCodeHash)) {
3314
+ throw new Error("invalid runtime code hash");
3315
+ }
3316
+ this.expectedRuntimeCodeHash = options.expectedRuntimeCodeHash?.toLowerCase();
3317
+ this.context = Object.freeze(normalized);
3318
+ Object.freeze(this);
3319
+ }
3320
+ async validateDeployment(reader, options = {}) {
3321
+ if ((options.requireRuntimeProfile ?? true) && !this.expectedRuntimeCodeHash) {
3322
+ throw new MissingCapabilityError3("trusted deployment profile");
3323
+ }
3324
+ if (await reader.getChainId() !== this.context.chainId) {
3325
+ throw new Error("deployment chain mismatch");
3326
+ }
3327
+ const code = await reader.getCode(this.context.protocolAddress);
3328
+ if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(code) || this.expectedRuntimeCodeHash && keccak2567(code) !== this.expectedRuntimeCodeHash) {
3329
+ throw new Error("deployment runtime code profile mismatch");
3330
+ }
3331
+ const tokenCode = await reader.getCode(this.context.tokenAddress);
3332
+ if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(tokenCode)) {
3333
+ throw new Error("token address must have contract code");
3334
+ }
3335
+ }
3336
+ transact(request) {
3337
+ return {
3338
+ to: this.context.protocolAddress,
3339
+ value: 0n,
3340
+ ...buildTransactCalldata({ ...request, context: this.context })
3341
+ };
3342
+ }
3343
+ aggregate(request) {
3344
+ return {
3345
+ to: this.context.protocolAddress,
3346
+ value: 0n,
3347
+ ...buildTransactAggregateCalldata({ ...request, context: this.context })
3348
+ };
3349
+ }
3350
+ async shield(request) {
3351
+ return {
3352
+ to: this.context.protocolAddress,
3353
+ value: 0n,
3354
+ ...await buildShieldCalldata({ ...request, context: this.context })
3355
+ };
3356
+ }
3357
+ createCredit(request) {
3358
+ return {
3359
+ to: this.context.protocolAddress,
3360
+ value: 0n,
3361
+ ...buildCreateCreditCalldata({ ...request, context: this.context })
3362
+ };
3363
+ }
3364
+ drawCredit(request) {
3365
+ return {
3366
+ to: this.context.protocolAddress,
3367
+ value: 0n,
3368
+ ...buildCreditDrawCalldata({ ...request, context: this.context })
3369
+ };
3370
+ }
3371
+ cancelCredit(request) {
3372
+ return {
3373
+ to: this.context.protocolAddress,
3374
+ value: 0n,
3375
+ ...buildCancelCreditCalldata({ ...request, context: this.context })
3376
+ };
3377
+ }
3378
+ topUpCredit(request) {
3379
+ return {
3380
+ to: this.context.protocolAddress,
3381
+ value: 0n,
3382
+ ...buildTopUpCreditCalldata({ ...request, context: this.context })
3383
+ };
3384
+ }
3385
+ };
3386
+
3387
+ // src/Protocol.ts
3388
+ var Protocol = class _Protocol {
3389
+ deployment;
3390
+ context;
3391
+ constructor(options) {
3392
+ known(options, ["deployment"], "protocol options");
3393
+ this.deployment = defineDeployment(options.deployment);
3394
+ this.context = Object.freeze({
3395
+ chainId: this.deployment.chainId,
3396
+ protocolAddress: this.deployment.protocol.address
3397
+ });
3398
+ Object.freeze(this);
3399
+ }
3400
+ /** Load the selected deployment and verify its contract against Chain RPC before returning. */
3401
+ static async fromRpc(rpc, provider, options = {}) {
3402
+ const chainId = (await provider.getNetwork()).chainId;
3403
+ if (typeof chainId !== "bigint" || chainId <= 0n || chainId >= 1n << 64n)
3404
+ throw new Error("invalid protocol chainId");
3405
+ const deployment = await rpc.getDeployment(
3406
+ chainId,
3407
+ options.signal ? { signal: options.signal } : {}
3408
+ );
3409
+ const protocol = new _Protocol({ deployment });
3410
+ if (protocol.context.chainId !== chainId) throw new Error("RPC deployment chain mismatch");
3411
+ await protocol.validateDeployment(provider);
3412
+ return protocol;
3413
+ }
3414
+ async validateDeployment(connection) {
3415
+ const reader = "getNetwork" in connection ? {
3416
+ getChainId: async () => (await connection.getNetwork()).chainId,
3417
+ getCode: async (address) => await connection.getCode(address),
3418
+ getProtocolVersion: async (address) => BigInt(
3419
+ await new Contract2(
3420
+ address,
3421
+ ["function VERSION() view returns (uint256)"],
3422
+ connection
3423
+ ).getFunction("VERSION")()
3424
+ )
3425
+ } : connection;
3426
+ if (await reader.getChainId() !== this.context.chainId)
3427
+ throw new Error("deployment chain mismatch");
3428
+ const code = await reader.getCode(this.context.protocolAddress);
3429
+ if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(code) || keccak2568(code) !== this.deployment.protocol.runtimeCodeHash)
3430
+ throw new Error("protocol runtime code profile mismatch");
3431
+ if (reader.getProtocolVersion && await reader.getProtocolVersion(this.context.protocolAddress) !== 1n)
3432
+ throw new Error("unsupported onchain protocol version");
3433
+ }
3434
+ aggregate(request) {
3435
+ return {
3436
+ to: this.context.protocolAddress,
3437
+ value: 0n,
3438
+ ...buildTransactAggregateCalldata({ ...request, context: this.context })
3439
+ };
3440
+ }
3441
+ /** Build an operation context for one asset within this same deployment. */
3442
+ forToken(tokenAddress) {
3443
+ return new TokenProtocol(
3444
+ { ...this.context, tokenAddress: getAddress7(tokenAddress) },
3445
+ { expectedRuntimeCodeHash: this.deployment.protocol.runtimeCodeHash }
3446
+ );
3447
+ }
3448
+ };
3449
+
3450
+ // src/verify.ts
3451
+ import {
3452
+ computeCreditCommitment as computeCreditCommitment2,
3453
+ computeCreditSharedKeyHash as computeCreditSharedKeyHash2,
3454
+ computeNoteCommitment as computeNoteCommitment3,
3455
+ computeNoteIdentity as computeNoteIdentity2,
3456
+ FIELD_MODULUS as FIELD_MODULUS2
3457
+ } from "@invisi-labs/core";
3458
+ async function verifyNoteCommitment(params) {
3459
+ const expected = await computeNoteCommitment3(
3460
+ params.chainId,
3461
+ await computeNoteIdentity2(BigInt(params.walletIdentity), BigInt(params.nonce)),
3462
+ BigInt(params.tokenAddress),
3463
+ params.amount
3464
+ );
3465
+ return BigInt(expected) === BigInt(params.noteCommitment);
3466
+ }
3467
+ async function verifyCreditCommitment(params) {
3468
+ if (params.creditSharedKey <= 0n || params.creditSharedKey >= FIELD_MODULUS2)
3469
+ throw new RangeError("creditSharedKey must be a nonzero canonical Field");
3470
+ const expected = await computeCreditCommitment2(
3471
+ params.chainId,
3472
+ params.spenderWalletIdentity,
3473
+ params.ownerWalletIdentity,
3474
+ BigInt(params.spenderPayout),
3475
+ BigInt(params.ownerPayout),
3476
+ BigInt(params.tokenAddress),
3477
+ params.amount,
3478
+ params.nonce,
3479
+ params.expiry,
3480
+ await computeCreditSharedKeyHash2(params.creditSharedKey)
3481
+ );
3482
+ return BigInt(expected) === BigInt(params.creditCommitment);
3483
+ }
3484
+
3485
+ // src/withdrawal.ts
3486
+ import {
3487
+ computeNoteCommitment as computeNoteCommitment4,
3488
+ computeNoteIdentity as computeNoteIdentity3,
3489
+ computeNoteNullifier as computeNoteNullifier2
3490
+ } from "@invisi-labs/core";
3491
+ async function buildWithdrawalCalldata(p) {
3492
+ const r = normalizeTransactRequest(p.context, p.params, [], p.funding);
3493
+ if (r.outputCount !== 0 || r.depositAmount !== 0n || p.sourceNotes.length === 0 || p.sourceNotes.length !== r.inputCount) {
3494
+ throw new Error("full withdrawal requires inputs, no private outputs and no funding");
3495
+ }
3496
+ const walletIdentity = BigInt(p.sourceNotes[0].walletIdentity);
3497
+ let total = 0n;
3498
+ for (const [index, note] of p.sourceNotes.entries()) {
3499
+ if (note.chainId !== p.context.chainId || note.protocolAddress !== BigInt(p.context.protocolAddress))
3500
+ throw new Error("source note context mismatch");
3501
+ if (BigInt(note.walletIdentity) !== walletIdentity || note.tokenAddress !== BigInt(p.context.tokenAddress) || note.amount <= 0n)
3502
+ throw new Error("source note wallet/token/amount mismatch");
3503
+ const commitment = await computeNoteCommitment4(
3504
+ note.chainId,
3505
+ await computeNoteIdentity3(walletIdentity, note.nonce),
3506
+ note.tokenAddress,
3507
+ note.amount
3508
+ );
3509
+ const nullifier = await computeNoteNullifier2(note.chainId, note.nonce, commitment);
3510
+ if (nullifier.toLowerCase() !== r.nullifiers[index].toLowerCase())
3511
+ throw new Error("source note nullifier mismatch");
3512
+ total += note.amount;
3513
+ }
3514
+ if (r.withdrawalAmount !== total)
3515
+ throw new Error("withdrawal must equal the full input balance");
3516
+ return buildTransactCalldata({ ...p, deliveries: [] });
3517
+ }
3518
+
3519
+ // src/factory.ts
3520
+ import { Contract as Contract3, getAddress as getAddress8 } from "ethers";
3521
+ async function resolveInstanceAddress(client, factoryAddress, salt) {
3522
+ const instance = await new Contract3(
3523
+ getAddress8(factoryAddress),
3524
+ invisiFactoryAbi,
3525
+ client
3526
+ ).getFunction("getInstanceAddress")(salt);
3527
+ return getAddress8(instance);
3528
+ }
3529
+ export {
3530
+ AddressRegistry,
3531
+ CREATE_CREDIT_FIELDS,
3532
+ CREDIT_DRAW_CAPACITIES,
3533
+ EMPTY_FUNDING,
3534
+ EMPTY_PERMIT,
3535
+ FIELD_MODULUS,
3536
+ Protocol,
3537
+ RegistrationOperation,
3538
+ TRANSACT_CAPACITIES,
3539
+ TokenProtocol,
3540
+ WitnessBuilder,
3541
+ ZERO_ADDRESS,
3542
+ ZERO_WORD,
3543
+ aggregateMemberRequestHash,
3544
+ aggregatePublicInputs,
3545
+ buildCancelCreditCalldata,
3546
+ buildCreateCreditCalldata,
3547
+ buildCreditDrawCalldata,
3548
+ buildRegistrationCalldata,
3549
+ buildShieldCalldata,
3550
+ buildTopUpCreditCalldata,
3551
+ buildTransactAggregateCalldata,
3552
+ buildTransactCalldata,
3553
+ buildWithdrawalCalldata,
3554
+ cancelCreditBaseInputs,
3555
+ cancelCreditPublicInputs,
3556
+ cancelCreditRequestHash,
3557
+ checkDeadline,
3558
+ createCreditBaseInputs,
3559
+ createCreditPublicInputs,
3560
+ createCreditRequestHash,
3561
+ createRegistryReceivingKeyLookup,
3562
+ creditDrawBaseInputs,
3563
+ creditDrawPublicInputs,
3564
+ deliveriesHash,
3565
+ dense,
3566
+ encodeAggregateFundingTypedData,
3567
+ encodeCancelCreditTypedData,
3568
+ encodeCreateCreditFundingTypedData,
3569
+ encodeCreateCreditTypedData,
3570
+ encodeCreditDrawTypedData,
3571
+ encodeCreditProof,
3572
+ encodeShieldFundingTypedData,
3573
+ encodeTopUpCreditFundingTypedData,
3574
+ encodeTopUpCreditTypedData,
3575
+ encodeTransactFundingTypedData,
3576
+ encodeTransactTypedData,
3577
+ envelope,
3578
+ field,
3579
+ fundingFields,
3580
+ getEIP712Domain,
3581
+ known,
3582
+ normalizeContext,
3583
+ normalizeDelivery,
3584
+ normalizeFunding,
3585
+ normalizeSources,
3586
+ normalizeTransactRequest,
3587
+ notes,
3588
+ pad,
3589
+ registrationAuthorizationRequest,
3590
+ registrationPublicInputs,
3591
+ registrationTypedData,
3592
+ resolveInstanceAddress,
3593
+ selectCreditDrawCircuit,
3594
+ selectTransactCapacity,
3595
+ shieldFundingRequestHash,
3596
+ topUpCreditBaseInputs,
3597
+ topUpCreditPublicInputs,
3598
+ topUpCreditRequestHash,
3599
+ transactFundingRequestHash,
3600
+ transactPublicInputs,
3601
+ transactUserPublicInputs,
3602
+ uint,
3603
+ validateCancelCreditRequest,
3604
+ validateCreateCreditRequest,
3605
+ validateCreditDrawRequest,
3606
+ validateFundingSubmission,
3607
+ validateShieldRequest,
3608
+ validateTopUpCreditRequest,
3609
+ verifyCreditCommitment,
3610
+ verifyNoteCommitment,
3611
+ word
3612
+ };
3613
+ //# sourceMappingURL=index.js.map