@invisi-labs/protocol 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -79,8 +79,7 @@ __export(src_exports, {
79
79
  normalizeTransactRequest: () => normalizeTransactRequest,
80
80
  notes: () => notes,
81
81
  pad: () => pad,
82
- registrationAuthorizationRequest: () => registrationAuthorizationRequest,
83
- registrationPublicInputs: () => registrationPublicInputs,
82
+ registrationDigest: () => registrationDigest,
84
83
  registrationTypedData: () => registrationTypedData,
85
84
  resolveInstanceAddress: () => resolveInstanceAddress,
86
85
  selectCreditDrawCircuit: () => selectCreditDrawCircuit,
@@ -106,11 +105,11 @@ __export(src_exports, {
106
105
  module.exports = __toCommonJS(src_exports);
107
106
 
108
107
  // src/AddressRegistry.ts
109
- var import_ethers7 = require("ethers");
110
- var import_core7 = require("@invisi-labs/core");
108
+ var import_ethers3 = require("ethers");
109
+ var import_core3 = require("@invisi-labs/core");
111
110
 
112
111
  // src/RegistrationOperation.ts
113
- var import_ethers6 = require("ethers");
112
+ var import_ethers2 = require("ethers");
114
113
 
115
114
  // src/contracts/abis/InvisiProtocol.ts
116
115
  var invisiProtocolAbi = [
@@ -153,6 +152,11 @@ var invisiProtocolAbi = [
153
152
  "name": "_screener",
154
153
  "type": "address",
155
154
  "internalType": "address"
155
+ },
156
+ {
157
+ "name": "_addressRegistry",
158
+ "type": "address",
159
+ "internalType": "address"
156
160
  }
157
161
  ],
158
162
  "stateMutability": "nonpayable"
@@ -229,6 +233,19 @@ var invisiProtocolAbi = [
229
233
  ],
230
234
  "stateMutability": "view"
231
235
  },
236
+ {
237
+ "type": "function",
238
+ "name": "addressRegistry",
239
+ "inputs": [],
240
+ "outputs": [
241
+ {
242
+ "name": "",
243
+ "type": "address",
244
+ "internalType": "contract IAddressRegistry"
245
+ }
246
+ ],
247
+ "stateMutability": "view"
248
+ },
232
249
  {
233
250
  "type": "function",
234
251
  "name": "cancelCredit",
@@ -422,7 +439,7 @@ var invisiProtocolAbi = [
422
439
  {
423
440
  "name": "permit",
424
441
  "type": "tuple",
425
- "internalType": "struct IInvisiMetaTx.TokenPermit",
442
+ "internalType": "struct IMetaTx.TokenPermit",
426
443
  "components": [
427
444
  {
428
445
  "name": "deadline",
@@ -965,7 +982,7 @@ var invisiProtocolAbi = [
965
982
  {
966
983
  "name": "permit",
967
984
  "type": "tuple",
968
- "internalType": "struct IInvisiMetaTx.TokenPermit",
985
+ "internalType": "struct IMetaTx.TokenPermit",
969
986
  "components": [
970
987
  {
971
988
  "name": "deadline",
@@ -1147,7 +1164,7 @@ var invisiProtocolAbi = [
1147
1164
  {
1148
1165
  "name": "permit",
1149
1166
  "type": "tuple",
1150
- "internalType": "struct IInvisiMetaTx.TokenPermit",
1167
+ "internalType": "struct IMetaTx.TokenPermit",
1151
1168
  "components": [
1152
1169
  {
1153
1170
  "name": "deadline",
@@ -1295,7 +1312,7 @@ var invisiProtocolAbi = [
1295
1312
  {
1296
1313
  "name": "permit",
1297
1314
  "type": "tuple",
1298
- "internalType": "struct IInvisiMetaTx.TokenPermit",
1315
+ "internalType": "struct IMetaTx.TokenPermit",
1299
1316
  "components": [
1300
1317
  {
1301
1318
  "name": "deadline",
@@ -1445,7 +1462,7 @@ var invisiProtocolAbi = [
1445
1462
  {
1446
1463
  "name": "permit",
1447
1464
  "type": "tuple",
1448
- "internalType": "struct IInvisiMetaTx.TokenPermit",
1465
+ "internalType": "struct IMetaTx.TokenPermit",
1449
1466
  "components": [
1450
1467
  {
1451
1468
  "name": "deadline",
@@ -2532,6 +2549,11 @@ var invisiProtocolAbi = [
2532
2549
  }
2533
2550
  ]
2534
2551
  },
2552
+ {
2553
+ "type": "error",
2554
+ "name": "InvalidAddressRegistry",
2555
+ "inputs": []
2556
+ },
2535
2557
  {
2536
2558
  "type": "error",
2537
2559
  "name": "InvalidAggregateBatch",
@@ -2908,6 +2930,11 @@ var invisiFactoryAbi = [
2908
2930
  "name": "screener_",
2909
2931
  "type": "address",
2910
2932
  "internalType": "address"
2933
+ },
2934
+ {
2935
+ "name": "addressRegistry_",
2936
+ "type": "address",
2937
+ "internalType": "address"
2911
2938
  }
2912
2939
  ],
2913
2940
  "outputs": [
@@ -2960,6 +2987,11 @@ var invisiFactoryAbi = [
2960
2987
  "name": "screener_",
2961
2988
  "type": "address",
2962
2989
  "internalType": "address"
2990
+ },
2991
+ {
2992
+ "name": "addressRegistry_",
2993
+ "type": "address",
2994
+ "internalType": "address"
2963
2995
  }
2964
2996
  ],
2965
2997
  "outputs": [
@@ -3343,13 +3375,7 @@ var invisiFactoryAbi = [
3343
3375
  var invisiAddressRegistryAbi = [
3344
3376
  {
3345
3377
  "type": "constructor",
3346
- "inputs": [
3347
- {
3348
- "name": "verifier",
3349
- "type": "address",
3350
- "internalType": "contract IVerifier"
3351
- }
3352
- ],
3378
+ "inputs": [],
3353
3379
  "stateMutability": "nonpayable"
3354
3380
  },
3355
3381
  {
@@ -3365,6 +3391,49 @@ var invisiAddressRegistryAbi = [
3365
3391
  ],
3366
3392
  "stateMutability": "view"
3367
3393
  },
3394
+ {
3395
+ "type": "function",
3396
+ "name": "eip712Domain",
3397
+ "inputs": [],
3398
+ "outputs": [
3399
+ {
3400
+ "name": "fields",
3401
+ "type": "bytes1",
3402
+ "internalType": "bytes1"
3403
+ },
3404
+ {
3405
+ "name": "name",
3406
+ "type": "string",
3407
+ "internalType": "string"
3408
+ },
3409
+ {
3410
+ "name": "version",
3411
+ "type": "string",
3412
+ "internalType": "string"
3413
+ },
3414
+ {
3415
+ "name": "chainId",
3416
+ "type": "uint256",
3417
+ "internalType": "uint256"
3418
+ },
3419
+ {
3420
+ "name": "verifyingContract",
3421
+ "type": "address",
3422
+ "internalType": "address"
3423
+ },
3424
+ {
3425
+ "name": "salt",
3426
+ "type": "bytes32",
3427
+ "internalType": "bytes32"
3428
+ },
3429
+ {
3430
+ "name": "extensions",
3431
+ "type": "uint256[]",
3432
+ "internalType": "uint256[]"
3433
+ }
3434
+ ],
3435
+ "stateMutability": "view"
3436
+ },
3368
3437
  {
3369
3438
  "type": "function",
3370
3439
  "name": "isRegistered",
@@ -3417,7 +3486,7 @@ var invisiAddressRegistryAbi = [
3417
3486
  {
3418
3487
  "name": "keys",
3419
3488
  "type": "tuple",
3420
- "internalType": "struct IInvisiAddressRegistry.ReceivingKeys",
3489
+ "internalType": "struct IAddressRegistry.ReceivingKeys",
3421
3490
  "components": [
3422
3491
  {
3423
3492
  "name": "viewingPublicKey",
@@ -3446,7 +3515,7 @@ var invisiAddressRegistryAbi = [
3446
3515
  {
3447
3516
  "name": "registration",
3448
3517
  "type": "tuple",
3449
- "internalType": "struct IInvisiAddressRegistry.Registration",
3518
+ "internalType": "struct IAddressRegistry.Registration",
3450
3519
  "components": [
3451
3520
  {
3452
3521
  "name": "walletIdentity",
@@ -3456,7 +3525,7 @@ var invisiAddressRegistryAbi = [
3456
3525
  {
3457
3526
  "name": "keys",
3458
3527
  "type": "tuple",
3459
- "internalType": "struct IInvisiAddressRegistry.ReceivingKeys",
3528
+ "internalType": "struct IAddressRegistry.ReceivingKeys",
3460
3529
  "components": [
3461
3530
  {
3462
3531
  "name": "viewingPublicKey",
@@ -3483,7 +3552,7 @@ var invisiAddressRegistryAbi = [
3483
3552
  ]
3484
3553
  },
3485
3554
  {
3486
- "name": "proof",
3555
+ "name": "signature",
3487
3556
  "type": "bytes",
3488
3557
  "internalType": "bytes"
3489
3558
  }
@@ -3491,19 +3560,6 @@ var invisiAddressRegistryAbi = [
3491
3560
  "outputs": [],
3492
3561
  "stateMutability": "nonpayable"
3493
3562
  },
3494
- {
3495
- "type": "function",
3496
- "name": "registrationVerifier",
3497
- "inputs": [],
3498
- "outputs": [
3499
- {
3500
- "name": "",
3501
- "type": "address",
3502
- "internalType": "contract IVerifier"
3503
- }
3504
- ],
3505
- "stateMutability": "view"
3506
- },
3507
3563
  {
3508
3564
  "type": "function",
3509
3565
  "name": "supportsInterface",
@@ -3530,7 +3586,7 @@ var invisiAddressRegistryAbi = [
3530
3586
  {
3531
3587
  "name": "registration",
3532
3588
  "type": "tuple",
3533
- "internalType": "struct IInvisiAddressRegistry.Registration",
3589
+ "internalType": "struct IAddressRegistry.Registration",
3534
3590
  "components": [
3535
3591
  {
3536
3592
  "name": "walletIdentity",
@@ -3540,7 +3596,7 @@ var invisiAddressRegistryAbi = [
3540
3596
  {
3541
3597
  "name": "keys",
3542
3598
  "type": "tuple",
3543
- "internalType": "struct IInvisiAddressRegistry.ReceivingKeys",
3599
+ "internalType": "struct IAddressRegistry.ReceivingKeys",
3544
3600
  "components": [
3545
3601
  {
3546
3602
  "name": "viewingPublicKey",
@@ -3567,7 +3623,7 @@ var invisiAddressRegistryAbi = [
3567
3623
  ]
3568
3624
  },
3569
3625
  {
3570
- "name": "proof",
3626
+ "name": "signature",
3571
3627
  "type": "bytes",
3572
3628
  "internalType": "bytes"
3573
3629
  }
@@ -3575,6 +3631,12 @@ var invisiAddressRegistryAbi = [
3575
3631
  "outputs": [],
3576
3632
  "stateMutability": "nonpayable"
3577
3633
  },
3634
+ {
3635
+ "type": "event",
3636
+ "name": "EIP712DomainChanged",
3637
+ "inputs": [],
3638
+ "anonymous": false
3639
+ },
3578
3640
  {
3579
3641
  "type": "event",
3580
3642
  "name": "ReceivingKeysSet",
@@ -3628,12 +3690,12 @@ var invisiAddressRegistryAbi = [
3628
3690
  },
3629
3691
  {
3630
3692
  "type": "error",
3631
- "name": "InvalidRegistrationProof",
3693
+ "name": "InvalidRegistrationSignature",
3632
3694
  "inputs": []
3633
3695
  },
3634
3696
  {
3635
3697
  "type": "error",
3636
- "name": "InvalidVerifier",
3698
+ "name": "InvalidShortString",
3637
3699
  "inputs": []
3638
3700
  },
3639
3701
  {
@@ -3641,11 +3703,6 @@ var invisiAddressRegistryAbi = [
3641
3703
  "name": "InvalidWalletIdentity",
3642
3704
  "inputs": []
3643
3705
  },
3644
- {
3645
- "type": "error",
3646
- "name": "InvalidWalletStatement",
3647
- "inputs": []
3648
- },
3649
3706
  {
3650
3707
  "type": "error",
3651
3708
  "name": "NonceExhausted",
@@ -3665,17 +3722,27 @@ var invisiAddressRegistryAbi = [
3665
3722
  "type": "error",
3666
3723
  "name": "RegistrationExpired",
3667
3724
  "inputs": []
3725
+ },
3726
+ {
3727
+ "type": "error",
3728
+ "name": "StringTooLong",
3729
+ "inputs": [
3730
+ {
3731
+ "name": "str",
3732
+ "type": "string",
3733
+ "internalType": "string"
3734
+ }
3735
+ ]
3668
3736
  }
3669
3737
  ];
3670
3738
 
3671
3739
  // src/RegistrationOperation.ts
3672
- var import_core6 = require("@invisi-labs/core");
3740
+ var import_core2 = require("@invisi-labs/core");
3673
3741
 
3674
3742
  // src/registry.ts
3675
3743
  var import_ethers = require("ethers");
3676
3744
  var import_core = require("@invisi-labs/core");
3677
3745
  var MAX_NONCE = (1n << 64n) - 1n;
3678
- var MASK128 = (1n << 128n) - 1n;
3679
3746
  function uint64(value, name) {
3680
3747
  if (typeof value !== "bigint" || value < 0n || value > MAX_NONCE)
3681
3748
  throw new RangeError(`${name} must be uint64`);
@@ -3704,8 +3771,12 @@ function normalize(context, registration, options) {
3704
3771
  uint64(context.chainId, "chainId");
3705
3772
  const registryAddress = (0, import_ethers.getAddress)(context.registryAddress);
3706
3773
  if (BigInt(registryAddress) === 0n) throw new Error("Registry address must be nonzero");
3774
+ if (!/^0x(?:[0-9a-fA-F]{40}|[0-9a-fA-F]{64})$/.test(registration.walletIdentity))
3775
+ throw new Error("Wallet identity must be an EVM owner or padded bytes32");
3707
3776
  const walletIdentity = (0, import_core.decodeAddress)(
3708
- import_core.ReceivingAddress.fromIdentity(registration.walletIdentity).toString()
3777
+ import_core.ReceivingAddress.fromIdentity(
3778
+ (0, import_ethers.toBeHex)(BigInt(registration.walletIdentity), 20)
3779
+ ).toString()
3709
3780
  ).walletIdentity;
3710
3781
  const keys = normalizeKeys(walletIdentity, registration.keys);
3711
3782
  const nonce = uint64(registration.nonce, "nonce"), deadline = uint64(registration.deadline, "deadline");
@@ -3720,44 +3791,42 @@ function normalize(context, registration, options) {
3720
3791
  throw new Error("Registration expired");
3721
3792
  return { registryAddress, registration: { walletIdentity, keys, nonce, deadline } };
3722
3793
  }
3723
- function registrationAuthorizationRequest(context, registration, options = {}) {
3724
- const normalized = normalize(context, registration, options), r = normalized.registration;
3725
- const keysHash = BigInt(
3726
- (0, import_ethers.keccak256)((0, import_ethers.concat)([r.keys.viewingPublicKey, r.keys.clueKey]))
3727
- );
3794
+ function registrationTypedData(context, registration, options = {}) {
3795
+ const { registryAddress, registration: r } = normalize(context, registration, options);
3796
+ const primaryType = options.update ? "UpdateReceivingKeys" : "RegisterReceivingKeys";
3728
3797
  return {
3729
- context: { chainId: context.chainId, protocolAddress: BigInt(normalized.registryAddress) },
3730
- operation: options.update ? "update-address" : "register-address",
3731
- capacity: 0,
3732
- words: [
3733
- context.chainId,
3734
- BigInt(normalized.registryAddress),
3735
- BigInt(r.walletIdentity),
3736
- r.nonce,
3737
- r.deadline,
3738
- keysHash >> 128n,
3739
- keysHash & MASK128
3740
- ]
3798
+ domain: {
3799
+ name: "InvisiAddressRegistry",
3800
+ version: "1",
3801
+ chainId: context.chainId,
3802
+ verifyingContract: registryAddress
3803
+ },
3804
+ primaryType,
3805
+ types: {
3806
+ [primaryType]: [
3807
+ { name: "walletIdentity", type: "bytes32" },
3808
+ { name: "viewingPublicKey", type: "bytes" },
3809
+ { name: "clueKey", type: "bytes32" },
3810
+ { name: "nonce", type: "uint64" },
3811
+ { name: "deadline", type: "uint64" }
3812
+ ]
3813
+ },
3814
+ message: {
3815
+ walletIdentity: (0, import_ethers.toBeHex)(BigInt(r.walletIdentity), 32),
3816
+ ...r.keys,
3817
+ nonce: r.nonce,
3818
+ deadline: r.deadline
3819
+ }
3741
3820
  };
3742
3821
  }
3743
- function registrationTypedData(context, registration, options = {}) {
3744
- return (0, import_core.walletAuthorizationTypedData)(
3745
- registrationAuthorizationRequest(context, registration, options)
3746
- );
3747
- }
3748
- function registrationPublicInputs(context, registration, options = {}) {
3749
- const request = registrationAuthorizationRequest(context, registration, options);
3750
- const digest = BigInt((0, import_core.computeWalletAuthorizationDigest)(request));
3751
- return [
3752
- (0, import_ethers.toBeHex)(request.words[2], 32),
3753
- (0, import_ethers.toBeHex)(digest >> 128n, 32),
3754
- (0, import_ethers.toBeHex)(digest & MASK128, 32)
3755
- ];
3822
+ function registrationDigest(context, registration, options = {}) {
3823
+ const typed = registrationTypedData(context, registration, options);
3824
+ return import_ethers.TypedDataEncoder.hash(typed.domain, typed.types, typed.message);
3756
3825
  }
3757
- function buildRegistrationCalldata(context, registration, proof, options = {}) {
3826
+ function buildRegistrationCalldata(context, registration, signature, options = {}) {
3758
3827
  const normalized = normalize(context, registration, options);
3759
- if (typeof proof !== "string" || !(0, import_ethers.isHexString)(proof) || proof.length <= 2 || proof.length % 2 !== 0)
3760
- throw new Error("Registration proof must be nonempty hexadecimal bytes");
3828
+ if (typeof signature !== "string" || !(0, import_ethers.isHexString)(signature) || signature.length % 2 !== 0)
3829
+ throw new Error("Registration signature must be hexadecimal bytes");
3761
3830
  return {
3762
3831
  to: normalized.registryAddress,
3763
3832
  value: 0n,
@@ -3768,10 +3837,9 @@ function buildRegistrationCalldata(context, registration, proof, options = {}) {
3768
3837
  ...normalized.registration,
3769
3838
  walletIdentity: (0, import_ethers.toBeHex)(BigInt(normalized.registration.walletIdentity), 32)
3770
3839
  },
3771
- proof
3840
+ signature
3772
3841
  ]
3773
- ),
3774
- publicInputs: registrationPublicInputs(context, normalized.registration, options)
3842
+ )
3775
3843
  };
3776
3844
  }
3777
3845
  function createRegistryReceivingKeyLookup(client, registryAddress) {
@@ -3795,161 +3863,513 @@ function createRegistryReceivingKeyLookup(client, registryAddress) {
3795
3863
  };
3796
3864
  }
3797
3865
 
3798
- // src/witness.ts
3799
- var import_core5 = require("@invisi-labs/core");
3800
- var import_prover = require("@invisi-labs/prover");
3801
-
3802
- // src/credit-create.ts
3803
- var import_ethers3 = require("ethers");
3804
- var import_core2 = require("@invisi-labs/core");
3805
-
3806
- // src/validation.ts
3807
- var import_ethers2 = require("ethers");
3808
- var FIELD_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
3809
- var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
3810
- var ZERO_WORD = (0, import_ethers2.toBeHex)(0n, 32);
3811
- var EMPTY_PERMIT = {
3812
- deadline: 0n,
3813
- v: 0,
3814
- r: ZERO_WORD,
3815
- s: ZERO_WORD
3816
- };
3817
- var EMPTY_FUNDING = {
3818
- payer: ZERO_ADDRESS,
3819
- amount: 0n,
3820
- sigNonce: 0n,
3821
- deadline: 0n,
3822
- signature: "0x",
3823
- permit: EMPTY_PERMIT
3824
- };
3825
- function uint(v, bits, name = "value") {
3826
- if (typeof v !== "bigint" && typeof v !== "number" && typeof v !== "string" || typeof v === "number" && !Number.isSafeInteger(v))
3827
- throw new Error(`${name} must be an integer`);
3828
- const n = BigInt(v);
3829
- if (n < 0n || n >= 1n << BigInt(bits)) throw new Error(`${name} exceeds u${bits}`);
3830
- return n;
3831
- }
3832
- function field(v, name = "field") {
3833
- const n = uint(v, 256, name);
3834
- if (n >= FIELD_MODULUS) throw new Error(`${name} is noncanonical field`);
3835
- return n;
3836
- }
3837
- var word = (v) => (0, import_ethers2.toBeHex)(typeof v === "bigint" ? v : BigInt(v), 32);
3838
- function dense(v, name) {
3839
- if (!Array.isArray(v)) throw new Error(`${name} must be array`);
3840
- for (let i = 0; i < v.length; i++)
3841
- if (!Object.hasOwn(v, i) || v[i] === void 0 || v[i] === null)
3842
- throw new Error(`${name} has missing or sparse entries`);
3843
- return v;
3844
- }
3845
- function known(v, keys, name = "params") {
3846
- if (!v || typeof v !== "object" || Array.isArray(v) || Object.keys(v).some((k) => !keys.includes(k)))
3847
- throw new Error(`${name} has unsupported fields`);
3848
- }
3849
- function notes(v, name) {
3850
- const r = dense(v, name).map((v2) => word(field(v2, name)));
3851
- if (r.some((v2) => BigInt(v2) === 0n) || new Set(r).size !== r.length)
3852
- throw new Error(`duplicate or zero ${name}`);
3853
- return r;
3854
- }
3855
- function envelope(v, length, version) {
3856
- if (!(0, import_ethers2.isHexString)(v) || !/^0x(?:[a-fA-F0-9]{2})*$/.test(v) || (0, import_ethers2.dataLength)(v) !== length)
3857
- throw new Error(`ciphertext must be ${length} bytes`);
3858
- if (version !== void 0 && Number.parseInt(v.slice(2, 4), 16) !== version)
3859
- throw new Error("unsupported ciphertext envelope version");
3860
- return v;
3861
- }
3862
- function normalizeContext(c) {
3863
- return {
3864
- ...c,
3865
- chainId: uint(c.chainId, 64, "chainId"),
3866
- protocolAddress: (0, import_ethers2.getAddress)(c.protocolAddress),
3867
- tokenAddress: (0, import_ethers2.getAddress)(c.tokenAddress)
3868
- };
3869
- }
3870
- function checkDeadline(c, value) {
3871
- const n = uint(value, 64, "deadline");
3872
- if (c.now !== void 0 && n < uint(c.now, 64, "now")) throw new Error("deadline has expired");
3873
- return n;
3874
- }
3875
- function normalizeSources(sources, inputCount, capacity) {
3876
- dense(sources, "sources");
3877
- if (inputCount < 0 || inputCount > capacity || sources.length > inputCount || (inputCount === 0 ? sources.length !== 0 : sources.length === 0))
3878
- throw new Error("source count must be 1..inputCount, or empty for zero inputs");
3879
- let previous = 0n;
3880
- return sources.map((s) => {
3881
- known(s, ["treeId", "merkleRoot"], "source");
3882
- const treeId = uint(s.treeId, 64, "treeId"), merkleRoot = word(field(s.merkleRoot, "merkleRoot"));
3883
- if (treeId === 0n || treeId <= previous || BigInt(merkleRoot) === 0n)
3884
- throw new Error("sources must have positive roots and strictly ascending tree IDs");
3885
- previous = treeId;
3886
- return { treeId, merkleRoot };
3887
- });
3888
- }
3889
- var pad = (v, n) => [
3890
- ...v,
3891
- ...Array(n - v.length).fill(0n)
3892
- ];
3893
- function normalizeDelivery(value, options = {}) {
3894
- known(value, ["ciphertext", "clue"], "delivery");
3895
- if (options.empty) {
3896
- if (value.ciphertext !== "0x" || value.clue !== "0x")
3897
- throw new Error("absent output requires an empty delivery");
3898
- return { ciphertext: "0x", clue: "0x" };
3866
+ // src/RegistrationOperation.ts
3867
+ function check(ok, message) {
3868
+ if (!ok) {
3869
+ throw new Error(message);
3899
3870
  }
3900
- const ciphertext = envelope(
3901
- value.ciphertext,
3902
- options.credit ? 400 : 158,
3903
- options.credit ? 3 : 1
3904
- );
3905
- const clue = envelope(value.clue, 68);
3906
- if (clue.slice(130, 132).toLowerCase() !== "18") throw new Error("clue precision must be 24");
3907
- return { ciphertext, clue };
3908
3871
  }
3909
- var deliveriesHash = (v) => (0, import_ethers2.keccak256)(
3910
- import_ethers2.AbiCoder.defaultAbiCoder().encode(
3911
- [
3912
- {
3913
- type: "tuple[]",
3914
- components: [
3915
- { name: "ciphertext", type: "bytes" },
3916
- { name: "clue", type: "bytes" }
3917
- ]
3918
- }
3919
- ].map((parameter) => import_ethers2.ParamType.from(parameter)),
3920
- [dense(v, "deliveries")]
3921
- )
3922
- );
3923
- function normalizeFunding(input = {}) {
3924
- const f = { ...EMPTY_FUNDING, ...input };
3925
- (0, import_ethers2.getAddress)(f.payer);
3926
- uint(f.amount, 128, "depositAmount");
3927
- uint(f.sigNonce, 256, "sigNonce");
3928
- uint(f.deadline, 256, "funding deadline");
3929
- if (!(0, import_ethers2.isHexString)(f.signature) || !/^0x(?:[a-fA-F0-9]{2})*$/.test(f.signature))
3930
- throw new Error("invalid signature bytes");
3931
- const p = f.permit;
3872
+ var RegistrationOperation = class _RegistrationOperation {
3873
+ #registry;
3874
+ #runtime;
3875
+ #plan;
3876
+ #signature;
3877
+ #hash;
3878
+ #anchor;
3879
+ status;
3880
+ constructor(registry, runtime, plan, status, signature, hash, anchor) {
3881
+ this.#registry = registry;
3882
+ this.#runtime = { ...runtime };
3883
+ this.#plan = structuredClone(plan);
3884
+ this.status = status;
3885
+ this.#signature = signature;
3886
+ this.#hash = hash;
3887
+ this.#anchor = anchor ? { ...anchor } : void 0;
3888
+ Object.freeze(this);
3889
+ }
3890
+ static async prepare(registry, options) {
3891
+ const runtime = { ...options };
3892
+ const update = options.update ?? false;
3893
+ check(typeof update === "boolean", "update must be boolean");
3894
+ await registry.validateDeployment(runtime.reader);
3895
+ const block = await runtime.reader.getBlock(await runtime.reader.getLatestBlockNumber());
3896
+ const context = { ...registry.context, now: block.timestamp };
3897
+ const nonce = await runtime.reader.getRegistryNonce(
3898
+ context,
3899
+ runtime.wallet.walletIdentity,
3900
+ block
3901
+ );
3902
+ check(
3903
+ typeof nonce === "bigint" && nonce >= 0n && nonce < (1n << 64n) - 1n,
3904
+ "invalid or exhausted registry nonce"
3905
+ );
3906
+ check(
3907
+ update ? nonce > 0n : nonce === 0n,
3908
+ update ? "wallet is not registered" : "wallet is already registered; prepare an update"
3909
+ );
3910
+ const address = import_core2.ReceivingAddress.parse(await registry.resolve(runtime.wallet.getAddress()));
3911
+ const keys = address.getReceivingKeys();
3912
+ const registration = {
3913
+ walletIdentity: runtime.wallet.walletIdentity,
3914
+ keys: {
3915
+ viewingPublicKey: (0, import_ethers2.hexlify)(keys.viewingPublicKey),
3916
+ clueKey: (0, import_ethers2.hexlify)(keys.clueKey)
3917
+ },
3918
+ nonce,
3919
+ deadline: options.deadline ?? block.timestamp + 300n
3920
+ };
3921
+ registrationTypedData(context, registration, { update, expectedNonce: nonce });
3922
+ check(
3923
+ (await runtime.reader.getBlock(block.number)).hash === block.hash,
3924
+ "canonical registry block changed while preparing"
3925
+ );
3926
+ return new _RegistrationOperation(
3927
+ registry,
3928
+ runtime,
3929
+ { id: crypto.randomUUID(), context, registration, update },
3930
+ "prepared"
3931
+ );
3932
+ }
3933
+ get id() {
3934
+ return this.#plan.id;
3935
+ }
3936
+ preview() {
3937
+ return {
3938
+ id: this.id,
3939
+ status: this.status,
3940
+ chainId: this.#plan.context.chainId,
3941
+ registryAddress: this.#plan.context.registryAddress,
3942
+ ...structuredClone(this.#plan.registration),
3943
+ update: this.#plan.update
3944
+ };
3945
+ }
3946
+ /** Sign with ethers, or attach externally obtained ERC-1271 signature bytes. */
3947
+ async authorize(options = {}) {
3948
+ check(this.status === "prepared", "registry operation is not awaiting authorization");
3949
+ options.signal?.throwIfAborted();
3950
+ await this.validateFreshness();
3951
+ options.signal?.throwIfAborted();
3952
+ let signature = options.signature;
3953
+ if (signature === void 0) {
3954
+ const signer = this.#runtime.signer;
3955
+ check(signer, "registry signer capability is missing");
3956
+ check(
3957
+ BigInt(await signer.getAddress()) === BigInt(this.#plan.registration.walletIdentity),
3958
+ "registry signer does not match wallet owner"
3959
+ );
3960
+ const typed = this.typedData();
3961
+ signature = await signer.signTypedData(
3962
+ typed.domain,
3963
+ typed.types,
3964
+ typed.message
3965
+ );
3966
+ }
3967
+ check(
3968
+ /^0x(?:[a-fA-F0-9]{2})+$/.test(signature),
3969
+ "registry signature must be nonempty hexadecimal bytes"
3970
+ );
3971
+ const p = this.#plan;
3972
+ const owner = p.registration.walletIdentity;
3973
+ let valid = false;
3974
+ try {
3975
+ const bytes = (0, import_ethers2.getBytes)(signature);
3976
+ const typed = this.typedData();
3977
+ valid = bytes.length === 65 && (bytes[64] === 27 || bytes[64] === 28) && BigInt((0, import_ethers2.verifyTypedData)(typed.domain, typed.types, typed.message, signature)) === BigInt(owner);
3978
+ } catch {
3979
+ valid = false;
3980
+ }
3981
+ if (!valid) {
3982
+ const code = await this.#runtime.reader.getCode(owner);
3983
+ check(/^0x(?:[a-fA-F0-9]{2})*$/.test(code), "invalid owner contract code");
3984
+ check(code !== "0x", "invalid EOA registry signature");
3985
+ const verify = this.#runtime.reader.isValidRegistrationSignature;
3986
+ check(verify, "ERC-1271 registry signature verification capability is missing");
3987
+ check(
3988
+ await verify.call(
3989
+ this.#runtime.reader,
3990
+ owner,
3991
+ registrationDigest(p.context, p.registration, { update: p.update }),
3992
+ signature
3993
+ ),
3994
+ "invalid ERC-1271 registry signature"
3995
+ );
3996
+ }
3997
+ options.signal?.throwIfAborted();
3998
+ return new _RegistrationOperation(
3999
+ this.#registry,
4000
+ this.#runtime,
4001
+ this.#plan,
4002
+ "ready",
4003
+ signature
4004
+ );
4005
+ }
4006
+ /** Empty signatures require the transaction sender to be the wallet owner. */
4007
+ async authorizeDirect() {
4008
+ check(this.status === "prepared", "registry operation is not awaiting authorization");
4009
+ await this.validateFreshness();
4010
+ return new _RegistrationOperation(this.#registry, this.#runtime, this.#plan, "ready", "0x");
4011
+ }
4012
+ typedData() {
4013
+ const p = this.#plan;
4014
+ return registrationTypedData(p.context, p.registration, {
4015
+ update: p.update,
4016
+ expectedNonce: p.registration.nonce
4017
+ });
4018
+ }
4019
+ call() {
4020
+ check(this.#signature !== void 0, "registry signature is missing");
4021
+ const p = this.#plan;
4022
+ const result = buildRegistrationCalldata(p.context, p.registration, this.#signature, {
4023
+ update: p.update,
4024
+ expectedNonce: p.registration.nonce
4025
+ });
4026
+ return { to: result.to, data: result.callData, value: result.value };
4027
+ }
4028
+ async exportTransaction() {
4029
+ check(
4030
+ this.#signature !== void 0 && this.status !== "prepared",
4031
+ "registry operation is not ready"
4032
+ );
4033
+ await this.validateFreshness();
4034
+ return this.call();
4035
+ }
4036
+ async validateFreshness() {
4037
+ await this.#registry.validateDeployment(this.#runtime.reader);
4038
+ const block = await this.#runtime.reader.getBlock(
4039
+ await this.#runtime.reader.getLatestBlockNumber()
4040
+ );
4041
+ const p = this.#plan;
4042
+ check(block.timestamp <= p.registration.deadline, "registry operation has expired");
4043
+ check(
4044
+ await this.#runtime.reader.getRegistryNonce(
4045
+ p.context,
4046
+ p.registration.walletIdentity,
4047
+ block
4048
+ ) === p.registration.nonce,
4049
+ "registry nonce changed; prepare again"
4050
+ );
4051
+ check(
4052
+ (await this.#runtime.reader.getBlock(block.number)).hash === block.hash,
4053
+ "canonical registry block changed during authorization"
4054
+ );
4055
+ }
4056
+ /** Associate a signed/broadcast transaction; ethers owns sending and receipt waiting. */
4057
+ trackTransaction(transactionHash) {
4058
+ check(/^0x[a-fA-F0-9]{64}$/.test(transactionHash), "invalid registry transaction hash");
4059
+ check(
4060
+ this.#signature !== void 0 && ["ready", "uncertain"].includes(this.status),
4061
+ "registry operation is not ready"
4062
+ );
4063
+ return new _RegistrationOperation(
4064
+ this.#registry,
4065
+ this.#runtime,
4066
+ this.#plan,
4067
+ "uncertain",
4068
+ this.#signature,
4069
+ transactionHash
4070
+ );
4071
+ }
4072
+ async reconcile(options = {}) {
4073
+ options.signal?.throwIfAborted();
4074
+ const { reader } = this.#runtime;
4075
+ const p = this.#plan;
4076
+ await this.#registry.validateDeployment(reader);
4077
+ if (this.#anchor && (await reader.getBlock(this.#anchor.number)).hash !== this.#anchor.hash) {
4078
+ return new _RegistrationOperation(
4079
+ this.#registry,
4080
+ this.#runtime,
4081
+ p,
4082
+ "reorged",
4083
+ this.#signature,
4084
+ this.#hash
4085
+ );
4086
+ }
4087
+ const hash = options.transactionHash ?? this.#hash;
4088
+ const receipt = hash ? await reader.getReceipt(hash) : null;
4089
+ if (receipt) {
4090
+ check(
4091
+ receipt.transactionHash === hash && (await reader.getBlock(receipt.block.number)).hash === receipt.block.hash,
4092
+ "registry receipt is not canonical"
4093
+ );
4094
+ const transaction = await reader.getTransaction(hash);
4095
+ const call = this.call();
4096
+ check(
4097
+ transaction && transaction.transactionHash === hash && transaction.to.toLowerCase() === call.to.toLowerCase() && transaction.data.toLowerCase() === call.data.toLowerCase() && transaction.value === 0n && (this.#signature !== "0x" || BigInt(transaction.from) === BigInt(p.registration.walletIdentity)),
4098
+ "registry transaction differs from frozen request"
4099
+ );
4100
+ check(
4101
+ receipt.status === "success" || receipt.status === "reverted",
4102
+ "registry execution status is missing"
4103
+ );
4104
+ if (receipt.status === "success") {
4105
+ const found = receipt.logs.some((log) => {
4106
+ if (log.address.toLowerCase() !== p.context.registryAddress.toLowerCase() || log.transactionHash !== hash) {
4107
+ return false;
4108
+ }
4109
+ try {
4110
+ const event = ((decoded) => ({
4111
+ eventName: decoded.name,
4112
+ args: decoded.args.toObject()
4113
+ }))(
4114
+ new import_ethers2.Interface(invisiAddressRegistryAbi).parseLog({
4115
+ data: log.data,
4116
+ topics: log.topics
4117
+ })
4118
+ );
4119
+ 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;
4120
+ } catch {
4121
+ return false;
4122
+ }
4123
+ });
4124
+ check(found, "registry receipt has no matching key update event");
4125
+ check(
4126
+ (await reader.getBlock(receipt.block.number)).hash === receipt.block.hash,
4127
+ "registry block changed during confirmation"
4128
+ );
4129
+ options.signal?.throwIfAborted();
4130
+ return new _RegistrationOperation(
4131
+ this.#registry,
4132
+ this.#runtime,
4133
+ p,
4134
+ "confirmed",
4135
+ this.#signature,
4136
+ hash,
4137
+ receipt.block
4138
+ );
4139
+ }
4140
+ }
4141
+ const head = await reader.getBlock(await reader.getLatestBlockNumber());
4142
+ const nonce = await reader.getRegistryNonce(p.context, p.registration.walletIdentity, head);
4143
+ check(
4144
+ (await reader.getBlock(head.number)).hash === head.hash,
4145
+ "canonical registry block changed during reconciliation"
4146
+ );
4147
+ return new _RegistrationOperation(
4148
+ this.#registry,
4149
+ this.#runtime,
4150
+ p,
4151
+ head.timestamp > p.registration.deadline ? "expired" : nonce !== p.registration.nonce ? "failed" : "uncertain",
4152
+ this.#signature,
4153
+ hash
4154
+ );
4155
+ }
4156
+ toJSON() {
4157
+ return {
4158
+ id: this.id,
4159
+ kind: this.#plan.update ? "update-receiving-keys" : "register-receiving-keys",
4160
+ status: this.status
4161
+ };
4162
+ }
4163
+ [/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
4164
+ return this.toJSON();
4165
+ }
4166
+ };
4167
+
4168
+ // src/AddressRegistry.ts
4169
+ var AddressRegistry = class {
4170
+ context;
4171
+ #lookup;
4172
+ expectedRuntimeCodeHash;
4173
+ constructor(context, options = {}) {
4174
+ if (typeof context.chainId !== "bigint" || context.chainId < 0n || context.chainId >= 1n << 64n || BigInt((0, import_ethers3.getAddress)(context.registryAddress)) === 0n) {
4175
+ throw new Error("invalid registry context");
4176
+ }
4177
+ this.context = Object.freeze({
4178
+ ...context,
4179
+ registryAddress: (0, import_ethers3.getAddress)(context.registryAddress)
4180
+ });
4181
+ this.#lookup = options.lookup;
4182
+ this.expectedRuntimeCodeHash = options.expectedRuntimeCodeHash?.toLowerCase();
4183
+ if (this.expectedRuntimeCodeHash && !/^0x[0-9a-f]{64}$/.test(this.expectedRuntimeCodeHash)) {
4184
+ throw new Error("invalid registry runtime profile");
4185
+ }
4186
+ Object.freeze(this);
4187
+ }
4188
+ async validateDeployment(reader) {
4189
+ if (!this.expectedRuntimeCodeHash) {
4190
+ throw new import_core3.MissingCapabilityError("trusted registry deployment profile");
4191
+ }
4192
+ if (await reader.getChainId() !== this.context.chainId) {
4193
+ throw new Error("registry chain mismatch");
4194
+ }
4195
+ const code = await reader.getCode(this.context.registryAddress);
4196
+ if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(code) || (0, import_ethers3.keccak256)(code) !== this.expectedRuntimeCodeHash) {
4197
+ throw new Error("registry runtime profile mismatch");
4198
+ }
4199
+ }
4200
+ prepareRegistration(options) {
4201
+ return RegistrationOperation.prepare(this, options);
4202
+ }
4203
+ async resolve(address) {
4204
+ const receiving = import_core3.ReceivingAddress.parse(address);
4205
+ if (receiving.kind === "short" && !this.#lookup) {
4206
+ throw new import_core3.MissingCapabilityError("registry reader");
4207
+ }
4208
+ return (await receiving.resolve(this.#lookup)).toString();
4209
+ }
4210
+ typedData(registration, options) {
4211
+ return registrationTypedData(this.context, registration, options);
4212
+ }
4213
+ digest(registration, options) {
4214
+ return registrationDigest(this.context, registration, options);
4215
+ }
4216
+ buildCall(registration, signature, options) {
4217
+ return buildRegistrationCalldata(this.context, registration, signature, options);
4218
+ }
4219
+ };
4220
+
4221
+ // src/credit-create.ts
4222
+ var import_ethers5 = require("ethers");
4223
+ var import_core4 = require("@invisi-labs/core");
4224
+
4225
+ // src/validation.ts
4226
+ var import_ethers4 = require("ethers");
4227
+ var FIELD_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
4228
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
4229
+ var ZERO_WORD = (0, import_ethers4.toBeHex)(0n, 32);
4230
+ var EMPTY_PERMIT = {
4231
+ deadline: 0n,
4232
+ v: 0,
4233
+ r: ZERO_WORD,
4234
+ s: ZERO_WORD
4235
+ };
4236
+ var EMPTY_FUNDING = {
4237
+ payer: ZERO_ADDRESS,
4238
+ amount: 0n,
4239
+ sigNonce: 0n,
4240
+ deadline: 0n,
4241
+ signature: "0x",
4242
+ permit: EMPTY_PERMIT
4243
+ };
4244
+ function uint(v, bits, name = "value") {
4245
+ if (typeof v !== "bigint" && typeof v !== "number" && typeof v !== "string" || typeof v === "number" && !Number.isSafeInteger(v))
4246
+ throw new Error(`${name} must be an integer`);
4247
+ const n = BigInt(v);
4248
+ if (n < 0n || n >= 1n << BigInt(bits)) throw new Error(`${name} exceeds u${bits}`);
4249
+ return n;
4250
+ }
4251
+ function field(v, name = "field") {
4252
+ const n = uint(v, 256, name);
4253
+ if (n >= FIELD_MODULUS) throw new Error(`${name} is noncanonical field`);
4254
+ return n;
4255
+ }
4256
+ var word = (v) => (0, import_ethers4.toBeHex)(typeof v === "bigint" ? v : BigInt(v), 32);
4257
+ function dense(v, name) {
4258
+ if (!Array.isArray(v)) throw new Error(`${name} must be array`);
4259
+ for (let i = 0; i < v.length; i++)
4260
+ if (!Object.hasOwn(v, i) || v[i] === void 0 || v[i] === null)
4261
+ throw new Error(`${name} has missing or sparse entries`);
4262
+ return v;
4263
+ }
4264
+ function known(v, keys, name = "params") {
4265
+ if (!v || typeof v !== "object" || Array.isArray(v) || Object.keys(v).some((k) => !keys.includes(k)))
4266
+ throw new Error(`${name} has unsupported fields`);
4267
+ }
4268
+ function notes(v, name) {
4269
+ const r = dense(v, name).map((v2) => word(field(v2, name)));
4270
+ if (r.some((v2) => BigInt(v2) === 0n) || new Set(r).size !== r.length)
4271
+ throw new Error(`duplicate or zero ${name}`);
4272
+ return r;
4273
+ }
4274
+ function envelope(v, length, version, maximum = length) {
4275
+ if (!(0, import_ethers4.isHexString)(v) || !/^0x(?:[a-fA-F0-9]{2})*$/.test(v) || (0, import_ethers4.dataLength)(v) < length || (0, import_ethers4.dataLength)(v) > maximum)
4276
+ throw new Error(`ciphertext must be ${length} bytes`);
4277
+ if (version !== void 0 && Number.parseInt(v.slice(2, 4), 16) !== version)
4278
+ throw new Error("unsupported ciphertext envelope version");
4279
+ return v;
4280
+ }
4281
+ function normalizeContext(c) {
4282
+ return {
4283
+ ...c,
4284
+ chainId: uint(c.chainId, 64, "chainId"),
4285
+ protocolAddress: (0, import_ethers4.getAddress)(c.protocolAddress),
4286
+ tokenAddress: (0, import_ethers4.getAddress)(c.tokenAddress)
4287
+ };
4288
+ }
4289
+ function checkDeadline(c, value) {
4290
+ const n = uint(value, 64, "deadline");
4291
+ if (c.now !== void 0 && n < uint(c.now, 64, "now")) throw new Error("deadline has expired");
4292
+ return n;
4293
+ }
4294
+ function normalizeSources(sources, inputCount, capacity) {
4295
+ dense(sources, "sources");
4296
+ if (inputCount < 0 || inputCount > capacity || sources.length > inputCount || (inputCount === 0 ? sources.length !== 0 : sources.length === 0))
4297
+ throw new Error("source count must be 1..inputCount, or empty for zero inputs");
4298
+ let previous = 0n;
4299
+ return sources.map((s) => {
4300
+ known(s, ["treeId", "merkleRoot"], "source");
4301
+ const treeId = uint(s.treeId, 64, "treeId"), merkleRoot = word(field(s.merkleRoot, "merkleRoot"));
4302
+ if (treeId === 0n || treeId <= previous || BigInt(merkleRoot) === 0n)
4303
+ throw new Error("sources must have positive roots and strictly ascending tree IDs");
4304
+ previous = treeId;
4305
+ return { treeId, merkleRoot };
4306
+ });
4307
+ }
4308
+ var pad = (v, n) => [
4309
+ ...v,
4310
+ ...Array(n - v.length).fill(0n)
4311
+ ];
4312
+ function normalizeDelivery(value, options = {}) {
4313
+ known(value, ["ciphertext", "clue"], "delivery");
4314
+ if (options.empty) {
4315
+ if (value.ciphertext !== "0x" || value.clue !== "0x")
4316
+ throw new Error("absent output requires an empty delivery");
4317
+ return { ciphertext: "0x", clue: "0x" };
4318
+ }
4319
+ const ciphertext = envelope(
4320
+ value.ciphertext,
4321
+ options.credit ? 402 : 160,
4322
+ options.credit ? 4 : 2,
4323
+ options.credit ? 658 : 416
4324
+ );
4325
+ const clue = envelope(value.clue, 68);
4326
+ if (clue.slice(130, 132).toLowerCase() !== "18") throw new Error("clue precision must be 24");
4327
+ return { ciphertext, clue };
4328
+ }
4329
+ var deliveriesHash = (v) => (0, import_ethers4.keccak256)(
4330
+ import_ethers4.AbiCoder.defaultAbiCoder().encode(
4331
+ [
4332
+ {
4333
+ type: "tuple[]",
4334
+ components: [
4335
+ { name: "ciphertext", type: "bytes" },
4336
+ { name: "clue", type: "bytes" }
4337
+ ]
4338
+ }
4339
+ ].map((parameter) => import_ethers4.ParamType.from(parameter)),
4340
+ [dense(v, "deliveries")]
4341
+ )
4342
+ );
4343
+ function normalizeFunding(input = {}) {
4344
+ const f = { ...EMPTY_FUNDING, ...input };
4345
+ (0, import_ethers4.getAddress)(f.payer);
4346
+ uint(f.amount, 128, "depositAmount");
4347
+ uint(f.sigNonce, 256, "sigNonce");
4348
+ uint(f.deadline, 256, "funding deadline");
4349
+ if (!(0, import_ethers4.isHexString)(f.signature) || !/^0x(?:[a-fA-F0-9]{2})*$/.test(f.signature))
4350
+ throw new Error("invalid signature bytes");
4351
+ const p = f.permit;
3932
4352
  uint(p.deadline, 256);
3933
4353
  uint(p.v, 8);
3934
4354
  for (const v of [p.r, p.s])
3935
- if (!(0, import_ethers2.isHexString)(v) || (0, import_ethers2.dataLength)(v) !== 32) throw new Error("permit r/s must be bytes32");
4355
+ if (!(0, import_ethers4.isHexString)(v) || (0, import_ethers4.dataLength)(v) !== 32) throw new Error("permit r/s must be bytes32");
3936
4356
  if (f.amount === 0n !== (BigInt(f.payer) === 0n))
3937
4357
  throw new Error("deposit amount and payer must both be zero or positive");
3938
4358
  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))
3939
4359
  throw new Error("zero funding must be entirely empty");
3940
- return { ...f, payer: (0, import_ethers2.getAddress)(f.payer) };
4360
+ return { ...f, payer: (0, import_ethers4.getAddress)(f.payer) };
3941
4361
  }
3942
4362
  function validateFundingSubmission(f, caller, now) {
3943
4363
  if (f.signature !== "0x" && now !== void 0 && uint(now, 64, "now") > f.deadline)
3944
4364
  throw new Error("funding authorization has expired");
3945
- if (f.signature === "0x" && (f.sigNonce !== 0n || f.deadline !== 0n || caller !== void 0 && f.amount > 0n && (0, import_ethers2.getAddress)(caller) !== f.payer))
4365
+ if (f.signature === "0x" && (f.sigNonce !== 0n || f.deadline !== 0n || caller !== void 0 && f.amount > 0n && (0, import_ethers4.getAddress)(caller) !== f.payer))
3946
4366
  throw new Error("direct funding requires payer caller and zero nonce/deadline");
3947
4367
  }
3948
4368
  var getEIP712Domain = (c) => ({
3949
4369
  name: "InvisibleProtocol",
3950
4370
  version: "1",
3951
4371
  chainId: uint(c.chainId, 64),
3952
- verifyingContract: (0, import_ethers2.getAddress)(c.protocolAddress)
4372
+ verifyingContract: (0, import_ethers4.getAddress)(c.protocolAddress)
3953
4373
  });
3954
4374
  var fundingFields = [
3955
4375
  { name: "requestHash", type: "bytes32" },
@@ -3975,9 +4395,9 @@ var CREATE_CREDIT_FIELDS = [
3975
4395
  ];
3976
4396
  function validateCreateCreditRequest(c, p, cs, funding = {}) {
3977
4397
  known(p, CREATE_CREDIT_FIELDS);
3978
- if ((0, import_ethers3.getAddress)(p.token) !== (0, import_ethers3.getAddress)(c.tokenAddress))
4398
+ if ((0, import_ethers5.getAddress)(p.token) !== (0, import_ethers5.getAddress)(c.tokenAddress))
3979
4399
  throw new Error("request token mismatch");
3980
- 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 = (0, import_ethers3.getAddress)(p.owner), expiry = uint(p.expiry, 64, "expiry"), deadline = checkDeadline(c, p.deadline), f = normalizeFunding(funding);
4400
+ 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 = (0, import_ethers5.getAddress)(p.owner), expiry = uint(p.expiry, 64, "expiry"), deadline = checkDeadline(c, p.deadline), f = normalizeFunding(funding);
3981
4401
  if (BigInt(creditCommitment) === 0n || creditCommitment === changeCommitment)
3982
4402
  throw new Error("zero or duplicate commitment");
3983
4403
  if (BigInt(owner) === 0n || expiry === 0n || c.now !== void 0 && expiry <= c.now)
@@ -4034,7 +4454,7 @@ function createCreditBaseInputs(c, p, cs, f = {}) {
4034
4454
  function createCreditPublicInputs(c, p, deliveries, funding = {}) {
4035
4455
  const base = createCreditBaseInputs(c, p, deliveries, funding);
4036
4456
  const digest = BigInt(
4037
- (0, import_core2.computeWalletAuthorizationDigest)({
4457
+ (0, import_core4.computeWalletAuthorizationDigest)({
4038
4458
  context: { chainId: c.chainId, protocolAddress: BigInt(c.protocolAddress) },
4039
4459
  operation: "create-credit",
4040
4460
  capacity: 10,
@@ -4050,17 +4470,17 @@ var hashContext = {
4050
4470
  };
4051
4471
  function createCreditRequestHash(p, cs, f = {}) {
4052
4472
  const r = validateCreateCreditRequest({ ...hashContext, tokenAddress: p.token }, p, cs, f);
4053
- return (0, import_ethers3.keccak256)(
4054
- import_ethers3.AbiCoder.defaultAbiCoder().encode(
4473
+ return (0, import_ethers5.keccak256)(
4474
+ import_ethers5.AbiCoder.defaultAbiCoder().encode(
4055
4475
  [
4056
4476
  { type: "bytes32" },
4057
4477
  creationTuple,
4058
4478
  { type: "bytes32" },
4059
4479
  { type: "address" },
4060
4480
  { type: "uint256" }
4061
- ].map((parameter) => import_ethers3.ParamType.from(parameter)),
4481
+ ].map((parameter) => import_ethers5.ParamType.from(parameter)),
4062
4482
  [
4063
- (0, import_ethers3.keccak256)(new TextEncoder().encode("InvisiCreateCredit")),
4483
+ (0, import_ethers5.keccak256)(new TextEncoder().encode("InvisiCreateCredit")),
4064
4484
  p,
4065
4485
  deliveriesHash(cs),
4066
4486
  r.funding.payer,
@@ -4070,7 +4490,7 @@ function createCreditRequestHash(p, cs, f = {}) {
4070
4490
  );
4071
4491
  }
4072
4492
  function encodeCreateCreditTypedData(c, p, deliveries, funding = {}) {
4073
- return (0, import_core2.walletAuthorizationTypedData)({
4493
+ return (0, import_core4.walletAuthorizationTypedData)({
4074
4494
  context: { chainId: c.chainId, protocolAddress: BigInt(c.protocolAddress) },
4075
4495
  operation: "create-credit",
4076
4496
  capacity: 10,
@@ -4097,7 +4517,7 @@ function buildCreateCreditCalldata(p) {
4097
4517
  const r = validateCreateCreditRequest(p.context, p.params, p.deliveries, p.funding);
4098
4518
  validateFundingSubmission(r.funding, p.caller, p.context.now);
4099
4519
  return {
4100
- data: new import_ethers3.Interface(invisiProtocolAbi).encodeFunctionData("createCredit", [
4520
+ data: new import_ethers5.Interface(invisiProtocolAbi).encodeFunctionData("createCredit", [
4101
4521
  encodeCreditProof(p.proof),
4102
4522
  p.params,
4103
4523
  p.deliveries,
@@ -4107,17 +4527,17 @@ function buildCreateCreditCalldata(p) {
4107
4527
  };
4108
4528
  }
4109
4529
  function encodeCreditProof(proof) {
4110
- if (!(0, import_ethers3.isHexString)(proof) || !/^0x(?:[a-fA-F0-9]{2})*$/.test(proof) || (0, import_ethers3.dataLength)(proof) === 0)
4530
+ if (!(0, import_ethers5.isHexString)(proof) || !/^0x(?:[a-fA-F0-9]{2})*$/.test(proof) || (0, import_ethers5.dataLength)(proof) === 0)
4111
4531
  throw new Error("empty or malformed Credit proof");
4112
- return import_ethers3.AbiCoder.defaultAbiCoder().encode(
4113
- ["uint8", "bytes"].map((parameter) => import_ethers3.ParamType.from(parameter)),
4532
+ return import_ethers5.AbiCoder.defaultAbiCoder().encode(
4533
+ ["uint8", "bytes"].map((parameter) => import_ethers5.ParamType.from(parameter)),
4114
4534
  [0, proof]
4115
4535
  );
4116
4536
  }
4117
4537
 
4118
4538
  // src/credit-lifecycle.ts
4119
- var import_ethers4 = require("ethers");
4120
- var import_core3 = require("@invisi-labs/core");
4539
+ var import_ethers6 = require("ethers");
4540
+ var import_core5 = require("@invisi-labs/core");
4121
4541
  var CREDIT_DRAW_CAPACITIES = [1, 12, 50, 120];
4122
4542
  function selectCreditDrawCircuit(count) {
4123
4543
  if (!Number.isInteger(count) || count < 1 || count > 120)
@@ -4142,7 +4562,7 @@ function validateCreditDrawRequest(c, p, cs) {
4142
4562
  "totalAmount",
4143
4563
  "deadline"
4144
4564
  ]);
4145
- if ((0, import_ethers4.getAddress)(p.token) !== (0, import_ethers4.getAddress)(c.tokenAddress))
4565
+ if ((0, import_ethers6.getAddress)(p.token) !== (0, import_ethers6.getAddress)(c.tokenAddress))
4146
4566
  throw new Error("request token mismatch");
4147
4567
  const ctx = normalizeContext(c), ns = notes(p.nullifiers, "nullifiers"), profile = selectCreditDrawCircuit(ns.length), sources = normalizeSources(p.sources, ns.length, profile.maxSize);
4148
4568
  for (const [key, v] of Object.entries({
@@ -4160,7 +4580,7 @@ function validateCreditDrawRequest(c, p, cs) {
4160
4580
  if (BigInt(remainderCommitments[i]) === 0n && BigInt(recoveryAmounts[i]) !== 0n)
4161
4581
  throw new Error("full draw requires zero recovery amount");
4162
4582
  }
4163
- const spender = (0, import_ethers4.getAddress)(p.spender), totalAmount = uint(p.totalAmount, profile.totalBits, "totalAmount");
4583
+ const spender = (0, import_ethers6.getAddress)(p.spender), totalAmount = uint(p.totalAmount, profile.totalBits, "totalAmount");
4164
4584
  if (BigInt(spender) === 0n || totalAmount === 0n)
4165
4585
  throw new Error("spender and total amount must be positive");
4166
4586
  if (dense(cs, "deliveries").length !== 2 * ns.length)
@@ -4211,9 +4631,9 @@ function creditDrawBaseInputs(c, p, cs) {
4211
4631
  }
4212
4632
  function validateCancelCreditRequest(c, p) {
4213
4633
  known(p, ["token", "source", "nullifier", "owner", "amount", "deadline"]);
4214
- if ((0, import_ethers4.getAddress)(p.token) !== (0, import_ethers4.getAddress)(c.tokenAddress))
4634
+ if ((0, import_ethers6.getAddress)(p.token) !== (0, import_ethers6.getAddress)(c.tokenAddress))
4215
4635
  throw new Error("request token mismatch");
4216
- const ctx = normalizeContext(c), source = normalizeSources([p.source], 1, 1)[0], nullifier = notes([p.nullifier], "nullifier")[0], owner = (0, import_ethers4.getAddress)(p.owner), amount = uint(p.amount, 126, "amount");
4636
+ const ctx = normalizeContext(c), source = normalizeSources([p.source], 1, 1)[0], nullifier = notes([p.nullifier], "nullifier")[0], owner = (0, import_ethers6.getAddress)(p.owner), amount = uint(p.amount, 126, "amount");
4217
4637
  if (BigInt(owner) === 0n || amount === 0n) throw new Error("owner and amount must be positive");
4218
4638
  return {
4219
4639
  ...ctx,
@@ -4271,10 +4691,10 @@ var hashContext2 = {
4271
4691
  };
4272
4692
  function cancelCreditRequestHash(p) {
4273
4693
  validateCancelCreditRequest({ ...hashContext2, tokenAddress: p.token }, p);
4274
- return (0, import_ethers4.keccak256)(
4275
- import_ethers4.AbiCoder.defaultAbiCoder().encode(
4276
- [{ type: "bytes32" }, cancelTuple].map((parameter) => import_ethers4.ParamType.from(parameter)),
4277
- [(0, import_ethers4.keccak256)(new TextEncoder().encode("InvisiCancelCredit")), p]
4694
+ return (0, import_ethers6.keccak256)(
4695
+ import_ethers6.AbiCoder.defaultAbiCoder().encode(
4696
+ [{ type: "bytes32" }, cancelTuple].map((parameter) => import_ethers6.ParamType.from(parameter)),
4697
+ [(0, import_ethers6.keccak256)(new TextEncoder().encode("InvisiCancelCredit")), p]
4278
4698
  )
4279
4699
  );
4280
4700
  }
@@ -4285,17 +4705,17 @@ function topUpCreditRequestHash(p, cs, f = {}) {
4285
4705
  cs,
4286
4706
  f
4287
4707
  );
4288
- return (0, import_ethers4.keccak256)(
4289
- import_ethers4.AbiCoder.defaultAbiCoder().encode(
4708
+ return (0, import_ethers6.keccak256)(
4709
+ import_ethers6.AbiCoder.defaultAbiCoder().encode(
4290
4710
  [
4291
4711
  { type: "bytes32" },
4292
4712
  topTuple,
4293
4713
  { type: "bytes32" },
4294
4714
  { type: "address" },
4295
4715
  { type: "uint256" }
4296
- ].map((parameter) => import_ethers4.ParamType.from(parameter)),
4716
+ ].map((parameter) => import_ethers6.ParamType.from(parameter)),
4297
4717
  [
4298
- (0, import_ethers4.keccak256)(new TextEncoder().encode("InvisiTopUpCredit")),
4718
+ (0, import_ethers6.keccak256)(new TextEncoder().encode("InvisiTopUpCredit")),
4299
4719
  p,
4300
4720
  deliveriesHash(cs),
4301
4721
  r.creation.funding.payer,
@@ -4305,7 +4725,7 @@ function topUpCreditRequestHash(p, cs, f = {}) {
4305
4725
  );
4306
4726
  }
4307
4727
  function authorize(c, operation, capacity, words) {
4308
- return (0, import_core3.walletAuthorizationTypedData)({
4728
+ return (0, import_core5.walletAuthorizationTypedData)({
4309
4729
  context: { chainId: c.chainId, protocolAddress: BigInt(c.protocolAddress) },
4310
4730
  operation,
4311
4731
  capacity,
@@ -4314,7 +4734,7 @@ function authorize(c, operation, capacity, words) {
4314
4734
  }
4315
4735
  function appendDigest(c, operation, capacity, words) {
4316
4736
  const digest = BigInt(
4317
- (0, import_core3.computeWalletAuthorizationDigest)({
4737
+ (0, import_core5.computeWalletAuthorizationDigest)({
4318
4738
  context: { chainId: c.chainId, protocolAddress: BigInt(c.protocolAddress) },
4319
4739
  operation,
4320
4740
  capacity,
@@ -4370,7 +4790,7 @@ function encodeTopUpCreditFundingTypedData(c, p, cs, f) {
4370
4790
  function buildCreditDrawCalldata(p) {
4371
4791
  validateCreditDrawRequest(p.context, p.params, p.deliveries);
4372
4792
  return {
4373
- data: new import_ethers4.Interface(invisiProtocolAbi).encodeFunctionData("creditDraw", [
4793
+ data: new import_ethers6.Interface(invisiProtocolAbi).encodeFunctionData("creditDraw", [
4374
4794
  encodeCreditProof(p.proof),
4375
4795
  p.params,
4376
4796
  p.deliveries
@@ -4382,7 +4802,7 @@ function buildCreditDrawCalldata(p) {
4382
4802
  function buildCancelCreditCalldata(p) {
4383
4803
  validateCancelCreditRequest(p.context, p.params);
4384
4804
  return {
4385
- data: new import_ethers4.Interface(invisiProtocolAbi).encodeFunctionData("cancelCredit", [
4805
+ data: new import_ethers6.Interface(invisiProtocolAbi).encodeFunctionData("cancelCredit", [
4386
4806
  encodeCreditProof(p.proof),
4387
4807
  p.params
4388
4808
  ])
@@ -4392,7 +4812,7 @@ function buildTopUpCreditCalldata(p) {
4392
4812
  const r = validateTopUpCreditRequest(p.context, p.params, p.deliveries, p.funding);
4393
4813
  validateFundingSubmission(r.creation.funding, p.caller, p.context.now);
4394
4814
  return {
4395
- data: new import_ethers4.Interface(invisiProtocolAbi).encodeFunctionData("topUpCredit", [
4815
+ data: new import_ethers6.Interface(invisiProtocolAbi).encodeFunctionData("topUpCredit", [
4396
4816
  encodeCreditProof(p.proof),
4397
4817
  p.params,
4398
4818
  p.deliveries,
@@ -4403,8 +4823,8 @@ function buildTopUpCreditCalldata(p) {
4403
4823
  }
4404
4824
 
4405
4825
  // src/funds.ts
4406
- var import_ethers5 = require("ethers");
4407
- var import_core4 = require("@invisi-labs/core");
4826
+ var import_ethers7 = require("ethers");
4827
+ var import_core6 = require("@invisi-labs/core");
4408
4828
  var TRANSACT_CAPACITIES = [14, 56, 112, 168];
4409
4829
  function selectTransactCapacity(inputs, outputs) {
4410
4830
  if (!Number.isInteger(inputs) || !Number.isInteger(outputs) || inputs < 0 || outputs < 0 || inputs + outputs < 1 || inputs === 0 && outputs < 2 || inputs + outputs > 168)
@@ -4413,7 +4833,7 @@ function selectTransactCapacity(inputs, outputs) {
4413
4833
  }
4414
4834
  function normalizeTransactRequest(c, p, cs, funding = {}) {
4415
4835
  const ctx = normalizeContext(c);
4416
- if ((0, import_ethers5.getAddress)(p.token) !== ctx.tokenAddress)
4836
+ if ((0, import_ethers7.getAddress)(p.token) !== ctx.tokenAddress)
4417
4837
  throw new Error("request token mismatch");
4418
4838
  known(p, [
4419
4839
  "token",
@@ -4427,7 +4847,7 @@ function normalizeTransactRequest(c, p, cs, funding = {}) {
4427
4847
  const ns = notes(p.nullifiers, "nullifiers"), os = notes(p.outputCommitments, "outputCommitments"), capacity = selectTransactCapacity(ns.length, os.length);
4428
4848
  const sources = normalizeSources(p.sources, ns.length, capacity), deliveries = dense(cs, "deliveries").map((v) => normalizeDelivery(v));
4429
4849
  if (deliveries.length !== os.length) throw new Error("deliveries count mismatch");
4430
- const withdrawalAmount = uint(p.withdrawalAmount, 128, "withdrawalAmount"), withdrawalAddress = (0, import_ethers5.getAddress)(p.withdrawalAddress), f = normalizeFunding(funding);
4850
+ const withdrawalAmount = uint(p.withdrawalAmount, 128, "withdrawalAmount"), withdrawalAddress = (0, import_ethers7.getAddress)(p.withdrawalAddress), f = normalizeFunding(funding);
4431
4851
  if (withdrawalAmount === 0n !== (BigInt(withdrawalAddress) === 0n) || os.length === 0 && withdrawalAmount === 0n)
4432
4852
  throw new Error("invalid withdrawal");
4433
4853
  if (ns.length === 0 && (f.amount === 0n || withdrawalAmount !== 0n))
@@ -4483,7 +4903,7 @@ function transactPublicInputs(c, p, cs, f = {}) {
4483
4903
  }
4484
4904
  function encodeTransactTypedData(c, p, deliveries, f = {}) {
4485
4905
  const r = normalizeTransactRequest(c, p, deliveries, f);
4486
- return (0, import_core4.walletAuthorizationTypedData)({
4906
+ return (0, import_core6.walletAuthorizationTypedData)({
4487
4907
  context: { chainId: r.chainId, protocolAddress: BigInt(r.protocolAddress) },
4488
4908
  operation: "transact",
4489
4909
  capacity: r.capacity,
@@ -4507,24 +4927,24 @@ function transactFundingRequestHash(proof, p, cs) {
4507
4927
  withdrawalAmount: p.withdrawalAmount,
4508
4928
  deadline: p.deadline
4509
4929
  };
4510
- return p.sources.length > 1 ? (0, import_ethers5.keccak256)(
4511
- import_ethers5.AbiCoder.defaultAbiCoder().encode(
4930
+ return p.sources.length > 1 ? (0, import_ethers7.keccak256)(
4931
+ import_ethers7.AbiCoder.defaultAbiCoder().encode(
4512
4932
  [{ type: "bytes32" }, { type: "bytes32" }, crossTuple, { type: "bytes32" }].map(
4513
- (parameter) => import_ethers5.ParamType.from(parameter)
4933
+ (parameter) => import_ethers7.ParamType.from(parameter)
4514
4934
  ),
4515
4935
  [
4516
- (0, import_ethers5.keccak256)(new TextEncoder().encode("InvisiCrossTreeTransact")),
4517
- (0, import_ethers5.keccak256)(proof),
4936
+ (0, import_ethers7.keccak256)(new TextEncoder().encode("InvisiCrossTreeTransact")),
4937
+ (0, import_ethers7.keccak256)(proof),
4518
4938
  p,
4519
4939
  deliveriesHash(cs)
4520
4940
  ]
4521
4941
  )
4522
- ) : (0, import_ethers5.keccak256)(
4523
- import_ethers5.AbiCoder.defaultAbiCoder().encode(
4942
+ ) : (0, import_ethers7.keccak256)(
4943
+ import_ethers7.AbiCoder.defaultAbiCoder().encode(
4524
4944
  [{ type: "bytes32" }, singleTuple, { type: "bytes32" }].map(
4525
- (parameter) => import_ethers5.ParamType.from(parameter)
4945
+ (parameter) => import_ethers7.ParamType.from(parameter)
4526
4946
  ),
4527
- [(0, import_ethers5.keccak256)(proof), single, deliveriesHash(cs)]
4947
+ [(0, import_ethers7.keccak256)(proof), single, deliveriesHash(cs)]
4528
4948
  )
4529
4949
  );
4530
4950
  }
@@ -4564,7 +4984,7 @@ function buildTransactCalldata(p) {
4564
4984
  const abi = invisiProtocolAbi.filter(
4565
4985
  (item) => item.type === "function" && item.name === "transact" && item.inputs.length === 2 && item.inputs[1]?.type === "tuple"
4566
4986
  );
4567
- const data = new import_ethers5.Interface(abi).encodeFunctionData("transact", [p.proof, request]);
4987
+ const data = new import_ethers7.Interface(abi).encodeFunctionData("transact", [p.proof, request]);
4568
4988
  return { data, capacity: r.capacity, approveAmount: r.depositAmount };
4569
4989
  }
4570
4990
  function buildTransactAggregateCalldata(p) {
@@ -4581,7 +5001,7 @@ function buildTransactAggregateCalldata(p) {
4581
5001
  validateFundingSubmission(r.funding, p.caller, p.context.now);
4582
5002
  }
4583
5003
  return {
4584
- data: new import_ethers5.Interface(
5004
+ data: new import_ethers7.Interface(
4585
5005
  invisiProtocolAbi.filter(
4586
5006
  (item) => item.type === "function" && item.name === "transact" && item.inputs[1]?.type === "tuple[]"
4587
5007
  )
@@ -4591,7 +5011,7 @@ function buildTransactAggregateCalldata(p) {
4591
5011
  }
4592
5012
  async function validateShieldRequest(p) {
4593
5013
  normalizeContext(p.context);
4594
- if ((0, import_ethers5.getAddress)(p.params.token) !== (0, import_ethers5.getAddress)(p.context.tokenAddress))
5014
+ if ((0, import_ethers7.getAddress)(p.params.token) !== (0, import_ethers7.getAddress)(p.context.tokenAddress))
4595
5015
  throw new Error("request token mismatch");
4596
5016
  known(p.params, ["token", "outputCommitments", "deadline"]);
4597
5017
  checkDeadline(p.context, p.params.deadline);
@@ -4605,7 +5025,7 @@ async function validateShieldRequest(p) {
4605
5025
  if (o.amount === 0n) throw new Error("amount must be positive");
4606
5026
  field(o.identity);
4607
5027
  normalizeDelivery(cs[i]);
4608
- if (await (0, import_core4.computeNoteCommitment)(
5028
+ if (await (0, import_core6.computeNoteCommitment)(
4609
5029
  p.context.chainId,
4610
5030
  o.identity,
4611
5031
  BigInt(p.context.tokenAddress),
@@ -4618,22 +5038,22 @@ async function validateShieldRequest(p) {
4618
5038
  return f;
4619
5039
  }
4620
5040
  function shieldFundingRequestHash(params, outputs, cs) {
4621
- const outputHash = (0, import_ethers5.keccak256)(
4622
- import_ethers5.AbiCoder.defaultAbiCoder().encode(
4623
- ["(bytes32 identity,uint256 amount)[]"].map((parameter) => import_ethers5.ParamType.from(parameter)),
5041
+ const outputHash = (0, import_ethers7.keccak256)(
5042
+ import_ethers7.AbiCoder.defaultAbiCoder().encode(
5043
+ ["(bytes32 identity,uint256 amount)[]"].map((parameter) => import_ethers7.ParamType.from(parameter)),
4624
5044
  [outputs]
4625
5045
  )
4626
5046
  );
4627
- return (0, import_ethers5.keccak256)(
4628
- import_ethers5.AbiCoder.defaultAbiCoder().encode(
5047
+ return (0, import_ethers7.keccak256)(
5048
+ import_ethers7.AbiCoder.defaultAbiCoder().encode(
4629
5049
  [
4630
5050
  "bytes32",
4631
5051
  "(address token,bytes32[] outputCommitments,uint256 deadline)",
4632
5052
  "bytes32",
4633
5053
  "bytes32"
4634
- ].map((parameter) => import_ethers5.ParamType.from(parameter)),
5054
+ ].map((parameter) => import_ethers7.ParamType.from(parameter)),
4635
5055
  [
4636
- (0, import_ethers5.keccak256)(new TextEncoder().encode("InvisiShield")),
5056
+ (0, import_ethers7.keccak256)(new TextEncoder().encode("InvisiShield")),
4637
5057
  params,
4638
5058
  outputHash,
4639
5059
  deliveriesHash(cs)
@@ -4660,7 +5080,7 @@ async function buildShieldCalldata(p) {
4660
5080
  const f = await validateShieldRequest(p);
4661
5081
  validateFundingSubmission(f, p.caller, p.context.now);
4662
5082
  return {
4663
- data: new import_ethers5.Interface(invisiProtocolAbi).encodeFunctionData("shield", [
5083
+ data: new import_ethers7.Interface(invisiProtocolAbi).encodeFunctionData("shield", [
4664
5084
  p.params,
4665
5085
  p.outputs,
4666
5086
  p.deliveries,
@@ -4671,7 +5091,7 @@ async function buildShieldCalldata(p) {
4671
5091
  }
4672
5092
  function transactUserPublicInputs(c, p, cs, f = {}) {
4673
5093
  const words = transactPublicInputs(c, p, cs, f), digest = BigInt(
4674
- ((typed) => import_ethers5.TypedDataEncoder.hash(
5094
+ ((typed) => import_ethers7.TypedDataEncoder.hash(
4675
5095
  typed.domain,
4676
5096
  Object.fromEntries(
4677
5097
  Object.entries(typed.types).map(([name, fields]) => [
@@ -4690,11 +5110,11 @@ function aggregateMemberRequestHash(c, r) {
4690
5110
  r.params.outputCommitments.length
4691
5111
  );
4692
5112
  if (capacity !== 14) throw new Error("aggregate supports only capacity 14");
4693
- return (0, import_ethers5.keccak256)(
4694
- import_ethers5.AbiCoder.defaultAbiCoder().encode(
4695
- ["bytes32", "uint256", "bytes32[]"].map((parameter) => import_ethers5.ParamType.from(parameter)),
5113
+ return (0, import_ethers7.keccak256)(
5114
+ import_ethers7.AbiCoder.defaultAbiCoder().encode(
5115
+ ["bytes32", "uint256", "bytes32[]"].map((parameter) => import_ethers7.ParamType.from(parameter)),
4696
5116
  [
4697
- (0, import_ethers5.keccak256)(new TextEncoder().encode("InvisiAtomicBatchMemberV1")),
5117
+ (0, import_ethers7.keccak256)(new TextEncoder().encode("InvisiAtomicBatchMemberV1")),
4698
5118
  BigInt(capacity),
4699
5119
  transactPublicInputs(c, r.params, r.deliveries, r.funding)
4700
5120
  ]
@@ -4727,6 +5147,240 @@ function encodeAggregateFundingTypedData(c, r) {
4727
5147
  };
4728
5148
  }
4729
5149
 
5150
+ // src/Protocol.ts
5151
+ var import_ethers9 = require("ethers");
5152
+ var import_rpc = require("@invisi-labs/rpc");
5153
+
5154
+ // src/TokenProtocol.ts
5155
+ var import_ethers8 = require("ethers");
5156
+ var import_core7 = require("@invisi-labs/core");
5157
+ var TokenProtocol = class {
5158
+ context;
5159
+ expectedRuntimeCodeHash;
5160
+ constructor(context, options = {}) {
5161
+ const normalized = normalizeContext(context);
5162
+ if (BigInt(normalized.protocolAddress) === 0n || BigInt(normalized.tokenAddress) === 0n) {
5163
+ throw new Error("deployment addresses must be nonzero");
5164
+ }
5165
+ if (options.expectedRuntimeCodeHash && !/^0x[0-9a-fA-F]{64}$/.test(options.expectedRuntimeCodeHash)) {
5166
+ throw new Error("invalid runtime code hash");
5167
+ }
5168
+ this.expectedRuntimeCodeHash = options.expectedRuntimeCodeHash?.toLowerCase();
5169
+ this.context = Object.freeze(normalized);
5170
+ Object.freeze(this);
5171
+ }
5172
+ async validateDeployment(reader, options = {}) {
5173
+ if ((options.requireRuntimeProfile ?? true) && !this.expectedRuntimeCodeHash) {
5174
+ throw new import_core7.MissingCapabilityError("trusted deployment profile");
5175
+ }
5176
+ if (await reader.getChainId() !== this.context.chainId) {
5177
+ throw new Error("deployment chain mismatch");
5178
+ }
5179
+ const code = await reader.getCode(this.context.protocolAddress);
5180
+ if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(code) || this.expectedRuntimeCodeHash && (0, import_ethers8.keccak256)(code) !== this.expectedRuntimeCodeHash) {
5181
+ throw new Error("deployment runtime code profile mismatch");
5182
+ }
5183
+ const tokenCode = await reader.getCode(this.context.tokenAddress);
5184
+ if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(tokenCode)) {
5185
+ throw new Error("token address must have contract code");
5186
+ }
5187
+ }
5188
+ transact(request) {
5189
+ return {
5190
+ to: this.context.protocolAddress,
5191
+ value: 0n,
5192
+ ...buildTransactCalldata({ ...request, context: this.context })
5193
+ };
5194
+ }
5195
+ aggregate(request) {
5196
+ return {
5197
+ to: this.context.protocolAddress,
5198
+ value: 0n,
5199
+ ...buildTransactAggregateCalldata({ ...request, context: this.context })
5200
+ };
5201
+ }
5202
+ async shield(request) {
5203
+ return {
5204
+ to: this.context.protocolAddress,
5205
+ value: 0n,
5206
+ ...await buildShieldCalldata({ ...request, context: this.context })
5207
+ };
5208
+ }
5209
+ createCredit(request) {
5210
+ return {
5211
+ to: this.context.protocolAddress,
5212
+ value: 0n,
5213
+ ...buildCreateCreditCalldata({ ...request, context: this.context })
5214
+ };
5215
+ }
5216
+ drawCredit(request) {
5217
+ return {
5218
+ to: this.context.protocolAddress,
5219
+ value: 0n,
5220
+ ...buildCreditDrawCalldata({ ...request, context: this.context })
5221
+ };
5222
+ }
5223
+ cancelCredit(request) {
5224
+ return {
5225
+ to: this.context.protocolAddress,
5226
+ value: 0n,
5227
+ ...buildCancelCreditCalldata({ ...request, context: this.context })
5228
+ };
5229
+ }
5230
+ topUpCredit(request) {
5231
+ return {
5232
+ to: this.context.protocolAddress,
5233
+ value: 0n,
5234
+ ...buildTopUpCreditCalldata({ ...request, context: this.context })
5235
+ };
5236
+ }
5237
+ };
5238
+
5239
+ // src/Protocol.ts
5240
+ var Protocol = class _Protocol {
5241
+ deployment;
5242
+ context;
5243
+ constructor(options) {
5244
+ known(options, ["deployment"], "protocol options");
5245
+ this.deployment = (0, import_rpc.defineDeployment)(options.deployment);
5246
+ this.context = Object.freeze({
5247
+ chainId: this.deployment.chainId,
5248
+ protocolAddress: this.deployment.protocol.address
5249
+ });
5250
+ Object.freeze(this);
5251
+ }
5252
+ /** Load the selected deployment and verify its contract against Chain RPC before returning. */
5253
+ static async fromRpc(rpc, provider, options = {}) {
5254
+ const chainId = (await provider.getNetwork()).chainId;
5255
+ if (typeof chainId !== "bigint" || chainId <= 0n || chainId >= 1n << 64n)
5256
+ throw new Error("invalid protocol chainId");
5257
+ const deployment = await rpc.getDeployment(
5258
+ chainId,
5259
+ options.signal ? { signal: options.signal } : {}
5260
+ );
5261
+ const protocol = new _Protocol({ deployment });
5262
+ if (protocol.context.chainId !== chainId) throw new Error("RPC deployment chain mismatch");
5263
+ await protocol.validateDeployment(provider);
5264
+ return protocol;
5265
+ }
5266
+ async validateDeployment(connection) {
5267
+ const reader = "getNetwork" in connection ? {
5268
+ getChainId: async () => (await connection.getNetwork()).chainId,
5269
+ getCode: async (address) => await connection.getCode(address),
5270
+ getProtocolAddressRegistry: async (address) => (0, import_ethers9.getAddress)(
5271
+ await new import_ethers9.Contract(
5272
+ address,
5273
+ ["function addressRegistry() view returns (address)"],
5274
+ connection
5275
+ ).getFunction("addressRegistry")()
5276
+ ),
5277
+ getProtocolVersion: async (address) => BigInt(
5278
+ await new import_ethers9.Contract(
5279
+ address,
5280
+ ["function VERSION() view returns (uint256)"],
5281
+ connection
5282
+ ).getFunction("VERSION")()
5283
+ )
5284
+ } : connection;
5285
+ if (await reader.getChainId() !== this.context.chainId)
5286
+ throw new Error("deployment chain mismatch");
5287
+ const code = await reader.getCode(this.context.protocolAddress);
5288
+ if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(code) || (0, import_ethers9.keccak256)(code) !== this.deployment.protocol.runtimeCodeHash)
5289
+ throw new Error("protocol runtime code profile mismatch");
5290
+ if (reader.getProtocolVersion && await reader.getProtocolVersion(this.context.protocolAddress) !== 1n)
5291
+ throw new Error("unsupported onchain protocol version");
5292
+ const registry = this.deployment.registry;
5293
+ if (registry) {
5294
+ if (!reader.getProtocolAddressRegistry)
5295
+ throw new Error("registry binding reader capability is missing");
5296
+ if ((0, import_ethers9.getAddress)(
5297
+ await reader.getProtocolAddressRegistry(this.context.protocolAddress)
5298
+ ) !== (0, import_ethers9.getAddress)(registry.address))
5299
+ throw new Error("protocol registry binding mismatch");
5300
+ const registryCode = await reader.getCode(registry.address);
5301
+ if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(registryCode) || (0, import_ethers9.keccak256)(registryCode) !== registry.runtimeCodeHash)
5302
+ throw new Error("registry runtime code profile mismatch");
5303
+ }
5304
+ }
5305
+ aggregate(request) {
5306
+ return {
5307
+ to: this.context.protocolAddress,
5308
+ value: 0n,
5309
+ ...buildTransactAggregateCalldata({ ...request, context: this.context })
5310
+ };
5311
+ }
5312
+ /** Build an operation context for one asset within this same deployment. */
5313
+ forToken(tokenAddress) {
5314
+ return new TokenProtocol(
5315
+ { ...this.context, tokenAddress: (0, import_ethers9.getAddress)(tokenAddress) },
5316
+ { expectedRuntimeCodeHash: this.deployment.protocol.runtimeCodeHash }
5317
+ );
5318
+ }
5319
+ };
5320
+
5321
+ // src/verify.ts
5322
+ var import_core8 = require("@invisi-labs/core");
5323
+ async function verifyNoteCommitment(params) {
5324
+ const expected = await (0, import_core8.computeNoteCommitment)(
5325
+ params.chainId,
5326
+ await (0, import_core8.computeNoteIdentity)(BigInt(params.walletIdentity), BigInt(params.nonce)),
5327
+ BigInt(params.tokenAddress),
5328
+ params.amount
5329
+ );
5330
+ return BigInt(expected) === BigInt(params.noteCommitment);
5331
+ }
5332
+ async function verifyCreditCommitment(params) {
5333
+ if (params.creditSharedKey <= 0n || params.creditSharedKey >= import_core8.FIELD_MODULUS)
5334
+ throw new RangeError("creditSharedKey must be a nonzero canonical Field");
5335
+ const expected = await (0, import_core8.computeCreditCommitment)(
5336
+ params.chainId,
5337
+ params.spenderWalletIdentity,
5338
+ params.ownerWalletIdentity,
5339
+ BigInt(params.spenderPayout),
5340
+ BigInt(params.ownerPayout),
5341
+ BigInt(params.tokenAddress),
5342
+ params.amount,
5343
+ params.nonce,
5344
+ params.expiry,
5345
+ await (0, import_core8.computeCreditSharedKeyHash)(params.creditSharedKey)
5346
+ );
5347
+ return BigInt(expected) === BigInt(params.creditCommitment);
5348
+ }
5349
+
5350
+ // src/withdrawal.ts
5351
+ var import_core9 = require("@invisi-labs/core");
5352
+ async function buildWithdrawalCalldata(p) {
5353
+ const r = normalizeTransactRequest(p.context, p.params, [], p.funding);
5354
+ if (r.outputCount !== 0 || r.depositAmount !== 0n || p.sourceNotes.length === 0 || p.sourceNotes.length !== r.inputCount) {
5355
+ throw new Error("full withdrawal requires inputs, no private outputs and no funding");
5356
+ }
5357
+ const walletIdentity = BigInt(p.sourceNotes[0].walletIdentity);
5358
+ let total = 0n;
5359
+ for (const [index, note] of p.sourceNotes.entries()) {
5360
+ if (note.chainId !== p.context.chainId || note.protocolAddress !== BigInt(p.context.protocolAddress))
5361
+ throw new Error("source note context mismatch");
5362
+ if (BigInt(note.walletIdentity) !== walletIdentity || note.tokenAddress !== BigInt(p.context.tokenAddress) || note.amount <= 0n)
5363
+ throw new Error("source note wallet/token/amount mismatch");
5364
+ const commitment = await (0, import_core9.computeNoteCommitment)(
5365
+ note.chainId,
5366
+ await (0, import_core9.computeNoteIdentity)(walletIdentity, note.nonce),
5367
+ note.tokenAddress,
5368
+ note.amount
5369
+ );
5370
+ const nullifier = await (0, import_core9.computeNoteNullifier)(note.chainId, note.nonce, commitment);
5371
+ if (nullifier.toLowerCase() !== r.nullifiers[index].toLowerCase())
5372
+ throw new Error("source note nullifier mismatch");
5373
+ total += note.amount;
5374
+ }
5375
+ if (r.withdrawalAmount !== total)
5376
+ throw new Error("withdrawal must equal the full input balance");
5377
+ return buildTransactCalldata({ ...p, deliveries: [] });
5378
+ }
5379
+
5380
+ // src/witness.ts
5381
+ var import_core10 = require("@invisi-labs/core");
5382
+ var import_prover = require("@invisi-labs/prover");
5383
+
4730
5384
  // src/witness-layouts.json
4731
5385
  var witness_layouts_default = {
4732
5386
  transact_user_slots14: {
@@ -5718,301 +6372,85 @@ var witness_layouts_default = {
5718
6372
  publicInputCount: 732,
5719
6373
  public: [
5720
6374
  {
5721
- name: "chain_id",
5722
- count: 1,
5723
- array: false
5724
- },
5725
- {
5726
- name: "protocol_address",
5727
- count: 1,
5728
- array: false
5729
- },
5730
- {
5731
- name: "token_address",
5732
- count: 1,
5733
- array: false
5734
- },
5735
- {
5736
- name: "spender_address",
5737
- count: 1,
5738
- array: false
5739
- },
5740
- {
5741
- name: "actual_count",
5742
- count: 1,
5743
- array: false
5744
- },
5745
- {
5746
- name: "source_count",
5747
- count: 1,
5748
- array: false
5749
- },
5750
- {
5751
- name: "tree_ids",
5752
- count: 120,
5753
- array: true
5754
- },
5755
- {
5756
- name: "roots",
5757
- count: 120,
5758
- array: true
5759
- },
5760
- {
5761
- name: "nullifiers",
5762
- count: 120,
5763
- array: true
5764
- },
5765
- {
5766
- name: "remainder_commitments",
5767
- count: 120,
5768
- array: true
5769
- },
5770
- {
5771
- name: "expiries",
5772
- count: 120,
5773
- array: true
5774
- },
5775
- {
5776
- name: "total_amount",
5777
- count: 1,
5778
- array: false
5779
- },
5780
- {
5781
- name: "deadline",
5782
- count: 1,
5783
- array: false
5784
- },
5785
- {
5786
- name: "delivery_hash_high",
5787
- count: 1,
5788
- array: false
5789
- },
5790
- {
5791
- name: "delivery_hash_low",
5792
- count: 1,
5793
- array: false
5794
- },
5795
- {
5796
- name: "recovery_amounts",
5797
- count: 120,
5798
- array: true
5799
- },
5800
- {
5801
- name: "auth_digest_high",
5802
- count: 1,
5803
- array: false
5804
- },
5805
- {
5806
- name: "auth_digest_low",
5807
- count: 1,
5808
- array: false
5809
- }
5810
- ],
5811
- private: [
5812
- "public_key_x",
5813
- "public_key_y",
5814
- "signature",
5815
- "spender_wallet_identity",
5816
- "owner_payouts",
5817
- "owner_wallet_identities",
5818
- "input_amounts",
5819
- "input_nonces",
5820
- "credit_shared_keys",
5821
- "leaf_indices",
5822
- "merkle_paths",
5823
- "input_source_indices",
5824
- "draw_amounts"
5825
- ]
5826
- },
5827
- credit_cancel: {
5828
- artifactSha256: "ff278a04f22d2886c9f27f7785a0b8fc317dd242fd4aa9d0d9398d18b7513daf",
5829
- keys: {
5830
- evm: "1f8a3c20cb081d6a90962556da3124919cc4e5675e59ad31562af39299da02fb"
5831
- },
5832
- publicInputCount: 11,
5833
- public: [
5834
- {
5835
- name: "chain_id",
5836
- count: 1,
5837
- array: false
5838
- },
5839
- {
5840
- name: "protocol_address",
5841
- count: 1,
5842
- array: false
5843
- },
5844
- {
5845
- name: "token_address",
5846
- count: 1,
5847
- array: false
5848
- },
5849
- {
5850
- name: "owner_address",
5851
- count: 1,
5852
- array: false
5853
- },
5854
- {
5855
- name: "tree_id",
5856
- count: 1,
5857
- array: false
5858
- },
5859
- {
5860
- name: "merkle_root",
5861
- count: 1,
5862
- array: false
5863
- },
5864
- {
5865
- name: "nullifier",
5866
- count: 1,
5867
- array: false
5868
- },
5869
- {
5870
- name: "amount",
5871
- count: 1,
5872
- array: false
5873
- },
5874
- {
5875
- name: "deadline",
5876
- count: 1,
5877
- array: false
5878
- },
5879
- {
5880
- name: "auth_digest_high",
5881
- count: 1,
5882
- array: false
5883
- },
5884
- {
5885
- name: "auth_digest_low",
5886
- count: 1,
5887
- array: false
5888
- }
5889
- ],
5890
- private: [
5891
- "public_key_x",
5892
- "public_key_y",
5893
- "signature",
5894
- "spender_payout",
5895
- "spender_wallet_identity",
5896
- "owner_wallet_identity",
5897
- "input_nonce",
5898
- "expiry",
5899
- "credit_shared_key",
5900
- "leaf_index",
5901
- "merkle_path"
5902
- ]
5903
- },
5904
- credit_top_up: {
5905
- artifactSha256: "fbe662363d9814983f7940f74369117cd6c84783945fbf527b0ed48d011b58a4",
5906
- keys: {
5907
- evm: "44436f31414497a708355426da051ee48ba63fdebcb6cfd72347c37c34c98c50"
5908
- },
5909
- publicInputCount: 50,
5910
- public: [
5911
- {
5912
- name: "chain_id",
5913
- count: 1,
5914
- array: false
5915
- },
5916
- {
5917
- name: "protocol_address",
5918
- count: 1,
5919
- array: false
5920
- },
5921
- {
5922
- name: "token_address",
5923
- count: 1,
5924
- array: false
5925
- },
5926
- {
5927
- name: "owner_address",
5928
- count: 1,
5929
- array: false
5930
- },
5931
- {
5932
- name: "actual_count",
5933
- count: 1,
5934
- array: false
5935
- },
5936
- {
5937
- name: "source_count",
5938
- count: 1,
5939
- array: false
5940
- },
5941
- {
5942
- name: "input_tree_ids",
5943
- count: 10,
5944
- array: true
5945
- },
5946
- {
5947
- name: "merkle_roots",
5948
- count: 10,
5949
- array: true
5950
- },
5951
- {
5952
- name: "nullifiers",
5953
- count: 10,
5954
- array: true
5955
- },
5956
- {
5957
- name: "credit_commitment",
6375
+ name: "chain_id",
5958
6376
  count: 1,
5959
6377
  array: false
5960
6378
  },
5961
6379
  {
5962
- name: "change_commitment",
6380
+ name: "protocol_address",
5963
6381
  count: 1,
5964
6382
  array: false
5965
6383
  },
5966
6384
  {
5967
- name: "delivery_hash_high",
6385
+ name: "token_address",
5968
6386
  count: 1,
5969
6387
  array: false
5970
6388
  },
5971
6389
  {
5972
- name: "delivery_hash_low",
6390
+ name: "spender_address",
5973
6391
  count: 1,
5974
6392
  array: false
5975
6393
  },
5976
6394
  {
5977
- name: "expiry",
6395
+ name: "actual_count",
5978
6396
  count: 1,
5979
6397
  array: false
5980
6398
  },
5981
6399
  {
5982
- name: "deadline",
6400
+ name: "source_count",
5983
6401
  count: 1,
5984
6402
  array: false
5985
6403
  },
5986
6404
  {
5987
- name: "deposit_amount",
5988
- count: 1,
5989
- array: false
6405
+ name: "tree_ids",
6406
+ count: 120,
6407
+ array: true
5990
6408
  },
5991
6409
  {
5992
- name: "deposit_payer",
5993
- count: 1,
5994
- array: false
6410
+ name: "roots",
6411
+ count: 120,
6412
+ array: true
5995
6413
  },
5996
6414
  {
5997
- name: "credit_tree_id",
6415
+ name: "nullifiers",
6416
+ count: 120,
6417
+ array: true
6418
+ },
6419
+ {
6420
+ name: "remainder_commitments",
6421
+ count: 120,
6422
+ array: true
6423
+ },
6424
+ {
6425
+ name: "expiries",
6426
+ count: 120,
6427
+ array: true
6428
+ },
6429
+ {
6430
+ name: "total_amount",
5998
6431
  count: 1,
5999
6432
  array: false
6000
6433
  },
6001
6434
  {
6002
- name: "credit_merkle_root",
6435
+ name: "deadline",
6003
6436
  count: 1,
6004
6437
  array: false
6005
6438
  },
6006
6439
  {
6007
- name: "credit_nullifier",
6440
+ name: "delivery_hash_high",
6008
6441
  count: 1,
6009
6442
  array: false
6010
6443
  },
6011
6444
  {
6012
- name: "previous_expiry",
6445
+ name: "delivery_hash_low",
6013
6446
  count: 1,
6014
6447
  array: false
6015
6448
  },
6449
+ {
6450
+ name: "recovery_amounts",
6451
+ count: 120,
6452
+ array: true
6453
+ },
6016
6454
  {
6017
6455
  name: "auth_digest_high",
6018
6456
  count: 1,
@@ -6025,1089 +6463,666 @@ var witness_layouts_default = {
6025
6463
  }
6026
6464
  ],
6027
6465
  private: [
6466
+ "public_key_x",
6467
+ "public_key_y",
6468
+ "signature",
6469
+ "spender_wallet_identity",
6470
+ "owner_payouts",
6471
+ "owner_wallet_identities",
6028
6472
  "input_amounts",
6029
6473
  "input_nonces",
6474
+ "credit_shared_keys",
6030
6475
  "leaf_indices",
6031
6476
  "merkle_paths",
6032
6477
  "input_source_indices",
6033
- "public_key_x",
6034
- "public_key_y",
6035
- "signature",
6036
- "spender_payout",
6037
- "spender_wallet_identity",
6038
- "owner_wallet_identity",
6039
- "credit_amount",
6040
- "credit_nonce",
6041
- "credit_shared_key",
6042
- "change_amount",
6043
- "change_nonce",
6044
- "previous_credit_amount",
6045
- "previous_credit_nonce",
6046
- "previous_credit_leaf_index",
6047
- "previous_credit_merkle_path"
6478
+ "draw_amounts"
6048
6479
  ]
6049
6480
  },
6050
- wallet_registration: {
6051
- artifactSha256: "65c3d429f6bc9735af3136f7c383214c2eb222cd32655791f37f7ae5dd428048",
6481
+ credit_cancel: {
6482
+ artifactSha256: "ff278a04f22d2886c9f27f7785a0b8fc317dd242fd4aa9d0d9398d18b7513daf",
6052
6483
  keys: {
6053
- evm: "b8171bdb558489c75293ee71f64c1ac534f533ae3b3f71107378e46dbd93dd48"
6484
+ evm: "1f8a3c20cb081d6a90962556da3124919cc4e5675e59ad31562af39299da02fb"
6054
6485
  },
6055
- publicInputCount: 3,
6486
+ publicInputCount: 11,
6056
6487
  public: [
6057
6488
  {
6058
- name: "wallet_identity",
6059
- count: 1,
6060
- array: false
6061
- },
6062
- {
6063
- name: "auth_digest_high",
6064
- count: 1,
6065
- array: false
6066
- },
6067
- {
6068
- name: "auth_digest_low",
6069
- count: 1,
6070
- array: false
6071
- }
6072
- ],
6073
- private: [
6074
- "public_key_x",
6075
- "public_key_y",
6076
- "signature"
6077
- ]
6078
- }
6079
- };
6080
-
6081
- // src/witness.ts
6082
- var pad2 = (values, count, zero) => {
6083
- if (values.length > count) throw new Error("witness capacity exceeded");
6084
- return [...values, ...Array.from({ length: count - values.length }, zero)];
6085
- };
6086
- var zeros = () => Array(16).fill(0n);
6087
- var zeroAuthority = () => ({
6088
- public_key_x: Array(32).fill(0),
6089
- public_key_y: Array(32).fill(0),
6090
- signature: Array(64).fill(0)
6091
- });
6092
- function check(ok, message) {
6093
- if (!ok) throw new Error(message);
6094
- }
6095
- function provingRequest(circuitName, privateInputs, expectedPublicInputs, target = "evm") {
6096
- const schema = witness_layouts_default[circuitName], key = schema.keys[target];
6097
- check(typeof key === "string", "unpublished proof target");
6098
- check(
6099
- expectedPublicInputs.length === schema.publicInputCount,
6100
- "public input order/width mismatch"
6101
- );
6102
- check(
6103
- Object.keys(privateInputs).length === schema.private.length && schema.private.every((name) => Object.hasOwn(privateInputs, name)),
6104
- "private witness schema mismatch"
6105
- );
6106
- let offset = 0;
6107
- const publicInputs = {};
6108
- for (const entry of schema.public) {
6109
- const values = expectedPublicInputs.slice(offset, offset + entry.count).map((value) => {
6110
- const n = BigInt(value);
6111
- check(n >= 0n && n < FIELD_MODULUS, "noncanonical public input");
6112
- return n;
6113
- });
6114
- publicInputs[entry.name] = entry.array ? values : values[0];
6115
- offset += entry.count;
6116
- }
6117
- check(offset === expectedPublicInputs.length, "public input layout mismatch");
6118
- return {
6119
- circuitName,
6120
- target,
6121
- artifactSha256: schema.artifactSha256,
6122
- vkSha256: key,
6123
- expectedPublicInputs: [...expectedPublicInputs],
6124
- witness: new import_prover.LocalWitness({ ...privateInputs, ...publicInputs })
6125
- };
6126
- }
6127
- var WitnessBuilder = class {
6128
- #protocol;
6129
- constructor(protocol) {
6130
- this.#protocol = protocol;
6131
- }
6132
- static statement(circuitName, expectedPublicInputs, target = "evm") {
6133
- const schema = witness_layouts_default[circuitName], key = schema.keys[target];
6134
- check(
6135
- typeof key === "string" && expectedPublicInputs.length === schema.publicInputCount,
6136
- "unpublished target or statement width mismatch"
6137
- );
6138
- return {
6139
- circuitName,
6140
- target,
6141
- artifactSha256: schema.artifactSha256,
6142
- vkSha256: key,
6143
- expectedPublicInputs: [...expectedPublicInputs]
6144
- };
6145
- }
6146
- context(note) {
6147
- const c = this.#protocol.context;
6148
- check(
6149
- note.chainId === c.chainId && note.protocolAddress === BigInt(c.protocolAddress) && note.tokenAddress === BigInt(c.tokenAddress),
6150
- "note context mismatch"
6151
- );
6152
- }
6153
- async authority(operation, capacity, words, signed, identity) {
6154
- check(!!signed, "private wallet authorization required");
6155
- const c = this.#protocol.context, request = {
6156
- context: { chainId: c.chainId, protocolAddress: BigInt(c.protocolAddress) },
6157
- operation,
6158
- capacity,
6159
- words: words.slice(0, -2).map(BigInt)
6160
- };
6161
- check(
6162
- signed.walletIdentity === identity && signed.digest === (0, import_core5.computeWalletAuthorizationDigest)(request),
6163
- "authorization statement mismatch"
6164
- );
6165
- const witness = signed.withWitness((value) => value);
6166
- check(
6167
- await (0, import_core5.verifyWalletAuthorization)(
6168
- identity,
6169
- Uint8Array.from([4, ...witness.public_key_x, ...witness.public_key_y]),
6170
- Uint8Array.from(witness.signature),
6171
- request
6172
- ),
6173
- "invalid wallet authorization"
6174
- );
6175
- return witness;
6176
- }
6177
- async membership(leaf, input, sources) {
6178
- const source = sources.findIndex((value) => value.treeId === input.treeId);
6179
- check(
6180
- source >= 0 && Number.isInteger(input.leafIndex) && input.leafIndex >= 0 && input.leafIndex < 65536 && input.path.length === 16,
6181
- "invalid membership position"
6182
- );
6183
- let root = BigInt(leaf);
6184
- for (let level = 0; level < 16; level++)
6185
- root = BigInt(
6186
- await (0, import_core5.poseidonHash)(
6187
- input.leafIndex >> level & 1 ? [input.path[level], root] : [root, input.path[level]]
6188
- )
6189
- );
6190
- check(root === BigInt(sources[source].merkleRoot), "membership root mismatch");
6191
- return source;
6192
- }
6193
- async noteLeaf(note) {
6194
- this.context(note);
6195
- return (0, import_core5.computeNoteCommitment)(
6196
- note.chainId,
6197
- await (0, import_core5.computeNoteIdentity)(BigInt(note.walletIdentity), note.nonce),
6198
- note.tokenAddress,
6199
- note.amount
6200
- );
6201
- }
6202
- async creditLeaf(note) {
6203
- this.context(note);
6204
- return (0, import_core5.computeCreditCommitment)(
6205
- note.chainId,
6206
- note.spenderWalletIdentity,
6207
- note.ownerWalletIdentity,
6208
- note.spenderPayout,
6209
- note.ownerPayout,
6210
- note.tokenAddress,
6211
- note.amount,
6212
- note.nonce,
6213
- note.expiry,
6214
- await (0, import_core5.computeCreditSharedKeyHash)(note.creditSharedKey)
6215
- );
6216
- }
6217
- async noteInputs(inputs, sources, nullifiers, identity, authority) {
6218
- check(inputs.length === nullifiers.length, "input count mismatch");
6219
- return Promise.all(
6220
- inputs.map(async (input, i) => {
6221
- check(input.note.walletIdentity === identity, "input wallet mismatch");
6222
- const leaf = await this.noteLeaf(input.note);
6223
- check(
6224
- await (0, import_core5.computeNoteNullifier)(input.note.chainId, input.note.nonce, leaf) === nullifiers[i],
6225
- "input nullifier mismatch"
6226
- );
6227
- return BigInt(await this.membership(leaf, input, sources));
6228
- })
6229
- );
6230
- }
6231
- async transact(p) {
6232
- const c = this.#protocol.context, n = normalizeTransactRequest(c, p.params, p.deliveries, p.funding), words = transactUserPublicInputs(c, p.params, p.deliveries, p.funding);
6233
- check(
6234
- p.inputs.length === n.inputCount && p.outputs.length === n.outputCount,
6235
- "note count mismatch"
6236
- );
6237
- const identity = p.inputs[0]?.note.walletIdentity;
6238
- const unsignedSweep = !!identity && !p.authorization && n.outputCount === 0 && n.depositAmount === 0n && BigInt(p.params.withdrawalAddress) === BigInt(identity);
6239
- const authority = identity && !unsignedSweep ? await this.authority("transact", n.capacity, words, p.authorization, identity) : zeroAuthority();
6240
- const sources = await this.noteInputs(
6241
- p.inputs,
6242
- p.params.sources,
6243
- p.params.nullifiers,
6244
- identity ?? "0x" + "00".repeat(32),
6245
- authority
6246
- );
6247
- for (const [i, note] of p.outputs.entries())
6248
- check(
6249
- await this.noteLeaf(note) === p.params.outputCommitments[i],
6250
- "output commitment mismatch"
6251
- );
6252
- const all = [...p.inputs.map((input) => input.note), ...p.outputs];
6253
- return provingRequest(
6254
- `transact_user_slots${n.capacity}`,
6489
+ name: "chain_id",
6490
+ count: 1,
6491
+ array: false
6492
+ },
6255
6493
  {
6256
- wallet_identity: identity ? BigInt(identity) : 0n,
6257
- ...authority,
6258
- output_wallet_identities: pad2(
6259
- [
6260
- ...p.inputs.map(() => 0n),
6261
- ...p.outputs.map((note) => BigInt(note.walletIdentity))
6262
- ],
6263
- n.capacity,
6264
- () => 0n
6265
- ),
6266
- amounts: pad2(
6267
- all.map((note) => note.amount),
6268
- n.capacity,
6269
- () => 0n
6270
- ),
6271
- nonces: pad2(
6272
- all.map((note) => note.nonce),
6273
- n.capacity,
6274
- () => 0n
6275
- ),
6276
- leaf_indices: pad2(
6277
- p.inputs.map((input) => BigInt(input.leafIndex)),
6278
- n.capacity,
6279
- () => 0n
6280
- ),
6281
- merkle_paths: pad2(
6282
- p.inputs.map((input) => [...input.path]),
6283
- n.capacity,
6284
- zeros
6285
- ),
6286
- input_source_indices: pad2(sources, n.capacity, () => 0n)
6494
+ name: "protocol_address",
6495
+ count: 1,
6496
+ array: false
6287
6497
  },
6288
- words,
6289
- p.target
6290
- );
6291
- }
6292
- async creation(p, operation, words) {
6293
- const state = (0, import_core5.normalizeCreditDeliveryState)(p.state), note = state.note;
6294
- check(
6295
- await this.creditLeaf(note) === p.params.creditCommitment && note.ownerPayout === BigInt(p.params.owner) && note.expiry === p.params.expiry,
6296
- "Credit creation mismatch"
6297
- );
6298
- const authority = await this.authority(
6299
- operation,
6300
- 10,
6301
- words,
6302
- p.authorization,
6303
- note.ownerWalletIdentity
6304
- );
6305
- const sources = await this.noteInputs(
6306
- p.inputs,
6307
- p.params.sources,
6308
- p.params.nullifiers,
6309
- note.ownerWalletIdentity,
6310
- authority
6311
- );
6312
- if (p.change)
6313
- check(
6314
- p.change.walletIdentity === note.ownerWalletIdentity && await this.noteLeaf(p.change) === p.params.changeCommitment,
6315
- "change commitment mismatch"
6316
- );
6317
- else check(BigInt(p.params.changeCommitment) === 0n, "missing change note");
6318
- return {
6319
- ...authority,
6320
- input_amounts: pad2(
6321
- p.inputs.map((input) => input.note.amount),
6322
- 10,
6323
- () => 0n
6324
- ),
6325
- input_nonces: pad2(
6326
- p.inputs.map((input) => input.note.nonce),
6327
- 10,
6328
- () => 0n
6329
- ),
6330
- leaf_indices: pad2(
6331
- p.inputs.map((input) => BigInt(input.leafIndex)),
6332
- 10,
6333
- () => 0n
6334
- ),
6335
- merkle_paths: pad2(
6336
- p.inputs.map((input) => [...input.path]),
6337
- 10,
6338
- zeros
6339
- ),
6340
- input_source_indices: pad2(sources, 10, () => 0n),
6341
- spender_payout: note.spenderPayout,
6342
- spender_wallet_identity: BigInt(note.spenderWalletIdentity),
6343
- owner_wallet_identity: BigInt(note.ownerWalletIdentity),
6344
- credit_amount: note.amount,
6345
- credit_nonce: note.nonce,
6346
- credit_shared_key: note.creditSharedKey,
6347
- change_amount: p.change?.amount ?? 0n,
6348
- change_nonce: p.change?.nonce ?? 0n
6349
- };
6350
- }
6351
- async createCredit(p) {
6352
- const words = createCreditPublicInputs(
6353
- this.#protocol.context,
6354
- p.params,
6355
- p.deliveries,
6356
- p.funding
6357
- );
6358
- return provingRequest(
6359
- "create_credit",
6360
- await this.creation(p, "create-credit", words),
6361
- words
6362
- );
6363
- }
6364
- async cancelCredit(p) {
6365
- const note = (0, import_core5.normalizeCreditDeliveryState)(p.input.state).note, leaf = await this.creditLeaf(note), c = this.#protocol.context;
6366
- check(
6367
- await (0, import_core5.computeCreditNullifier)(c.chainId, note.creditSharedKey, leaf) === p.params.nullifier && note.amount === p.params.amount && note.ownerPayout === BigInt(p.params.owner),
6368
- "Credit cancellation mismatch"
6369
- );
6370
- await this.membership(leaf, p.input, [p.params.source]);
6371
- const words = cancelCreditPublicInputs(c, p.params), authority = await this.authority(
6372
- "cancel-credit",
6373
- 1,
6374
- words,
6375
- p.authorization,
6376
- note.ownerWalletIdentity
6377
- );
6378
- return provingRequest(
6379
- "credit_cancel",
6380
6498
  {
6381
- ...authority,
6382
- spender_payout: note.spenderPayout,
6383
- spender_wallet_identity: BigInt(note.spenderWalletIdentity),
6384
- owner_wallet_identity: BigInt(note.ownerWalletIdentity),
6385
- input_nonce: note.nonce,
6386
- expiry: note.expiry,
6387
- credit_shared_key: note.creditSharedKey,
6388
- leaf_index: BigInt(p.input.leafIndex),
6389
- merkle_path: [...p.input.path]
6499
+ name: "token_address",
6500
+ count: 1,
6501
+ array: false
6390
6502
  },
6391
- words
6392
- );
6393
- }
6394
- async drawCredit(p) {
6395
- const c = this.#protocol.context, profile = selectCreditDrawCircuit(p.inputs.length), capacity = profile.maxSize;
6396
- check(
6397
- p.inputs.length === p.amounts.length && p.inputs.length === p.params.nullifiers.length,
6398
- "draw input count mismatch"
6399
- );
6400
- const notes2 = p.inputs.map((input) => (0, import_core5.normalizeCreditDeliveryState)(input.state).note), identity = notes2[0].spenderWalletIdentity;
6401
- const words = creditDrawPublicInputs(c, p.params, p.deliveries), authority = await this.authority(
6402
- "credit-draw",
6403
- capacity,
6404
- words,
6405
- p.authorization,
6406
- identity
6407
- );
6408
- const sourceIndices = await Promise.all(
6409
- notes2.map(async (note, i) => {
6410
- const leaf = await this.creditLeaf(note);
6411
- check(
6412
- 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 (0, import_core5.computeCreditNullifier)(c.chainId, note.creditSharedKey, leaf) === p.params.nullifiers[i],
6413
- "Credit draw mismatch"
6414
- );
6415
- return BigInt(await this.membership(leaf, p.inputs[i], p.params.sources));
6416
- })
6417
- );
6418
- return provingRequest(
6419
- profile.name,
6420
6503
  {
6421
- ...authority,
6422
- spender_wallet_identity: BigInt(identity),
6423
- owner_payouts: pad2(
6424
- notes2.map((note) => note.ownerPayout),
6425
- capacity,
6426
- () => 0n
6427
- ),
6428
- owner_wallet_identities: pad2(
6429
- notes2.map((note) => BigInt(note.ownerWalletIdentity)),
6430
- capacity,
6431
- () => 0n
6432
- ),
6433
- input_amounts: pad2(
6434
- notes2.map((note) => note.amount),
6435
- capacity,
6436
- () => 0n
6437
- ),
6438
- input_nonces: pad2(
6439
- notes2.map((note) => note.nonce),
6440
- capacity,
6441
- () => 0n
6442
- ),
6443
- credit_shared_keys: pad2(
6444
- notes2.map((note) => note.creditSharedKey),
6445
- capacity,
6446
- () => 0n
6447
- ),
6448
- leaf_indices: pad2(
6449
- p.inputs.map((input) => BigInt(input.leafIndex)),
6450
- capacity,
6451
- () => 0n
6452
- ),
6453
- merkle_paths: pad2(
6454
- p.inputs.map((input) => [...input.path]),
6455
- capacity,
6456
- zeros
6457
- ),
6458
- input_source_indices: pad2(sourceIndices, capacity, () => 0n),
6459
- draw_amounts: pad2(p.amounts, capacity, () => 0n)
6504
+ name: "owner_address",
6505
+ count: 1,
6506
+ array: false
6460
6507
  },
6461
- words
6462
- );
6463
- }
6464
- async topUpCredit(p) {
6465
- const c = this.#protocol.context, previous = (0, import_core5.normalizeCreditDeliveryState)(p.previous.state), next = (0, import_core5.normalizeCreditDeliveryState)(p.state), old = previous.note, note = next.note, leaf = await this.creditLeaf(old);
6466
- for (const field2 of [
6467
- "spenderWalletIdentity",
6468
- "ownerWalletIdentity",
6469
- "spenderPayout",
6470
- "ownerPayout",
6471
- "creditSharedKey"
6472
- ])
6473
- check(old[field2] === note[field2], "Credit role or payout changed");
6474
- check(
6475
- JSON.stringify(previous.ownerReceivingKeys) === JSON.stringify(next.ownerReceivingKeys) && JSON.stringify(previous.spenderReceivingKeys) === JSON.stringify(next.spenderReceivingKeys),
6476
- "Credit receiving snapshots changed"
6477
- );
6478
- check(
6479
- old.amount < note.amount && old.expiry <= note.expiry && old.expiry === p.params.previousExpiry && (c.now === void 0 || old.expiry > c.now),
6480
- "invalid Credit top-up"
6481
- );
6482
- check(
6483
- await (0, import_core5.computeCreditNullifier)(c.chainId, old.creditSharedKey, leaf) === p.params.creditNullifier,
6484
- "previous Credit nullifier mismatch"
6485
- );
6486
- await this.membership(leaf, p.previous, [p.params.creditSource]);
6487
- const words = topUpCreditPublicInputs(c, p.params, p.deliveries, p.funding), base = await this.creation({ ...p, params: p.params.creation }, "top-up-credit", words);
6488
- return provingRequest(
6489
- "credit_top_up",
6490
6508
  {
6491
- ...base,
6492
- previous_credit_amount: old.amount,
6493
- previous_credit_nonce: old.nonce,
6494
- previous_credit_leaf_index: BigInt(p.previous.leafIndex),
6495
- previous_credit_merkle_path: [...p.previous.path]
6509
+ name: "tree_id",
6510
+ count: 1,
6511
+ array: false
6512
+ },
6513
+ {
6514
+ name: "merkle_root",
6515
+ count: 1,
6516
+ array: false
6517
+ },
6518
+ {
6519
+ name: "nullifier",
6520
+ count: 1,
6521
+ array: false
6522
+ },
6523
+ {
6524
+ name: "amount",
6525
+ count: 1,
6526
+ array: false
6496
6527
  },
6497
- words
6498
- );
6499
- }
6500
- static async registration(context, registration, authorization, options) {
6501
- const request = registrationAuthorizationRequest(context, registration, options), words = registrationPublicInputs(context, registration, options);
6502
- check(
6503
- authorization.walletIdentity === registration.walletIdentity && authorization.digest === (0, import_core5.computeWalletAuthorizationDigest)(request),
6504
- "registry authorization mismatch"
6505
- );
6506
- const witness = authorization.withWitness((value) => value);
6507
- check(
6508
- await (0, import_core5.verifyWalletAuthorization)(
6509
- registration.walletIdentity,
6510
- Uint8Array.from([4, ...witness.public_key_x, ...witness.public_key_y]),
6511
- Uint8Array.from(witness.signature),
6512
- request
6513
- ),
6514
- "invalid registry authority"
6515
- );
6516
- return provingRequest("wallet_registration", { ...witness }, words);
6517
- }
6518
- };
6519
-
6520
- // src/RegistrationOperation.ts
6521
- function check2(ok, message) {
6522
- if (!ok) {
6523
- throw new Error(message);
6524
- }
6525
- }
6526
- function publicProof(bundle) {
6527
- return {
6528
- formatVersion: bundle.formatVersion,
6529
- bbVersion: bundle.bbVersion,
6530
- circuitName: bundle.circuitName,
6531
- target: bundle.target,
6532
- artifactSha256: bundle.artifactSha256,
6533
- vkSha256: bundle.vkSha256,
6534
- proofHex: bundle.proofHex,
6535
- proofSha256: bundle.proofSha256,
6536
- publicInputs: [...bundle.publicInputs]
6537
- };
6538
- }
6539
- var RegistrationOperation = class _RegistrationOperation {
6540
- #registry;
6541
- #runtime;
6542
- #plan;
6543
- #authorization;
6544
- #proof;
6545
- #hash;
6546
- #anchor;
6547
- status;
6548
- constructor(registry, runtime, plan, status, authorization, proof, hash, anchor) {
6549
- this.#registry = registry;
6550
- this.#runtime = { ...runtime };
6551
- this.#plan = structuredClone(plan);
6552
- this.status = status;
6553
- this.#authorization = authorization;
6554
- this.#proof = proof ? publicProof(proof) : void 0;
6555
- this.#hash = hash;
6556
- this.#anchor = anchor ? { ...anchor } : void 0;
6557
- Object.freeze(this);
6558
- }
6559
- static async prepare(registry, options) {
6560
- const runtime = { ...options };
6561
- const update = options.update ?? false;
6562
- check2(typeof update === "boolean", "update must be boolean");
6563
- await registry.validateDeployment(runtime.reader);
6564
- const block = await runtime.reader.getBlock(await runtime.reader.getLatestBlockNumber());
6565
- const context = { ...registry.context, now: block.timestamp };
6566
- const nonce = await runtime.reader.getRegistryNonce(
6567
- context,
6568
- runtime.wallet.walletIdentity,
6569
- block
6570
- );
6571
- check2(
6572
- typeof nonce === "bigint" && nonce >= 0n && nonce < (1n << 64n) - 1n,
6573
- "invalid or exhausted registry nonce"
6574
- );
6575
- check2(
6576
- update ? nonce > 0n : nonce === 0n,
6577
- update ? "wallet is not registered" : "wallet is already registered; prepare an update"
6578
- );
6579
- const address = import_core6.ReceivingAddress.parse(await registry.resolve(runtime.wallet.getAddress()));
6580
- const keys = address.getReceivingKeys();
6581
- const registration = {
6582
- walletIdentity: runtime.wallet.walletIdentity,
6583
- keys: {
6584
- viewingPublicKey: (0, import_ethers6.hexlify)(keys.viewingPublicKey),
6585
- clueKey: (0, import_ethers6.hexlify)(keys.clueKey)
6528
+ {
6529
+ name: "deadline",
6530
+ count: 1,
6531
+ array: false
6586
6532
  },
6587
- nonce,
6588
- deadline: options.deadline ?? block.timestamp + 300n
6589
- };
6590
- const words = registrationPublicInputs(context, registration, {
6591
- update,
6592
- expectedNonce: nonce
6593
- });
6594
- const statement = WitnessBuilder.statement("wallet_registration", words);
6595
- check2(
6596
- (await runtime.reader.getBlock(block.number)).hash === block.hash,
6597
- "canonical registry block changed while preparing"
6598
- );
6599
- return new _RegistrationOperation(
6600
- registry,
6601
- runtime,
6602
- { id: crypto.randomUUID(), context, registration, update, statement },
6603
- "prepared"
6604
- );
6605
- }
6606
- get id() {
6607
- return this.#plan.id;
6608
- }
6609
- preview() {
6610
- return {
6611
- id: this.id,
6612
- status: this.status,
6613
- chainId: this.#plan.context.chainId,
6614
- registryAddress: this.#plan.context.registryAddress,
6615
- ...structuredClone(this.#plan.registration),
6616
- update: this.#plan.update
6617
- };
6618
- }
6619
- async authorize(options = {}) {
6620
- check2(
6621
- this.status === "prepared" || this.status === "authorized",
6622
- "registry operation is not awaiting authorization"
6623
- );
6624
- options.signal?.throwIfAborted();
6625
- const provider = this.#runtime.authorization ?? this.#runtime.wallet.exportAuthorization();
6626
- const p = this.#plan;
6627
- check2(
6628
- provider.walletIdentity === p.registration.walletIdentity,
6629
- "registry wallet authorization capability mismatch"
6630
- );
6631
- const request = registrationAuthorizationRequest(p.context, p.registration, {
6632
- update: p.update,
6633
- expectedNonce: p.registration.nonce
6634
- });
6635
- const authorization = await provider.authorize(request);
6636
- check2(
6637
- authorization.walletIdentity === provider.walletIdentity && authorization.digest === (0, import_core6.computeWalletAuthorizationDigest)(request),
6638
- "registry authorization statement mismatch"
6639
- );
6640
- options.signal?.throwIfAborted();
6641
- return new _RegistrationOperation(
6642
- this.#registry,
6643
- this.#runtime,
6644
- p,
6645
- "authorized",
6646
- authorization
6647
- );
6648
- }
6649
- async prove(options = {}) {
6650
- check2(
6651
- this.status === "authorized" && this.#authorization,
6652
- "private registry authorization required"
6653
- );
6654
- const prover = this.#runtime.prover;
6655
- if (!prover) {
6656
- throw new import_core6.MissingCapabilityError("registry prover");
6657
- }
6658
- const p = this.#plan;
6659
- const request = await WitnessBuilder.registration(
6660
- p.context,
6661
- p.registration,
6662
- this.#authorization,
6663
- { update: p.update, expectedNonce: p.registration.nonce }
6664
- );
6665
- check2(
6666
- JSON.stringify({ ...request, witness: void 0 }) === JSON.stringify(p.statement),
6667
- "registry proof statement changed"
6668
- );
6669
- try {
6670
- const proof = publicProof(await prover.prove(request, options));
6671
- const expected = p.statement;
6672
- check2(
6673
- 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(
6674
- (word2, i) => word2 === expected.expectedPublicInputs[i]
6675
- ),
6676
- "registry proof release or public statement mismatch"
6677
- );
6678
- check2(/^0x(?:[a-fA-F0-9]{2})+$/.test(proof.proofHex), "malformed registry proof");
6679
- const bytes = Uint8Array.from(
6680
- proof.proofHex.slice(2).match(/../g),
6681
- (byte) => parseInt(byte, 16)
6682
- );
6683
- const hash = (0, import_ethers6.hexlify)(new Uint8Array(await crypto.subtle.digest("SHA-256", bytes))).slice(2);
6684
- check2(
6685
- hash === proof.proofSha256 && await prover.verify(publicProof(proof), structuredClone(expected), options),
6686
- "registry proof verification failed"
6687
- );
6688
- options.signal?.throwIfAborted();
6689
- return new _RegistrationOperation(
6690
- this.#registry,
6691
- this.#runtime,
6692
- p,
6693
- "ready",
6694
- void 0,
6695
- proof
6696
- );
6697
- } catch {
6698
- options.signal?.throwIfAborted();
6699
- throw new Error("registry proof generation or verification failed");
6700
- }
6701
- }
6702
- call() {
6703
- check2(this.#proof, "registry proof is missing");
6704
- const p = this.#plan;
6705
- const result = buildRegistrationCalldata(p.context, p.registration, this.#proof.proofHex, {
6706
- update: p.update,
6707
- expectedNonce: p.registration.nonce
6708
- });
6709
- return { to: result.to, data: result.callData, value: result.value };
6710
- }
6711
- async exportTransaction() {
6712
- check2(
6713
- this.#proof && this.status !== "prepared" && this.status !== "authorized",
6714
- "registry operation is not ready"
6715
- );
6716
- await this.#registry.validateDeployment(this.#runtime.reader);
6717
- const block = await this.#runtime.reader.getBlock(
6718
- await this.#runtime.reader.getLatestBlockNumber()
6719
- );
6720
- const p = this.#plan;
6721
- check2(block.timestamp <= p.registration.deadline, "registry operation has expired");
6722
- check2(
6723
- await this.#runtime.reader.getRegistryNonce(
6724
- p.context,
6725
- p.registration.walletIdentity,
6726
- block
6727
- ) === p.registration.nonce,
6728
- "registry nonce changed; prepare again"
6729
- );
6730
- return this.call();
6731
- }
6732
- /** Associate a signed/broadcast transaction; ethers owns sending and receipt waiting. */
6733
- trackTransaction(transactionHash) {
6734
- check2(/^0x[a-fA-F0-9]{64}$/.test(transactionHash), "invalid registry transaction hash");
6735
- check2(
6736
- this.#proof && ["ready", "uncertain"].includes(this.status),
6737
- "registry operation is not ready"
6738
- );
6739
- return new _RegistrationOperation(
6740
- this.#registry,
6741
- this.#runtime,
6742
- this.#plan,
6743
- "uncertain",
6744
- void 0,
6745
- this.#proof,
6746
- transactionHash
6747
- );
6748
- }
6749
- async reconcile(options = {}) {
6750
- options.signal?.throwIfAborted();
6751
- const { reader } = this.#runtime;
6752
- const p = this.#plan;
6753
- await this.#registry.validateDeployment(reader);
6754
- if (this.#anchor && (await reader.getBlock(this.#anchor.number)).hash !== this.#anchor.hash) {
6755
- return new _RegistrationOperation(
6756
- this.#registry,
6757
- this.#runtime,
6758
- p,
6759
- "reorged",
6760
- void 0,
6761
- this.#proof,
6762
- this.#hash
6763
- );
6764
- }
6765
- const hash = options.transactionHash ?? this.#hash;
6766
- const receipt = hash ? await reader.getReceipt(hash) : null;
6767
- if (receipt) {
6768
- check2(
6769
- receipt.transactionHash === hash && (await reader.getBlock(receipt.block.number)).hash === receipt.block.hash,
6770
- "registry receipt is not canonical"
6771
- );
6772
- const transaction = await reader.getTransaction(hash);
6773
- const call = this.call();
6774
- check2(
6775
- transaction && transaction.transactionHash === hash && transaction.to.toLowerCase() === call.to.toLowerCase() && transaction.data.toLowerCase() === call.data.toLowerCase() && transaction.value === 0n,
6776
- "registry transaction differs from frozen request"
6777
- );
6778
- check2(
6779
- receipt.status === "success" || receipt.status === "reverted",
6780
- "registry execution status is missing"
6781
- );
6782
- if (receipt.status === "success") {
6783
- const found = receipt.logs.some((log) => {
6784
- if (log.address.toLowerCase() !== p.context.registryAddress.toLowerCase() || log.transactionHash !== hash) {
6785
- return false;
6786
- }
6787
- try {
6788
- const event = ((decoded) => ({
6789
- eventName: decoded.name,
6790
- args: decoded.args.toObject()
6791
- }))(
6792
- new import_ethers6.Interface(invisiAddressRegistryAbi).parseLog({
6793
- data: log.data,
6794
- topics: log.topics
6795
- })
6796
- );
6797
- 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;
6798
- } catch {
6799
- return false;
6800
- }
6801
- });
6802
- check2(found, "registry receipt has no matching key update event");
6803
- check2(
6804
- (await reader.getBlock(receipt.block.number)).hash === receipt.block.hash,
6805
- "registry block changed during confirmation"
6806
- );
6807
- options.signal?.throwIfAborted();
6808
- return new _RegistrationOperation(
6809
- this.#registry,
6810
- this.#runtime,
6811
- p,
6812
- "confirmed",
6813
- void 0,
6814
- this.#proof,
6815
- hash,
6816
- receipt.block
6817
- );
6533
+ {
6534
+ name: "auth_digest_high",
6535
+ count: 1,
6536
+ array: false
6537
+ },
6538
+ {
6539
+ name: "auth_digest_low",
6540
+ count: 1,
6541
+ array: false
6542
+ }
6543
+ ],
6544
+ private: [
6545
+ "public_key_x",
6546
+ "public_key_y",
6547
+ "signature",
6548
+ "spender_payout",
6549
+ "spender_wallet_identity",
6550
+ "owner_wallet_identity",
6551
+ "input_nonce",
6552
+ "expiry",
6553
+ "credit_shared_key",
6554
+ "leaf_index",
6555
+ "merkle_path"
6556
+ ]
6557
+ },
6558
+ credit_top_up: {
6559
+ artifactSha256: "fbe662363d9814983f7940f74369117cd6c84783945fbf527b0ed48d011b58a4",
6560
+ keys: {
6561
+ evm: "44436f31414497a708355426da051ee48ba63fdebcb6cfd72347c37c34c98c50"
6562
+ },
6563
+ publicInputCount: 50,
6564
+ public: [
6565
+ {
6566
+ name: "chain_id",
6567
+ count: 1,
6568
+ array: false
6569
+ },
6570
+ {
6571
+ name: "protocol_address",
6572
+ count: 1,
6573
+ array: false
6574
+ },
6575
+ {
6576
+ name: "token_address",
6577
+ count: 1,
6578
+ array: false
6579
+ },
6580
+ {
6581
+ name: "owner_address",
6582
+ count: 1,
6583
+ array: false
6584
+ },
6585
+ {
6586
+ name: "actual_count",
6587
+ count: 1,
6588
+ array: false
6589
+ },
6590
+ {
6591
+ name: "source_count",
6592
+ count: 1,
6593
+ array: false
6594
+ },
6595
+ {
6596
+ name: "input_tree_ids",
6597
+ count: 10,
6598
+ array: true
6599
+ },
6600
+ {
6601
+ name: "merkle_roots",
6602
+ count: 10,
6603
+ array: true
6604
+ },
6605
+ {
6606
+ name: "nullifiers",
6607
+ count: 10,
6608
+ array: true
6609
+ },
6610
+ {
6611
+ name: "credit_commitment",
6612
+ count: 1,
6613
+ array: false
6614
+ },
6615
+ {
6616
+ name: "change_commitment",
6617
+ count: 1,
6618
+ array: false
6619
+ },
6620
+ {
6621
+ name: "delivery_hash_high",
6622
+ count: 1,
6623
+ array: false
6624
+ },
6625
+ {
6626
+ name: "delivery_hash_low",
6627
+ count: 1,
6628
+ array: false
6629
+ },
6630
+ {
6631
+ name: "expiry",
6632
+ count: 1,
6633
+ array: false
6634
+ },
6635
+ {
6636
+ name: "deadline",
6637
+ count: 1,
6638
+ array: false
6639
+ },
6640
+ {
6641
+ name: "deposit_amount",
6642
+ count: 1,
6643
+ array: false
6644
+ },
6645
+ {
6646
+ name: "deposit_payer",
6647
+ count: 1,
6648
+ array: false
6649
+ },
6650
+ {
6651
+ name: "credit_tree_id",
6652
+ count: 1,
6653
+ array: false
6654
+ },
6655
+ {
6656
+ name: "credit_merkle_root",
6657
+ count: 1,
6658
+ array: false
6659
+ },
6660
+ {
6661
+ name: "credit_nullifier",
6662
+ count: 1,
6663
+ array: false
6664
+ },
6665
+ {
6666
+ name: "previous_expiry",
6667
+ count: 1,
6668
+ array: false
6669
+ },
6670
+ {
6671
+ name: "auth_digest_high",
6672
+ count: 1,
6673
+ array: false
6674
+ },
6675
+ {
6676
+ name: "auth_digest_low",
6677
+ count: 1,
6678
+ array: false
6818
6679
  }
6819
- }
6820
- const head = await reader.getBlock(await reader.getLatestBlockNumber());
6821
- const nonce = await reader.getRegistryNonce(p.context, p.registration.walletIdentity, head);
6822
- check2(
6823
- (await reader.getBlock(head.number)).hash === head.hash,
6824
- "canonical registry block changed during reconciliation"
6825
- );
6826
- return new _RegistrationOperation(
6827
- this.#registry,
6828
- this.#runtime,
6829
- p,
6830
- head.timestamp > p.registration.deadline ? "expired" : nonce !== p.registration.nonce ? "failed" : "uncertain",
6831
- void 0,
6832
- this.#proof,
6833
- hash
6834
- );
6835
- }
6836
- toJSON() {
6837
- return {
6838
- id: this.id,
6839
- kind: this.#plan.update ? "update-address" : "register-address",
6840
- status: this.status
6841
- };
6842
- }
6843
- [/* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom")]() {
6844
- return this.toJSON();
6845
- }
6846
- };
6847
-
6848
- // src/AddressRegistry.ts
6849
- var AddressRegistry = class {
6850
- context;
6851
- #lookup;
6852
- expectedRuntimeCodeHash;
6853
- constructor(context, options = {}) {
6854
- if (typeof context.chainId !== "bigint" || context.chainId < 0n || context.chainId >= 1n << 64n || BigInt((0, import_ethers7.getAddress)(context.registryAddress)) === 0n) {
6855
- throw new Error("invalid registry context");
6856
- }
6857
- this.context = Object.freeze({
6858
- ...context,
6859
- registryAddress: (0, import_ethers7.getAddress)(context.registryAddress)
6860
- });
6861
- this.#lookup = options.lookup;
6862
- this.expectedRuntimeCodeHash = options.expectedRuntimeCodeHash?.toLowerCase();
6863
- if (this.expectedRuntimeCodeHash && !/^0x[0-9a-f]{64}$/.test(this.expectedRuntimeCodeHash)) {
6864
- throw new Error("invalid registry runtime profile");
6865
- }
6866
- Object.freeze(this);
6867
- }
6868
- async validateDeployment(reader) {
6869
- if (!this.expectedRuntimeCodeHash) {
6870
- throw new import_core7.MissingCapabilityError("trusted registry deployment profile");
6871
- }
6872
- if (await reader.getChainId() !== this.context.chainId) {
6873
- throw new Error("registry chain mismatch");
6874
- }
6875
- const code = await reader.getCode(this.context.registryAddress);
6876
- if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(code) || (0, import_ethers7.keccak256)(code) !== this.expectedRuntimeCodeHash) {
6877
- throw new Error("registry runtime profile mismatch");
6878
- }
6879
- }
6880
- prepareRegistration(options) {
6881
- return RegistrationOperation.prepare(this, options);
6882
- }
6883
- async resolve(address) {
6884
- const receiving = import_core7.ReceivingAddress.parse(address);
6885
- if (receiving.kind === "short" && !this.#lookup) {
6886
- throw new import_core7.MissingCapabilityError("registry reader");
6887
- }
6888
- return (await receiving.resolve(this.#lookup)).toString();
6889
- }
6890
- authorization(registration, options) {
6891
- return registrationAuthorizationRequest(this.context, registration, options);
6892
- }
6893
- publicInputs(registration, options) {
6894
- return registrationPublicInputs(this.context, registration, options);
6895
- }
6896
- buildCall(registration, proof, options) {
6897
- return buildRegistrationCalldata(this.context, registration, proof, options);
6898
- }
6899
- };
6900
-
6901
- // src/Protocol.ts
6902
- var import_ethers9 = require("ethers");
6903
- var import_rpc = require("@invisi-labs/rpc");
6904
-
6905
- // src/TokenProtocol.ts
6906
- var import_ethers8 = require("ethers");
6907
- var import_core8 = require("@invisi-labs/core");
6908
- var TokenProtocol = class {
6909
- context;
6910
- expectedRuntimeCodeHash;
6911
- constructor(context, options = {}) {
6912
- const normalized = normalizeContext(context);
6913
- if (BigInt(normalized.protocolAddress) === 0n || BigInt(normalized.tokenAddress) === 0n) {
6914
- throw new Error("deployment addresses must be nonzero");
6915
- }
6916
- if (options.expectedRuntimeCodeHash && !/^0x[0-9a-fA-F]{64}$/.test(options.expectedRuntimeCodeHash)) {
6917
- throw new Error("invalid runtime code hash");
6918
- }
6919
- this.expectedRuntimeCodeHash = options.expectedRuntimeCodeHash?.toLowerCase();
6920
- this.context = Object.freeze(normalized);
6921
- Object.freeze(this);
6922
- }
6923
- async validateDeployment(reader, options = {}) {
6924
- if ((options.requireRuntimeProfile ?? true) && !this.expectedRuntimeCodeHash) {
6925
- throw new import_core8.MissingCapabilityError("trusted deployment profile");
6926
- }
6927
- if (await reader.getChainId() !== this.context.chainId) {
6928
- throw new Error("deployment chain mismatch");
6929
- }
6930
- const code = await reader.getCode(this.context.protocolAddress);
6931
- if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(code) || this.expectedRuntimeCodeHash && (0, import_ethers8.keccak256)(code) !== this.expectedRuntimeCodeHash) {
6932
- throw new Error("deployment runtime code profile mismatch");
6933
- }
6934
- const tokenCode = await reader.getCode(this.context.tokenAddress);
6935
- if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(tokenCode)) {
6936
- throw new Error("token address must have contract code");
6937
- }
6938
- }
6939
- transact(request) {
6940
- return {
6941
- to: this.context.protocolAddress,
6942
- value: 0n,
6943
- ...buildTransactCalldata({ ...request, context: this.context })
6944
- };
6680
+ ],
6681
+ private: [
6682
+ "input_amounts",
6683
+ "input_nonces",
6684
+ "leaf_indices",
6685
+ "merkle_paths",
6686
+ "input_source_indices",
6687
+ "public_key_x",
6688
+ "public_key_y",
6689
+ "signature",
6690
+ "spender_payout",
6691
+ "spender_wallet_identity",
6692
+ "owner_wallet_identity",
6693
+ "credit_amount",
6694
+ "credit_nonce",
6695
+ "credit_shared_key",
6696
+ "change_amount",
6697
+ "change_nonce",
6698
+ "previous_credit_amount",
6699
+ "previous_credit_nonce",
6700
+ "previous_credit_leaf_index",
6701
+ "previous_credit_merkle_path"
6702
+ ]
6945
6703
  }
6946
- aggregate(request) {
6947
- return {
6948
- to: this.context.protocolAddress,
6949
- value: 0n,
6950
- ...buildTransactAggregateCalldata({ ...request, context: this.context })
6951
- };
6704
+ };
6705
+
6706
+ // src/witness.ts
6707
+ var pad2 = (values, count, zero) => {
6708
+ if (values.length > count) throw new Error("witness capacity exceeded");
6709
+ return [...values, ...Array.from({ length: count - values.length }, zero)];
6710
+ };
6711
+ var zeros = () => Array(16).fill(0n);
6712
+ var zeroAuthority = () => ({
6713
+ public_key_x: Array(32).fill(0),
6714
+ public_key_y: Array(32).fill(0),
6715
+ signature: Array(64).fill(0)
6716
+ });
6717
+ function check2(ok, message) {
6718
+ if (!ok) throw new Error(message);
6719
+ }
6720
+ function provingRequest(circuitName, privateInputs, expectedPublicInputs, target = "evm") {
6721
+ const schema = witness_layouts_default[circuitName], key = schema.keys[target];
6722
+ check2(typeof key === "string", "unpublished proof target");
6723
+ check2(
6724
+ expectedPublicInputs.length === schema.publicInputCount,
6725
+ "public input order/width mismatch"
6726
+ );
6727
+ check2(
6728
+ Object.keys(privateInputs).length === schema.private.length && schema.private.every((name) => Object.hasOwn(privateInputs, name)),
6729
+ "private witness schema mismatch"
6730
+ );
6731
+ let offset = 0;
6732
+ const publicInputs = {};
6733
+ for (const entry of schema.public) {
6734
+ const values = expectedPublicInputs.slice(offset, offset + entry.count).map((value) => {
6735
+ const n = BigInt(value);
6736
+ check2(n >= 0n && n < FIELD_MODULUS, "noncanonical public input");
6737
+ return n;
6738
+ });
6739
+ publicInputs[entry.name] = entry.array ? values : values[0];
6740
+ offset += entry.count;
6952
6741
  }
6953
- async shield(request) {
6954
- return {
6955
- to: this.context.protocolAddress,
6956
- value: 0n,
6957
- ...await buildShieldCalldata({ ...request, context: this.context })
6958
- };
6742
+ check2(offset === expectedPublicInputs.length, "public input layout mismatch");
6743
+ return {
6744
+ circuitName,
6745
+ target,
6746
+ artifactSha256: schema.artifactSha256,
6747
+ vkSha256: key,
6748
+ expectedPublicInputs: [...expectedPublicInputs],
6749
+ witness: new import_prover.LocalWitness({ ...privateInputs, ...publicInputs })
6750
+ };
6751
+ }
6752
+ var WitnessBuilder = class {
6753
+ #protocol;
6754
+ constructor(protocol) {
6755
+ this.#protocol = protocol;
6959
6756
  }
6960
- createCredit(request) {
6757
+ static statement(circuitName, expectedPublicInputs, target = "evm") {
6758
+ const schema = witness_layouts_default[circuitName], key = schema.keys[target];
6759
+ check2(
6760
+ typeof key === "string" && expectedPublicInputs.length === schema.publicInputCount,
6761
+ "unpublished target or statement width mismatch"
6762
+ );
6961
6763
  return {
6962
- to: this.context.protocolAddress,
6963
- value: 0n,
6964
- ...buildCreateCreditCalldata({ ...request, context: this.context })
6764
+ circuitName,
6765
+ target,
6766
+ artifactSha256: schema.artifactSha256,
6767
+ vkSha256: key,
6768
+ expectedPublicInputs: [...expectedPublicInputs]
6965
6769
  };
6966
6770
  }
6967
- drawCredit(request) {
6968
- return {
6969
- to: this.context.protocolAddress,
6970
- value: 0n,
6971
- ...buildCreditDrawCalldata({ ...request, context: this.context })
6972
- };
6771
+ context(note) {
6772
+ const c = this.#protocol.context;
6773
+ check2(
6774
+ note.chainId === c.chainId && note.protocolAddress === BigInt(c.protocolAddress) && note.tokenAddress === BigInt(c.tokenAddress),
6775
+ "note context mismatch"
6776
+ );
6973
6777
  }
6974
- cancelCredit(request) {
6975
- return {
6976
- to: this.context.protocolAddress,
6977
- value: 0n,
6978
- ...buildCancelCreditCalldata({ ...request, context: this.context })
6778
+ async authority(operation, capacity, words, signed, identity) {
6779
+ check2(!!signed, "private wallet authorization required");
6780
+ const c = this.#protocol.context, request = {
6781
+ context: { chainId: c.chainId, protocolAddress: BigInt(c.protocolAddress) },
6782
+ operation,
6783
+ capacity,
6784
+ words: words.slice(0, -2).map(BigInt)
6979
6785
  };
6786
+ check2(
6787
+ signed.walletIdentity === identity && signed.digest === (0, import_core10.computeWalletAuthorizationDigest)(request),
6788
+ "authorization statement mismatch"
6789
+ );
6790
+ const witness = signed.withWitness((value) => value);
6791
+ check2(
6792
+ await (0, import_core10.verifyWalletAuthorization)(
6793
+ identity,
6794
+ Uint8Array.from([4, ...witness.public_key_x, ...witness.public_key_y]),
6795
+ Uint8Array.from(witness.signature),
6796
+ request
6797
+ ),
6798
+ "invalid wallet authorization"
6799
+ );
6800
+ return witness;
6980
6801
  }
6981
- topUpCredit(request) {
6982
- return {
6983
- to: this.context.protocolAddress,
6984
- value: 0n,
6985
- ...buildTopUpCreditCalldata({ ...request, context: this.context })
6986
- };
6802
+ async membership(leaf, input, sources) {
6803
+ const source = sources.findIndex((value) => value.treeId === input.treeId);
6804
+ check2(
6805
+ source >= 0 && Number.isInteger(input.leafIndex) && input.leafIndex >= 0 && input.leafIndex < 65536 && input.path.length === 16,
6806
+ "invalid membership position"
6807
+ );
6808
+ let root = BigInt(leaf);
6809
+ for (let level = 0; level < 16; level++)
6810
+ root = BigInt(
6811
+ await (0, import_core10.poseidonHash)(
6812
+ input.leafIndex >> level & 1 ? [input.path[level], root] : [root, input.path[level]]
6813
+ )
6814
+ );
6815
+ check2(root === BigInt(sources[source].merkleRoot), "membership root mismatch");
6816
+ return source;
6987
6817
  }
6988
- };
6989
-
6990
- // src/Protocol.ts
6991
- var Protocol = class _Protocol {
6992
- deployment;
6993
- context;
6994
- constructor(options) {
6995
- known(options, ["deployment"], "protocol options");
6996
- this.deployment = (0, import_rpc.defineDeployment)(options.deployment);
6997
- this.context = Object.freeze({
6998
- chainId: this.deployment.chainId,
6999
- protocolAddress: this.deployment.protocol.address
7000
- });
7001
- Object.freeze(this);
6818
+ async noteLeaf(note) {
6819
+ this.context(note);
6820
+ return (0, import_core10.computeNoteCommitment)(
6821
+ note.chainId,
6822
+ await (0, import_core10.computeNoteIdentity)(BigInt(note.walletIdentity), note.nonce),
6823
+ note.tokenAddress,
6824
+ note.amount
6825
+ );
7002
6826
  }
7003
- /** Load the selected deployment and verify its contract against Chain RPC before returning. */
7004
- static async fromRpc(rpc, provider, options = {}) {
7005
- const chainId = (await provider.getNetwork()).chainId;
7006
- if (typeof chainId !== "bigint" || chainId <= 0n || chainId >= 1n << 64n)
7007
- throw new Error("invalid protocol chainId");
7008
- const deployment = await rpc.getDeployment(
7009
- chainId,
7010
- options.signal ? { signal: options.signal } : {}
6827
+ async creditLeaf(note) {
6828
+ this.context(note);
6829
+ return (0, import_core10.computeCreditCommitment)(
6830
+ note.chainId,
6831
+ note.spenderWalletIdentity,
6832
+ note.ownerWalletIdentity,
6833
+ note.spenderPayout,
6834
+ note.ownerPayout,
6835
+ note.tokenAddress,
6836
+ note.amount,
6837
+ note.nonce,
6838
+ note.expiry,
6839
+ await (0, import_core10.computeCreditSharedKeyHash)(note.creditSharedKey)
7011
6840
  );
7012
- const protocol = new _Protocol({ deployment });
7013
- if (protocol.context.chainId !== chainId) throw new Error("RPC deployment chain mismatch");
7014
- await protocol.validateDeployment(provider);
7015
- return protocol;
7016
6841
  }
7017
- async validateDeployment(connection) {
7018
- const reader = "getNetwork" in connection ? {
7019
- getChainId: async () => (await connection.getNetwork()).chainId,
7020
- getCode: async (address) => await connection.getCode(address),
7021
- getProtocolVersion: async (address) => BigInt(
7022
- await new import_ethers9.Contract(
7023
- address,
7024
- ["function VERSION() view returns (uint256)"],
7025
- connection
7026
- ).getFunction("VERSION")()
7027
- )
7028
- } : connection;
7029
- if (await reader.getChainId() !== this.context.chainId)
7030
- throw new Error("deployment chain mismatch");
7031
- const code = await reader.getCode(this.context.protocolAddress);
7032
- if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(code) || (0, import_ethers9.keccak256)(code) !== this.deployment.protocol.runtimeCodeHash)
7033
- throw new Error("protocol runtime code profile mismatch");
7034
- if (reader.getProtocolVersion && await reader.getProtocolVersion(this.context.protocolAddress) !== 1n)
7035
- throw new Error("unsupported onchain protocol version");
6842
+ async noteInputs(inputs, sources, nullifiers, identity, authority) {
6843
+ check2(inputs.length === nullifiers.length, "input count mismatch");
6844
+ return Promise.all(
6845
+ inputs.map(async (input, i) => {
6846
+ check2(input.note.walletIdentity === identity, "input wallet mismatch");
6847
+ const leaf = await this.noteLeaf(input.note);
6848
+ check2(
6849
+ await (0, import_core10.computeNoteNullifier)(input.note.chainId, input.note.nonce, leaf) === nullifiers[i],
6850
+ "input nullifier mismatch"
6851
+ );
6852
+ return BigInt(await this.membership(leaf, input, sources));
6853
+ })
6854
+ );
6855
+ }
6856
+ async transact(p) {
6857
+ const c = this.#protocol.context, n = normalizeTransactRequest(c, p.params, p.deliveries, p.funding), words = transactUserPublicInputs(c, p.params, p.deliveries, p.funding);
6858
+ check2(
6859
+ p.inputs.length === n.inputCount && p.outputs.length === n.outputCount,
6860
+ "note count mismatch"
6861
+ );
6862
+ const identity = p.inputs[0]?.note.walletIdentity;
6863
+ const unsignedSweep = !!identity && !p.authorization && n.outputCount === 0 && n.depositAmount === 0n && BigInt(p.params.withdrawalAddress) === BigInt(identity);
6864
+ const authority = identity && !unsignedSweep ? await this.authority("transact", n.capacity, words, p.authorization, identity) : zeroAuthority();
6865
+ const sources = await this.noteInputs(
6866
+ p.inputs,
6867
+ p.params.sources,
6868
+ p.params.nullifiers,
6869
+ identity ?? "0x" + "00".repeat(32),
6870
+ authority
6871
+ );
6872
+ for (const [i, note] of p.outputs.entries())
6873
+ check2(
6874
+ await this.noteLeaf(note) === p.params.outputCommitments[i],
6875
+ "output commitment mismatch"
6876
+ );
6877
+ const all = [...p.inputs.map((input) => input.note), ...p.outputs];
6878
+ return provingRequest(
6879
+ `transact_user_slots${n.capacity}`,
6880
+ {
6881
+ wallet_identity: identity ? BigInt(identity) : 0n,
6882
+ ...authority,
6883
+ output_wallet_identities: pad2(
6884
+ [
6885
+ ...p.inputs.map(() => 0n),
6886
+ ...p.outputs.map((note) => BigInt(note.walletIdentity))
6887
+ ],
6888
+ n.capacity,
6889
+ () => 0n
6890
+ ),
6891
+ amounts: pad2(
6892
+ all.map((note) => note.amount),
6893
+ n.capacity,
6894
+ () => 0n
6895
+ ),
6896
+ nonces: pad2(
6897
+ all.map((note) => note.nonce),
6898
+ n.capacity,
6899
+ () => 0n
6900
+ ),
6901
+ leaf_indices: pad2(
6902
+ p.inputs.map((input) => BigInt(input.leafIndex)),
6903
+ n.capacity,
6904
+ () => 0n
6905
+ ),
6906
+ merkle_paths: pad2(
6907
+ p.inputs.map((input) => [...input.path]),
6908
+ n.capacity,
6909
+ zeros
6910
+ ),
6911
+ input_source_indices: pad2(sources, n.capacity, () => 0n)
6912
+ },
6913
+ words,
6914
+ p.target
6915
+ );
7036
6916
  }
7037
- aggregate(request) {
6917
+ async creation(p, operation, words) {
6918
+ const state = (0, import_core10.normalizeCreditDeliveryState)(p.state), note = state.note;
6919
+ check2(
6920
+ await this.creditLeaf(note) === p.params.creditCommitment && note.ownerPayout === BigInt(p.params.owner) && note.expiry === p.params.expiry,
6921
+ "Credit creation mismatch"
6922
+ );
6923
+ const authority = await this.authority(
6924
+ operation,
6925
+ 10,
6926
+ words,
6927
+ p.authorization,
6928
+ note.ownerWalletIdentity
6929
+ );
6930
+ const sources = await this.noteInputs(
6931
+ p.inputs,
6932
+ p.params.sources,
6933
+ p.params.nullifiers,
6934
+ note.ownerWalletIdentity,
6935
+ authority
6936
+ );
6937
+ if (p.change)
6938
+ check2(
6939
+ p.change.walletIdentity === note.ownerWalletIdentity && await this.noteLeaf(p.change) === p.params.changeCommitment,
6940
+ "change commitment mismatch"
6941
+ );
6942
+ else check2(BigInt(p.params.changeCommitment) === 0n, "missing change note");
7038
6943
  return {
7039
- to: this.context.protocolAddress,
7040
- value: 0n,
7041
- ...buildTransactAggregateCalldata({ ...request, context: this.context })
6944
+ ...authority,
6945
+ input_amounts: pad2(
6946
+ p.inputs.map((input) => input.note.amount),
6947
+ 10,
6948
+ () => 0n
6949
+ ),
6950
+ input_nonces: pad2(
6951
+ p.inputs.map((input) => input.note.nonce),
6952
+ 10,
6953
+ () => 0n
6954
+ ),
6955
+ leaf_indices: pad2(
6956
+ p.inputs.map((input) => BigInt(input.leafIndex)),
6957
+ 10,
6958
+ () => 0n
6959
+ ),
6960
+ merkle_paths: pad2(
6961
+ p.inputs.map((input) => [...input.path]),
6962
+ 10,
6963
+ zeros
6964
+ ),
6965
+ input_source_indices: pad2(sources, 10, () => 0n),
6966
+ spender_payout: note.spenderPayout,
6967
+ spender_wallet_identity: BigInt(note.spenderWalletIdentity),
6968
+ owner_wallet_identity: BigInt(note.ownerWalletIdentity),
6969
+ credit_amount: note.amount,
6970
+ credit_nonce: note.nonce,
6971
+ credit_shared_key: note.creditSharedKey,
6972
+ change_amount: p.change?.amount ?? 0n,
6973
+ change_nonce: p.change?.nonce ?? 0n
7042
6974
  };
7043
6975
  }
7044
- /** Build an operation context for one asset within this same deployment. */
7045
- forToken(tokenAddress) {
7046
- return new TokenProtocol(
7047
- { ...this.context, tokenAddress: (0, import_ethers9.getAddress)(tokenAddress) },
7048
- { expectedRuntimeCodeHash: this.deployment.protocol.runtimeCodeHash }
6976
+ async createCredit(p) {
6977
+ const words = createCreditPublicInputs(
6978
+ this.#protocol.context,
6979
+ p.params,
6980
+ p.deliveries,
6981
+ p.funding
6982
+ );
6983
+ return provingRequest(
6984
+ "create_credit",
6985
+ await this.creation(p, "create-credit", words),
6986
+ words
7049
6987
  );
7050
6988
  }
7051
- };
7052
-
7053
- // src/verify.ts
7054
- var import_core9 = require("@invisi-labs/core");
7055
- async function verifyNoteCommitment(params) {
7056
- const expected = await (0, import_core9.computeNoteCommitment)(
7057
- params.chainId,
7058
- await (0, import_core9.computeNoteIdentity)(BigInt(params.walletIdentity), BigInt(params.nonce)),
7059
- BigInt(params.tokenAddress),
7060
- params.amount
7061
- );
7062
- return BigInt(expected) === BigInt(params.noteCommitment);
7063
- }
7064
- async function verifyCreditCommitment(params) {
7065
- if (params.creditSharedKey <= 0n || params.creditSharedKey >= import_core9.FIELD_MODULUS)
7066
- throw new RangeError("creditSharedKey must be a nonzero canonical Field");
7067
- const expected = await (0, import_core9.computeCreditCommitment)(
7068
- params.chainId,
7069
- params.spenderWalletIdentity,
7070
- params.ownerWalletIdentity,
7071
- BigInt(params.spenderPayout),
7072
- BigInt(params.ownerPayout),
7073
- BigInt(params.tokenAddress),
7074
- params.amount,
7075
- params.nonce,
7076
- params.expiry,
7077
- await (0, import_core9.computeCreditSharedKeyHash)(params.creditSharedKey)
7078
- );
7079
- return BigInt(expected) === BigInt(params.creditCommitment);
7080
- }
7081
-
7082
- // src/withdrawal.ts
7083
- var import_core10 = require("@invisi-labs/core");
7084
- async function buildWithdrawalCalldata(p) {
7085
- const r = normalizeTransactRequest(p.context, p.params, [], p.funding);
7086
- if (r.outputCount !== 0 || r.depositAmount !== 0n || p.sourceNotes.length === 0 || p.sourceNotes.length !== r.inputCount) {
7087
- throw new Error("full withdrawal requires inputs, no private outputs and no funding");
6989
+ async cancelCredit(p) {
6990
+ const note = (0, import_core10.normalizeCreditDeliveryState)(p.input.state).note, leaf = await this.creditLeaf(note), c = this.#protocol.context;
6991
+ check2(
6992
+ await (0, import_core10.computeCreditNullifier)(c.chainId, note.creditSharedKey, leaf) === p.params.nullifier && note.amount === p.params.amount && note.ownerPayout === BigInt(p.params.owner),
6993
+ "Credit cancellation mismatch"
6994
+ );
6995
+ await this.membership(leaf, p.input, [p.params.source]);
6996
+ const words = cancelCreditPublicInputs(c, p.params), authority = await this.authority(
6997
+ "cancel-credit",
6998
+ 1,
6999
+ words,
7000
+ p.authorization,
7001
+ note.ownerWalletIdentity
7002
+ );
7003
+ return provingRequest(
7004
+ "credit_cancel",
7005
+ {
7006
+ ...authority,
7007
+ spender_payout: note.spenderPayout,
7008
+ spender_wallet_identity: BigInt(note.spenderWalletIdentity),
7009
+ owner_wallet_identity: BigInt(note.ownerWalletIdentity),
7010
+ input_nonce: note.nonce,
7011
+ expiry: note.expiry,
7012
+ credit_shared_key: note.creditSharedKey,
7013
+ leaf_index: BigInt(p.input.leafIndex),
7014
+ merkle_path: [...p.input.path]
7015
+ },
7016
+ words
7017
+ );
7088
7018
  }
7089
- const walletIdentity = BigInt(p.sourceNotes[0].walletIdentity);
7090
- let total = 0n;
7091
- for (const [index, note] of p.sourceNotes.entries()) {
7092
- if (note.chainId !== p.context.chainId || note.protocolAddress !== BigInt(p.context.protocolAddress))
7093
- throw new Error("source note context mismatch");
7094
- if (BigInt(note.walletIdentity) !== walletIdentity || note.tokenAddress !== BigInt(p.context.tokenAddress) || note.amount <= 0n)
7095
- throw new Error("source note wallet/token/amount mismatch");
7096
- const commitment = await (0, import_core10.computeNoteCommitment)(
7097
- note.chainId,
7098
- await (0, import_core10.computeNoteIdentity)(walletIdentity, note.nonce),
7099
- note.tokenAddress,
7100
- note.amount
7019
+ async drawCredit(p) {
7020
+ const c = this.#protocol.context, profile = selectCreditDrawCircuit(p.inputs.length), capacity = profile.maxSize;
7021
+ check2(
7022
+ p.inputs.length === p.amounts.length && p.inputs.length === p.params.nullifiers.length,
7023
+ "draw input count mismatch"
7024
+ );
7025
+ const notes2 = p.inputs.map((input) => (0, import_core10.normalizeCreditDeliveryState)(input.state).note), identity = notes2[0].spenderWalletIdentity;
7026
+ const words = creditDrawPublicInputs(c, p.params, p.deliveries), authority = await this.authority(
7027
+ "credit-draw",
7028
+ capacity,
7029
+ words,
7030
+ p.authorization,
7031
+ identity
7032
+ );
7033
+ const sourceIndices = await Promise.all(
7034
+ notes2.map(async (note, i) => {
7035
+ const leaf = await this.creditLeaf(note);
7036
+ check2(
7037
+ 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 (0, import_core10.computeCreditNullifier)(c.chainId, note.creditSharedKey, leaf) === p.params.nullifiers[i],
7038
+ "Credit draw mismatch"
7039
+ );
7040
+ return BigInt(await this.membership(leaf, p.inputs[i], p.params.sources));
7041
+ })
7042
+ );
7043
+ return provingRequest(
7044
+ profile.name,
7045
+ {
7046
+ ...authority,
7047
+ spender_wallet_identity: BigInt(identity),
7048
+ owner_payouts: pad2(
7049
+ notes2.map((note) => note.ownerPayout),
7050
+ capacity,
7051
+ () => 0n
7052
+ ),
7053
+ owner_wallet_identities: pad2(
7054
+ notes2.map((note) => BigInt(note.ownerWalletIdentity)),
7055
+ capacity,
7056
+ () => 0n
7057
+ ),
7058
+ input_amounts: pad2(
7059
+ notes2.map((note) => note.amount),
7060
+ capacity,
7061
+ () => 0n
7062
+ ),
7063
+ input_nonces: pad2(
7064
+ notes2.map((note) => note.nonce),
7065
+ capacity,
7066
+ () => 0n
7067
+ ),
7068
+ credit_shared_keys: pad2(
7069
+ notes2.map((note) => note.creditSharedKey),
7070
+ capacity,
7071
+ () => 0n
7072
+ ),
7073
+ leaf_indices: pad2(
7074
+ p.inputs.map((input) => BigInt(input.leafIndex)),
7075
+ capacity,
7076
+ () => 0n
7077
+ ),
7078
+ merkle_paths: pad2(
7079
+ p.inputs.map((input) => [...input.path]),
7080
+ capacity,
7081
+ zeros
7082
+ ),
7083
+ input_source_indices: pad2(sourceIndices, capacity, () => 0n),
7084
+ draw_amounts: pad2(p.amounts, capacity, () => 0n)
7085
+ },
7086
+ words
7101
7087
  );
7102
- const nullifier = await (0, import_core10.computeNoteNullifier)(note.chainId, note.nonce, commitment);
7103
- if (nullifier.toLowerCase() !== r.nullifiers[index].toLowerCase())
7104
- throw new Error("source note nullifier mismatch");
7105
- total += note.amount;
7106
7088
  }
7107
- if (r.withdrawalAmount !== total)
7108
- throw new Error("withdrawal must equal the full input balance");
7109
- return buildTransactCalldata({ ...p, deliveries: [] });
7110
- }
7089
+ async topUpCredit(p) {
7090
+ const c = this.#protocol.context, previous = (0, import_core10.normalizeCreditDeliveryState)(p.previous.state), next = (0, import_core10.normalizeCreditDeliveryState)(p.state), old = previous.note, note = next.note, leaf = await this.creditLeaf(old);
7091
+ for (const field2 of [
7092
+ "spenderWalletIdentity",
7093
+ "ownerWalletIdentity",
7094
+ "spenderPayout",
7095
+ "ownerPayout",
7096
+ "creditSharedKey"
7097
+ ])
7098
+ check2(old[field2] === note[field2], "Credit role or payout changed");
7099
+ check2(
7100
+ JSON.stringify(previous.ownerReceivingKeys) === JSON.stringify(next.ownerReceivingKeys) && JSON.stringify(previous.spenderReceivingKeys) === JSON.stringify(next.spenderReceivingKeys),
7101
+ "Credit receiving snapshots changed"
7102
+ );
7103
+ check2(
7104
+ old.amount < note.amount && old.expiry <= note.expiry && old.expiry === p.params.previousExpiry && (c.now === void 0 || old.expiry > c.now),
7105
+ "invalid Credit top-up"
7106
+ );
7107
+ check2(
7108
+ await (0, import_core10.computeCreditNullifier)(c.chainId, old.creditSharedKey, leaf) === p.params.creditNullifier,
7109
+ "previous Credit nullifier mismatch"
7110
+ );
7111
+ await this.membership(leaf, p.previous, [p.params.creditSource]);
7112
+ const words = topUpCreditPublicInputs(c, p.params, p.deliveries, p.funding), base = await this.creation({ ...p, params: p.params.creation }, "top-up-credit", words);
7113
+ return provingRequest(
7114
+ "credit_top_up",
7115
+ {
7116
+ ...base,
7117
+ previous_credit_amount: old.amount,
7118
+ previous_credit_nonce: old.nonce,
7119
+ previous_credit_leaf_index: BigInt(p.previous.leafIndex),
7120
+ previous_credit_merkle_path: [...p.previous.path]
7121
+ },
7122
+ words
7123
+ );
7124
+ }
7125
+ };
7111
7126
 
7112
7127
  // src/factory.ts
7113
7128
  var import_ethers10 = require("ethers");
@@ -7180,8 +7195,7 @@ async function resolveInstanceAddress(client, factoryAddress, salt) {
7180
7195
  normalizeTransactRequest,
7181
7196
  notes,
7182
7197
  pad,
7183
- registrationAuthorizationRequest,
7184
- registrationPublicInputs,
7198
+ registrationDigest,
7185
7199
  registrationTypedData,
7186
7200
  resolveInstanceAddress,
7187
7201
  selectCreditDrawCircuit,