@invisi-labs/protocol 1.1.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.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,512 @@ 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");
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) {
4275
+ if (!(0, import_ethers4.isHexString)(v) || !/^0x(?:[a-fA-F0-9]{2})*$/.test(v) || (0, import_ethers4.dataLength)(v) !== length)
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 ? 400 : 158,
4322
+ options.credit ? 3 : 1
4323
+ );
4324
+ const clue = envelope(value.clue, 68);
4325
+ if (clue.slice(130, 132).toLowerCase() !== "18") throw new Error("clue precision must be 24");
4326
+ return { ciphertext, clue };
4327
+ }
4328
+ var deliveriesHash = (v) => (0, import_ethers4.keccak256)(
4329
+ import_ethers4.AbiCoder.defaultAbiCoder().encode(
4330
+ [
4331
+ {
4332
+ type: "tuple[]",
4333
+ components: [
4334
+ { name: "ciphertext", type: "bytes" },
4335
+ { name: "clue", type: "bytes" }
4336
+ ]
4337
+ }
4338
+ ].map((parameter) => import_ethers4.ParamType.from(parameter)),
4339
+ [dense(v, "deliveries")]
4340
+ )
4341
+ );
4342
+ function normalizeFunding(input = {}) {
4343
+ const f = { ...EMPTY_FUNDING, ...input };
4344
+ (0, import_ethers4.getAddress)(f.payer);
4345
+ uint(f.amount, 128, "depositAmount");
4346
+ uint(f.sigNonce, 256, "sigNonce");
3928
4347
  uint(f.deadline, 256, "funding deadline");
3929
- if (!(0, import_ethers2.isHexString)(f.signature) || !/^0x(?:[a-fA-F0-9]{2})*$/.test(f.signature))
4348
+ if (!(0, import_ethers4.isHexString)(f.signature) || !/^0x(?:[a-fA-F0-9]{2})*$/.test(f.signature))
3930
4349
  throw new Error("invalid signature bytes");
3931
4350
  const p = f.permit;
3932
4351
  uint(p.deadline, 256);
3933
4352
  uint(p.v, 8);
3934
4353
  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");
4354
+ if (!(0, import_ethers4.isHexString)(v) || (0, import_ethers4.dataLength)(v) !== 32) throw new Error("permit r/s must be bytes32");
3936
4355
  if (f.amount === 0n !== (BigInt(f.payer) === 0n))
3937
4356
  throw new Error("deposit amount and payer must both be zero or positive");
3938
4357
  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
4358
  throw new Error("zero funding must be entirely empty");
3940
- return { ...f, payer: (0, import_ethers2.getAddress)(f.payer) };
4359
+ return { ...f, payer: (0, import_ethers4.getAddress)(f.payer) };
3941
4360
  }
3942
4361
  function validateFundingSubmission(f, caller, now) {
3943
4362
  if (f.signature !== "0x" && now !== void 0 && uint(now, 64, "now") > f.deadline)
3944
4363
  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))
4364
+ if (f.signature === "0x" && (f.sigNonce !== 0n || f.deadline !== 0n || caller !== void 0 && f.amount > 0n && (0, import_ethers4.getAddress)(caller) !== f.payer))
3946
4365
  throw new Error("direct funding requires payer caller and zero nonce/deadline");
3947
4366
  }
3948
4367
  var getEIP712Domain = (c) => ({
3949
4368
  name: "InvisibleProtocol",
3950
4369
  version: "1",
3951
4370
  chainId: uint(c.chainId, 64),
3952
- verifyingContract: (0, import_ethers2.getAddress)(c.protocolAddress)
4371
+ verifyingContract: (0, import_ethers4.getAddress)(c.protocolAddress)
3953
4372
  });
3954
4373
  var fundingFields = [
3955
4374
  { name: "requestHash", type: "bytes32" },
@@ -3975,9 +4394,9 @@ var CREATE_CREDIT_FIELDS = [
3975
4394
  ];
3976
4395
  function validateCreateCreditRequest(c, p, cs, funding = {}) {
3977
4396
  known(p, CREATE_CREDIT_FIELDS);
3978
- if ((0, import_ethers3.getAddress)(p.token) !== (0, import_ethers3.getAddress)(c.tokenAddress))
4397
+ if ((0, import_ethers5.getAddress)(p.token) !== (0, import_ethers5.getAddress)(c.tokenAddress))
3979
4398
  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);
4399
+ 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
4400
  if (BigInt(creditCommitment) === 0n || creditCommitment === changeCommitment)
3982
4401
  throw new Error("zero or duplicate commitment");
3983
4402
  if (BigInt(owner) === 0n || expiry === 0n || c.now !== void 0 && expiry <= c.now)
@@ -4034,7 +4453,7 @@ function createCreditBaseInputs(c, p, cs, f = {}) {
4034
4453
  function createCreditPublicInputs(c, p, deliveries, funding = {}) {
4035
4454
  const base = createCreditBaseInputs(c, p, deliveries, funding);
4036
4455
  const digest = BigInt(
4037
- (0, import_core2.computeWalletAuthorizationDigest)({
4456
+ (0, import_core4.computeWalletAuthorizationDigest)({
4038
4457
  context: { chainId: c.chainId, protocolAddress: BigInt(c.protocolAddress) },
4039
4458
  operation: "create-credit",
4040
4459
  capacity: 10,
@@ -4050,17 +4469,17 @@ var hashContext = {
4050
4469
  };
4051
4470
  function createCreditRequestHash(p, cs, f = {}) {
4052
4471
  const r = validateCreateCreditRequest({ ...hashContext, tokenAddress: p.token }, p, cs, f);
4053
- return (0, import_ethers3.keccak256)(
4054
- import_ethers3.AbiCoder.defaultAbiCoder().encode(
4472
+ return (0, import_ethers5.keccak256)(
4473
+ import_ethers5.AbiCoder.defaultAbiCoder().encode(
4055
4474
  [
4056
4475
  { type: "bytes32" },
4057
4476
  creationTuple,
4058
4477
  { type: "bytes32" },
4059
4478
  { type: "address" },
4060
4479
  { type: "uint256" }
4061
- ].map((parameter) => import_ethers3.ParamType.from(parameter)),
4480
+ ].map((parameter) => import_ethers5.ParamType.from(parameter)),
4062
4481
  [
4063
- (0, import_ethers3.keccak256)(new TextEncoder().encode("InvisiCreateCredit")),
4482
+ (0, import_ethers5.keccak256)(new TextEncoder().encode("InvisiCreateCredit")),
4064
4483
  p,
4065
4484
  deliveriesHash(cs),
4066
4485
  r.funding.payer,
@@ -4070,7 +4489,7 @@ function createCreditRequestHash(p, cs, f = {}) {
4070
4489
  );
4071
4490
  }
4072
4491
  function encodeCreateCreditTypedData(c, p, deliveries, funding = {}) {
4073
- return (0, import_core2.walletAuthorizationTypedData)({
4492
+ return (0, import_core4.walletAuthorizationTypedData)({
4074
4493
  context: { chainId: c.chainId, protocolAddress: BigInt(c.protocolAddress) },
4075
4494
  operation: "create-credit",
4076
4495
  capacity: 10,
@@ -4097,7 +4516,7 @@ function buildCreateCreditCalldata(p) {
4097
4516
  const r = validateCreateCreditRequest(p.context, p.params, p.deliveries, p.funding);
4098
4517
  validateFundingSubmission(r.funding, p.caller, p.context.now);
4099
4518
  return {
4100
- data: new import_ethers3.Interface(invisiProtocolAbi).encodeFunctionData("createCredit", [
4519
+ data: new import_ethers5.Interface(invisiProtocolAbi).encodeFunctionData("createCredit", [
4101
4520
  encodeCreditProof(p.proof),
4102
4521
  p.params,
4103
4522
  p.deliveries,
@@ -4107,17 +4526,17 @@ function buildCreateCreditCalldata(p) {
4107
4526
  };
4108
4527
  }
4109
4528
  function encodeCreditProof(proof) {
4110
- if (!(0, import_ethers3.isHexString)(proof) || !/^0x(?:[a-fA-F0-9]{2})*$/.test(proof) || (0, import_ethers3.dataLength)(proof) === 0)
4529
+ if (!(0, import_ethers5.isHexString)(proof) || !/^0x(?:[a-fA-F0-9]{2})*$/.test(proof) || (0, import_ethers5.dataLength)(proof) === 0)
4111
4530
  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)),
4531
+ return import_ethers5.AbiCoder.defaultAbiCoder().encode(
4532
+ ["uint8", "bytes"].map((parameter) => import_ethers5.ParamType.from(parameter)),
4114
4533
  [0, proof]
4115
4534
  );
4116
4535
  }
4117
4536
 
4118
4537
  // src/credit-lifecycle.ts
4119
- var import_ethers4 = require("ethers");
4120
- var import_core3 = require("@invisi-labs/core");
4538
+ var import_ethers6 = require("ethers");
4539
+ var import_core5 = require("@invisi-labs/core");
4121
4540
  var CREDIT_DRAW_CAPACITIES = [1, 12, 50, 120];
4122
4541
  function selectCreditDrawCircuit(count) {
4123
4542
  if (!Number.isInteger(count) || count < 1 || count > 120)
@@ -4142,7 +4561,7 @@ function validateCreditDrawRequest(c, p, cs) {
4142
4561
  "totalAmount",
4143
4562
  "deadline"
4144
4563
  ]);
4145
- if ((0, import_ethers4.getAddress)(p.token) !== (0, import_ethers4.getAddress)(c.tokenAddress))
4564
+ if ((0, import_ethers6.getAddress)(p.token) !== (0, import_ethers6.getAddress)(c.tokenAddress))
4146
4565
  throw new Error("request token mismatch");
4147
4566
  const ctx = normalizeContext(c), ns = notes(p.nullifiers, "nullifiers"), profile = selectCreditDrawCircuit(ns.length), sources = normalizeSources(p.sources, ns.length, profile.maxSize);
4148
4567
  for (const [key, v] of Object.entries({
@@ -4160,7 +4579,7 @@ function validateCreditDrawRequest(c, p, cs) {
4160
4579
  if (BigInt(remainderCommitments[i]) === 0n && BigInt(recoveryAmounts[i]) !== 0n)
4161
4580
  throw new Error("full draw requires zero recovery amount");
4162
4581
  }
4163
- const spender = (0, import_ethers4.getAddress)(p.spender), totalAmount = uint(p.totalAmount, profile.totalBits, "totalAmount");
4582
+ const spender = (0, import_ethers6.getAddress)(p.spender), totalAmount = uint(p.totalAmount, profile.totalBits, "totalAmount");
4164
4583
  if (BigInt(spender) === 0n || totalAmount === 0n)
4165
4584
  throw new Error("spender and total amount must be positive");
4166
4585
  if (dense(cs, "deliveries").length !== 2 * ns.length)
@@ -4211,9 +4630,9 @@ function creditDrawBaseInputs(c, p, cs) {
4211
4630
  }
4212
4631
  function validateCancelCreditRequest(c, p) {
4213
4632
  known(p, ["token", "source", "nullifier", "owner", "amount", "deadline"]);
4214
- if ((0, import_ethers4.getAddress)(p.token) !== (0, import_ethers4.getAddress)(c.tokenAddress))
4633
+ if ((0, import_ethers6.getAddress)(p.token) !== (0, import_ethers6.getAddress)(c.tokenAddress))
4215
4634
  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");
4635
+ 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
4636
  if (BigInt(owner) === 0n || amount === 0n) throw new Error("owner and amount must be positive");
4218
4637
  return {
4219
4638
  ...ctx,
@@ -4271,10 +4690,10 @@ var hashContext2 = {
4271
4690
  };
4272
4691
  function cancelCreditRequestHash(p) {
4273
4692
  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]
4693
+ return (0, import_ethers6.keccak256)(
4694
+ import_ethers6.AbiCoder.defaultAbiCoder().encode(
4695
+ [{ type: "bytes32" }, cancelTuple].map((parameter) => import_ethers6.ParamType.from(parameter)),
4696
+ [(0, import_ethers6.keccak256)(new TextEncoder().encode("InvisiCancelCredit")), p]
4278
4697
  )
4279
4698
  );
4280
4699
  }
@@ -4285,17 +4704,17 @@ function topUpCreditRequestHash(p, cs, f = {}) {
4285
4704
  cs,
4286
4705
  f
4287
4706
  );
4288
- return (0, import_ethers4.keccak256)(
4289
- import_ethers4.AbiCoder.defaultAbiCoder().encode(
4707
+ return (0, import_ethers6.keccak256)(
4708
+ import_ethers6.AbiCoder.defaultAbiCoder().encode(
4290
4709
  [
4291
4710
  { type: "bytes32" },
4292
4711
  topTuple,
4293
4712
  { type: "bytes32" },
4294
4713
  { type: "address" },
4295
4714
  { type: "uint256" }
4296
- ].map((parameter) => import_ethers4.ParamType.from(parameter)),
4715
+ ].map((parameter) => import_ethers6.ParamType.from(parameter)),
4297
4716
  [
4298
- (0, import_ethers4.keccak256)(new TextEncoder().encode("InvisiTopUpCredit")),
4717
+ (0, import_ethers6.keccak256)(new TextEncoder().encode("InvisiTopUpCredit")),
4299
4718
  p,
4300
4719
  deliveriesHash(cs),
4301
4720
  r.creation.funding.payer,
@@ -4305,7 +4724,7 @@ function topUpCreditRequestHash(p, cs, f = {}) {
4305
4724
  );
4306
4725
  }
4307
4726
  function authorize(c, operation, capacity, words) {
4308
- return (0, import_core3.walletAuthorizationTypedData)({
4727
+ return (0, import_core5.walletAuthorizationTypedData)({
4309
4728
  context: { chainId: c.chainId, protocolAddress: BigInt(c.protocolAddress) },
4310
4729
  operation,
4311
4730
  capacity,
@@ -4314,7 +4733,7 @@ function authorize(c, operation, capacity, words) {
4314
4733
  }
4315
4734
  function appendDigest(c, operation, capacity, words) {
4316
4735
  const digest = BigInt(
4317
- (0, import_core3.computeWalletAuthorizationDigest)({
4736
+ (0, import_core5.computeWalletAuthorizationDigest)({
4318
4737
  context: { chainId: c.chainId, protocolAddress: BigInt(c.protocolAddress) },
4319
4738
  operation,
4320
4739
  capacity,
@@ -4370,7 +4789,7 @@ function encodeTopUpCreditFundingTypedData(c, p, cs, f) {
4370
4789
  function buildCreditDrawCalldata(p) {
4371
4790
  validateCreditDrawRequest(p.context, p.params, p.deliveries);
4372
4791
  return {
4373
- data: new import_ethers4.Interface(invisiProtocolAbi).encodeFunctionData("creditDraw", [
4792
+ data: new import_ethers6.Interface(invisiProtocolAbi).encodeFunctionData("creditDraw", [
4374
4793
  encodeCreditProof(p.proof),
4375
4794
  p.params,
4376
4795
  p.deliveries
@@ -4382,7 +4801,7 @@ function buildCreditDrawCalldata(p) {
4382
4801
  function buildCancelCreditCalldata(p) {
4383
4802
  validateCancelCreditRequest(p.context, p.params);
4384
4803
  return {
4385
- data: new import_ethers4.Interface(invisiProtocolAbi).encodeFunctionData("cancelCredit", [
4804
+ data: new import_ethers6.Interface(invisiProtocolAbi).encodeFunctionData("cancelCredit", [
4386
4805
  encodeCreditProof(p.proof),
4387
4806
  p.params
4388
4807
  ])
@@ -4392,7 +4811,7 @@ function buildTopUpCreditCalldata(p) {
4392
4811
  const r = validateTopUpCreditRequest(p.context, p.params, p.deliveries, p.funding);
4393
4812
  validateFundingSubmission(r.creation.funding, p.caller, p.context.now);
4394
4813
  return {
4395
- data: new import_ethers4.Interface(invisiProtocolAbi).encodeFunctionData("topUpCredit", [
4814
+ data: new import_ethers6.Interface(invisiProtocolAbi).encodeFunctionData("topUpCredit", [
4396
4815
  encodeCreditProof(p.proof),
4397
4816
  p.params,
4398
4817
  p.deliveries,
@@ -4403,8 +4822,8 @@ function buildTopUpCreditCalldata(p) {
4403
4822
  }
4404
4823
 
4405
4824
  // src/funds.ts
4406
- var import_ethers5 = require("ethers");
4407
- var import_core4 = require("@invisi-labs/core");
4825
+ var import_ethers7 = require("ethers");
4826
+ var import_core6 = require("@invisi-labs/core");
4408
4827
  var TRANSACT_CAPACITIES = [14, 56, 112, 168];
4409
4828
  function selectTransactCapacity(inputs, outputs) {
4410
4829
  if (!Number.isInteger(inputs) || !Number.isInteger(outputs) || inputs < 0 || outputs < 0 || inputs + outputs < 1 || inputs === 0 && outputs < 2 || inputs + outputs > 168)
@@ -4413,7 +4832,7 @@ function selectTransactCapacity(inputs, outputs) {
4413
4832
  }
4414
4833
  function normalizeTransactRequest(c, p, cs, funding = {}) {
4415
4834
  const ctx = normalizeContext(c);
4416
- if ((0, import_ethers5.getAddress)(p.token) !== ctx.tokenAddress)
4835
+ if ((0, import_ethers7.getAddress)(p.token) !== ctx.tokenAddress)
4417
4836
  throw new Error("request token mismatch");
4418
4837
  known(p, [
4419
4838
  "token",
@@ -4427,7 +4846,7 @@ function normalizeTransactRequest(c, p, cs, funding = {}) {
4427
4846
  const ns = notes(p.nullifiers, "nullifiers"), os = notes(p.outputCommitments, "outputCommitments"), capacity = selectTransactCapacity(ns.length, os.length);
4428
4847
  const sources = normalizeSources(p.sources, ns.length, capacity), deliveries = dense(cs, "deliveries").map((v) => normalizeDelivery(v));
4429
4848
  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);
4849
+ const withdrawalAmount = uint(p.withdrawalAmount, 128, "withdrawalAmount"), withdrawalAddress = (0, import_ethers7.getAddress)(p.withdrawalAddress), f = normalizeFunding(funding);
4431
4850
  if (withdrawalAmount === 0n !== (BigInt(withdrawalAddress) === 0n) || os.length === 0 && withdrawalAmount === 0n)
4432
4851
  throw new Error("invalid withdrawal");
4433
4852
  if (ns.length === 0 && (f.amount === 0n || withdrawalAmount !== 0n))
@@ -4483,7 +4902,7 @@ function transactPublicInputs(c, p, cs, f = {}) {
4483
4902
  }
4484
4903
  function encodeTransactTypedData(c, p, deliveries, f = {}) {
4485
4904
  const r = normalizeTransactRequest(c, p, deliveries, f);
4486
- return (0, import_core4.walletAuthorizationTypedData)({
4905
+ return (0, import_core6.walletAuthorizationTypedData)({
4487
4906
  context: { chainId: r.chainId, protocolAddress: BigInt(r.protocolAddress) },
4488
4907
  operation: "transact",
4489
4908
  capacity: r.capacity,
@@ -4507,24 +4926,24 @@ function transactFundingRequestHash(proof, p, cs) {
4507
4926
  withdrawalAmount: p.withdrawalAmount,
4508
4927
  deadline: p.deadline
4509
4928
  };
4510
- return p.sources.length > 1 ? (0, import_ethers5.keccak256)(
4511
- import_ethers5.AbiCoder.defaultAbiCoder().encode(
4929
+ return p.sources.length > 1 ? (0, import_ethers7.keccak256)(
4930
+ import_ethers7.AbiCoder.defaultAbiCoder().encode(
4512
4931
  [{ type: "bytes32" }, { type: "bytes32" }, crossTuple, { type: "bytes32" }].map(
4513
- (parameter) => import_ethers5.ParamType.from(parameter)
4932
+ (parameter) => import_ethers7.ParamType.from(parameter)
4514
4933
  ),
4515
4934
  [
4516
- (0, import_ethers5.keccak256)(new TextEncoder().encode("InvisiCrossTreeTransact")),
4517
- (0, import_ethers5.keccak256)(proof),
4935
+ (0, import_ethers7.keccak256)(new TextEncoder().encode("InvisiCrossTreeTransact")),
4936
+ (0, import_ethers7.keccak256)(proof),
4518
4937
  p,
4519
4938
  deliveriesHash(cs)
4520
4939
  ]
4521
4940
  )
4522
- ) : (0, import_ethers5.keccak256)(
4523
- import_ethers5.AbiCoder.defaultAbiCoder().encode(
4941
+ ) : (0, import_ethers7.keccak256)(
4942
+ import_ethers7.AbiCoder.defaultAbiCoder().encode(
4524
4943
  [{ type: "bytes32" }, singleTuple, { type: "bytes32" }].map(
4525
- (parameter) => import_ethers5.ParamType.from(parameter)
4944
+ (parameter) => import_ethers7.ParamType.from(parameter)
4526
4945
  ),
4527
- [(0, import_ethers5.keccak256)(proof), single, deliveriesHash(cs)]
4946
+ [(0, import_ethers7.keccak256)(proof), single, deliveriesHash(cs)]
4528
4947
  )
4529
4948
  );
4530
4949
  }
@@ -4564,7 +4983,7 @@ function buildTransactCalldata(p) {
4564
4983
  const abi = invisiProtocolAbi.filter(
4565
4984
  (item) => item.type === "function" && item.name === "transact" && item.inputs.length === 2 && item.inputs[1]?.type === "tuple"
4566
4985
  );
4567
- const data = new import_ethers5.Interface(abi).encodeFunctionData("transact", [p.proof, request]);
4986
+ const data = new import_ethers7.Interface(abi).encodeFunctionData("transact", [p.proof, request]);
4568
4987
  return { data, capacity: r.capacity, approveAmount: r.depositAmount };
4569
4988
  }
4570
4989
  function buildTransactAggregateCalldata(p) {
@@ -4581,7 +5000,7 @@ function buildTransactAggregateCalldata(p) {
4581
5000
  validateFundingSubmission(r.funding, p.caller, p.context.now);
4582
5001
  }
4583
5002
  return {
4584
- data: new import_ethers5.Interface(
5003
+ data: new import_ethers7.Interface(
4585
5004
  invisiProtocolAbi.filter(
4586
5005
  (item) => item.type === "function" && item.name === "transact" && item.inputs[1]?.type === "tuple[]"
4587
5006
  )
@@ -4591,7 +5010,7 @@ function buildTransactAggregateCalldata(p) {
4591
5010
  }
4592
5011
  async function validateShieldRequest(p) {
4593
5012
  normalizeContext(p.context);
4594
- if ((0, import_ethers5.getAddress)(p.params.token) !== (0, import_ethers5.getAddress)(p.context.tokenAddress))
5013
+ if ((0, import_ethers7.getAddress)(p.params.token) !== (0, import_ethers7.getAddress)(p.context.tokenAddress))
4595
5014
  throw new Error("request token mismatch");
4596
5015
  known(p.params, ["token", "outputCommitments", "deadline"]);
4597
5016
  checkDeadline(p.context, p.params.deadline);
@@ -4605,7 +5024,7 @@ async function validateShieldRequest(p) {
4605
5024
  if (o.amount === 0n) throw new Error("amount must be positive");
4606
5025
  field(o.identity);
4607
5026
  normalizeDelivery(cs[i]);
4608
- if (await (0, import_core4.computeNoteCommitment)(
5027
+ if (await (0, import_core6.computeNoteCommitment)(
4609
5028
  p.context.chainId,
4610
5029
  o.identity,
4611
5030
  BigInt(p.context.tokenAddress),
@@ -4618,22 +5037,22 @@ async function validateShieldRequest(p) {
4618
5037
  return f;
4619
5038
  }
4620
5039
  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)),
5040
+ const outputHash = (0, import_ethers7.keccak256)(
5041
+ import_ethers7.AbiCoder.defaultAbiCoder().encode(
5042
+ ["(bytes32 identity,uint256 amount)[]"].map((parameter) => import_ethers7.ParamType.from(parameter)),
4624
5043
  [outputs]
4625
5044
  )
4626
5045
  );
4627
- return (0, import_ethers5.keccak256)(
4628
- import_ethers5.AbiCoder.defaultAbiCoder().encode(
5046
+ return (0, import_ethers7.keccak256)(
5047
+ import_ethers7.AbiCoder.defaultAbiCoder().encode(
4629
5048
  [
4630
5049
  "bytes32",
4631
5050
  "(address token,bytes32[] outputCommitments,uint256 deadline)",
4632
5051
  "bytes32",
4633
5052
  "bytes32"
4634
- ].map((parameter) => import_ethers5.ParamType.from(parameter)),
5053
+ ].map((parameter) => import_ethers7.ParamType.from(parameter)),
4635
5054
  [
4636
- (0, import_ethers5.keccak256)(new TextEncoder().encode("InvisiShield")),
5055
+ (0, import_ethers7.keccak256)(new TextEncoder().encode("InvisiShield")),
4637
5056
  params,
4638
5057
  outputHash,
4639
5058
  deliveriesHash(cs)
@@ -4660,7 +5079,7 @@ async function buildShieldCalldata(p) {
4660
5079
  const f = await validateShieldRequest(p);
4661
5080
  validateFundingSubmission(f, p.caller, p.context.now);
4662
5081
  return {
4663
- data: new import_ethers5.Interface(invisiProtocolAbi).encodeFunctionData("shield", [
5082
+ data: new import_ethers7.Interface(invisiProtocolAbi).encodeFunctionData("shield", [
4664
5083
  p.params,
4665
5084
  p.outputs,
4666
5085
  p.deliveries,
@@ -4671,7 +5090,7 @@ async function buildShieldCalldata(p) {
4671
5090
  }
4672
5091
  function transactUserPublicInputs(c, p, cs, f = {}) {
4673
5092
  const words = transactPublicInputs(c, p, cs, f), digest = BigInt(
4674
- ((typed) => import_ethers5.TypedDataEncoder.hash(
5093
+ ((typed) => import_ethers7.TypedDataEncoder.hash(
4675
5094
  typed.domain,
4676
5095
  Object.fromEntries(
4677
5096
  Object.entries(typed.types).map(([name, fields]) => [
@@ -4690,11 +5109,11 @@ function aggregateMemberRequestHash(c, r) {
4690
5109
  r.params.outputCommitments.length
4691
5110
  );
4692
5111
  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)),
5112
+ return (0, import_ethers7.keccak256)(
5113
+ import_ethers7.AbiCoder.defaultAbiCoder().encode(
5114
+ ["bytes32", "uint256", "bytes32[]"].map((parameter) => import_ethers7.ParamType.from(parameter)),
4696
5115
  [
4697
- (0, import_ethers5.keccak256)(new TextEncoder().encode("InvisiAtomicBatchMemberV1")),
5116
+ (0, import_ethers7.keccak256)(new TextEncoder().encode("InvisiAtomicBatchMemberV1")),
4698
5117
  BigInt(capacity),
4699
5118
  transactPublicInputs(c, r.params, r.deliveries, r.funding)
4700
5119
  ]
@@ -4727,6 +5146,240 @@ function encodeAggregateFundingTypedData(c, r) {
4727
5146
  };
4728
5147
  }
4729
5148
 
5149
+ // src/Protocol.ts
5150
+ var import_ethers9 = require("ethers");
5151
+ var import_rpc = require("@invisi-labs/rpc");
5152
+
5153
+ // src/TokenProtocol.ts
5154
+ var import_ethers8 = require("ethers");
5155
+ var import_core7 = require("@invisi-labs/core");
5156
+ var TokenProtocol = class {
5157
+ context;
5158
+ expectedRuntimeCodeHash;
5159
+ constructor(context, options = {}) {
5160
+ const normalized = normalizeContext(context);
5161
+ if (BigInt(normalized.protocolAddress) === 0n || BigInt(normalized.tokenAddress) === 0n) {
5162
+ throw new Error("deployment addresses must be nonzero");
5163
+ }
5164
+ if (options.expectedRuntimeCodeHash && !/^0x[0-9a-fA-F]{64}$/.test(options.expectedRuntimeCodeHash)) {
5165
+ throw new Error("invalid runtime code hash");
5166
+ }
5167
+ this.expectedRuntimeCodeHash = options.expectedRuntimeCodeHash?.toLowerCase();
5168
+ this.context = Object.freeze(normalized);
5169
+ Object.freeze(this);
5170
+ }
5171
+ async validateDeployment(reader, options = {}) {
5172
+ if ((options.requireRuntimeProfile ?? true) && !this.expectedRuntimeCodeHash) {
5173
+ throw new import_core7.MissingCapabilityError("trusted deployment profile");
5174
+ }
5175
+ if (await reader.getChainId() !== this.context.chainId) {
5176
+ throw new Error("deployment chain mismatch");
5177
+ }
5178
+ const code = await reader.getCode(this.context.protocolAddress);
5179
+ if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(code) || this.expectedRuntimeCodeHash && (0, import_ethers8.keccak256)(code) !== this.expectedRuntimeCodeHash) {
5180
+ throw new Error("deployment runtime code profile mismatch");
5181
+ }
5182
+ const tokenCode = await reader.getCode(this.context.tokenAddress);
5183
+ if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(tokenCode)) {
5184
+ throw new Error("token address must have contract code");
5185
+ }
5186
+ }
5187
+ transact(request) {
5188
+ return {
5189
+ to: this.context.protocolAddress,
5190
+ value: 0n,
5191
+ ...buildTransactCalldata({ ...request, context: this.context })
5192
+ };
5193
+ }
5194
+ aggregate(request) {
5195
+ return {
5196
+ to: this.context.protocolAddress,
5197
+ value: 0n,
5198
+ ...buildTransactAggregateCalldata({ ...request, context: this.context })
5199
+ };
5200
+ }
5201
+ async shield(request) {
5202
+ return {
5203
+ to: this.context.protocolAddress,
5204
+ value: 0n,
5205
+ ...await buildShieldCalldata({ ...request, context: this.context })
5206
+ };
5207
+ }
5208
+ createCredit(request) {
5209
+ return {
5210
+ to: this.context.protocolAddress,
5211
+ value: 0n,
5212
+ ...buildCreateCreditCalldata({ ...request, context: this.context })
5213
+ };
5214
+ }
5215
+ drawCredit(request) {
5216
+ return {
5217
+ to: this.context.protocolAddress,
5218
+ value: 0n,
5219
+ ...buildCreditDrawCalldata({ ...request, context: this.context })
5220
+ };
5221
+ }
5222
+ cancelCredit(request) {
5223
+ return {
5224
+ to: this.context.protocolAddress,
5225
+ value: 0n,
5226
+ ...buildCancelCreditCalldata({ ...request, context: this.context })
5227
+ };
5228
+ }
5229
+ topUpCredit(request) {
5230
+ return {
5231
+ to: this.context.protocolAddress,
5232
+ value: 0n,
5233
+ ...buildTopUpCreditCalldata({ ...request, context: this.context })
5234
+ };
5235
+ }
5236
+ };
5237
+
5238
+ // src/Protocol.ts
5239
+ var Protocol = class _Protocol {
5240
+ deployment;
5241
+ context;
5242
+ constructor(options) {
5243
+ known(options, ["deployment"], "protocol options");
5244
+ this.deployment = (0, import_rpc.defineDeployment)(options.deployment);
5245
+ this.context = Object.freeze({
5246
+ chainId: this.deployment.chainId,
5247
+ protocolAddress: this.deployment.protocol.address
5248
+ });
5249
+ Object.freeze(this);
5250
+ }
5251
+ /** Load the selected deployment and verify its contract against Chain RPC before returning. */
5252
+ static async fromRpc(rpc, provider, options = {}) {
5253
+ const chainId = (await provider.getNetwork()).chainId;
5254
+ if (typeof chainId !== "bigint" || chainId <= 0n || chainId >= 1n << 64n)
5255
+ throw new Error("invalid protocol chainId");
5256
+ const deployment = await rpc.getDeployment(
5257
+ chainId,
5258
+ options.signal ? { signal: options.signal } : {}
5259
+ );
5260
+ const protocol = new _Protocol({ deployment });
5261
+ if (protocol.context.chainId !== chainId) throw new Error("RPC deployment chain mismatch");
5262
+ await protocol.validateDeployment(provider);
5263
+ return protocol;
5264
+ }
5265
+ async validateDeployment(connection) {
5266
+ const reader = "getNetwork" in connection ? {
5267
+ getChainId: async () => (await connection.getNetwork()).chainId,
5268
+ getCode: async (address) => await connection.getCode(address),
5269
+ getProtocolAddressRegistry: async (address) => (0, import_ethers9.getAddress)(
5270
+ await new import_ethers9.Contract(
5271
+ address,
5272
+ ["function addressRegistry() view returns (address)"],
5273
+ connection
5274
+ ).getFunction("addressRegistry")()
5275
+ ),
5276
+ getProtocolVersion: async (address) => BigInt(
5277
+ await new import_ethers9.Contract(
5278
+ address,
5279
+ ["function VERSION() view returns (uint256)"],
5280
+ connection
5281
+ ).getFunction("VERSION")()
5282
+ )
5283
+ } : connection;
5284
+ if (await reader.getChainId() !== this.context.chainId)
5285
+ throw new Error("deployment chain mismatch");
5286
+ const code = await reader.getCode(this.context.protocolAddress);
5287
+ if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(code) || (0, import_ethers9.keccak256)(code) !== this.deployment.protocol.runtimeCodeHash)
5288
+ throw new Error("protocol runtime code profile mismatch");
5289
+ if (reader.getProtocolVersion && await reader.getProtocolVersion(this.context.protocolAddress) !== 1n)
5290
+ throw new Error("unsupported onchain protocol version");
5291
+ const registry = this.deployment.registry;
5292
+ if (registry) {
5293
+ if (!reader.getProtocolAddressRegistry)
5294
+ throw new Error("registry binding reader capability is missing");
5295
+ if ((0, import_ethers9.getAddress)(
5296
+ await reader.getProtocolAddressRegistry(this.context.protocolAddress)
5297
+ ) !== (0, import_ethers9.getAddress)(registry.address))
5298
+ throw new Error("protocol registry binding mismatch");
5299
+ const registryCode = await reader.getCode(registry.address);
5300
+ if (!/^0x(?:[0-9a-fA-F]{2})+$/.test(registryCode) || (0, import_ethers9.keccak256)(registryCode) !== registry.runtimeCodeHash)
5301
+ throw new Error("registry runtime code profile mismatch");
5302
+ }
5303
+ }
5304
+ aggregate(request) {
5305
+ return {
5306
+ to: this.context.protocolAddress,
5307
+ value: 0n,
5308
+ ...buildTransactAggregateCalldata({ ...request, context: this.context })
5309
+ };
5310
+ }
5311
+ /** Build an operation context for one asset within this same deployment. */
5312
+ forToken(tokenAddress) {
5313
+ return new TokenProtocol(
5314
+ { ...this.context, tokenAddress: (0, import_ethers9.getAddress)(tokenAddress) },
5315
+ { expectedRuntimeCodeHash: this.deployment.protocol.runtimeCodeHash }
5316
+ );
5317
+ }
5318
+ };
5319
+
5320
+ // src/verify.ts
5321
+ var import_core8 = require("@invisi-labs/core");
5322
+ async function verifyNoteCommitment(params) {
5323
+ const expected = await (0, import_core8.computeNoteCommitment)(
5324
+ params.chainId,
5325
+ await (0, import_core8.computeNoteIdentity)(BigInt(params.walletIdentity), BigInt(params.nonce)),
5326
+ BigInt(params.tokenAddress),
5327
+ params.amount
5328
+ );
5329
+ return BigInt(expected) === BigInt(params.noteCommitment);
5330
+ }
5331
+ async function verifyCreditCommitment(params) {
5332
+ if (params.creditSharedKey <= 0n || params.creditSharedKey >= import_core8.FIELD_MODULUS)
5333
+ throw new RangeError("creditSharedKey must be a nonzero canonical Field");
5334
+ const expected = await (0, import_core8.computeCreditCommitment)(
5335
+ params.chainId,
5336
+ params.spenderWalletIdentity,
5337
+ params.ownerWalletIdentity,
5338
+ BigInt(params.spenderPayout),
5339
+ BigInt(params.ownerPayout),
5340
+ BigInt(params.tokenAddress),
5341
+ params.amount,
5342
+ params.nonce,
5343
+ params.expiry,
5344
+ await (0, import_core8.computeCreditSharedKeyHash)(params.creditSharedKey)
5345
+ );
5346
+ return BigInt(expected) === BigInt(params.creditCommitment);
5347
+ }
5348
+
5349
+ // src/withdrawal.ts
5350
+ var import_core9 = require("@invisi-labs/core");
5351
+ async function buildWithdrawalCalldata(p) {
5352
+ const r = normalizeTransactRequest(p.context, p.params, [], p.funding);
5353
+ if (r.outputCount !== 0 || r.depositAmount !== 0n || p.sourceNotes.length === 0 || p.sourceNotes.length !== r.inputCount) {
5354
+ throw new Error("full withdrawal requires inputs, no private outputs and no funding");
5355
+ }
5356
+ const walletIdentity = BigInt(p.sourceNotes[0].walletIdentity);
5357
+ let total = 0n;
5358
+ for (const [index, note] of p.sourceNotes.entries()) {
5359
+ if (note.chainId !== p.context.chainId || note.protocolAddress !== BigInt(p.context.protocolAddress))
5360
+ throw new Error("source note context mismatch");
5361
+ if (BigInt(note.walletIdentity) !== walletIdentity || note.tokenAddress !== BigInt(p.context.tokenAddress) || note.amount <= 0n)
5362
+ throw new Error("source note wallet/token/amount mismatch");
5363
+ const commitment = await (0, import_core9.computeNoteCommitment)(
5364
+ note.chainId,
5365
+ await (0, import_core9.computeNoteIdentity)(walletIdentity, note.nonce),
5366
+ note.tokenAddress,
5367
+ note.amount
5368
+ );
5369
+ const nullifier = await (0, import_core9.computeNoteNullifier)(note.chainId, note.nonce, commitment);
5370
+ if (nullifier.toLowerCase() !== r.nullifiers[index].toLowerCase())
5371
+ throw new Error("source note nullifier mismatch");
5372
+ total += note.amount;
5373
+ }
5374
+ if (r.withdrawalAmount !== total)
5375
+ throw new Error("withdrawal must equal the full input balance");
5376
+ return buildTransactCalldata({ ...p, deliveries: [] });
5377
+ }
5378
+
5379
+ // src/witness.ts
5380
+ var import_core10 = require("@invisi-labs/core");
5381
+ var import_prover = require("@invisi-labs/prover");
5382
+
4730
5383
  // src/witness-layouts.json
4731
5384
  var witness_layouts_default = {
4732
5385
  transact_user_slots14: {
@@ -5718,301 +6371,85 @@ var witness_layouts_default = {
5718
6371
  publicInputCount: 732,
5719
6372
  public: [
5720
6373
  {
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",
6374
+ name: "chain_id",
5958
6375
  count: 1,
5959
6376
  array: false
5960
6377
  },
5961
6378
  {
5962
- name: "change_commitment",
6379
+ name: "protocol_address",
5963
6380
  count: 1,
5964
6381
  array: false
5965
6382
  },
5966
6383
  {
5967
- name: "delivery_hash_high",
6384
+ name: "token_address",
5968
6385
  count: 1,
5969
6386
  array: false
5970
6387
  },
5971
6388
  {
5972
- name: "delivery_hash_low",
6389
+ name: "spender_address",
5973
6390
  count: 1,
5974
6391
  array: false
5975
6392
  },
5976
6393
  {
5977
- name: "expiry",
6394
+ name: "actual_count",
5978
6395
  count: 1,
5979
6396
  array: false
5980
6397
  },
5981
6398
  {
5982
- name: "deadline",
6399
+ name: "source_count",
5983
6400
  count: 1,
5984
6401
  array: false
5985
6402
  },
5986
6403
  {
5987
- name: "deposit_amount",
5988
- count: 1,
5989
- array: false
6404
+ name: "tree_ids",
6405
+ count: 120,
6406
+ array: true
5990
6407
  },
5991
6408
  {
5992
- name: "deposit_payer",
5993
- count: 1,
5994
- array: false
6409
+ name: "roots",
6410
+ count: 120,
6411
+ array: true
5995
6412
  },
5996
6413
  {
5997
- name: "credit_tree_id",
6414
+ name: "nullifiers",
6415
+ count: 120,
6416
+ array: true
6417
+ },
6418
+ {
6419
+ name: "remainder_commitments",
6420
+ count: 120,
6421
+ array: true
6422
+ },
6423
+ {
6424
+ name: "expiries",
6425
+ count: 120,
6426
+ array: true
6427
+ },
6428
+ {
6429
+ name: "total_amount",
5998
6430
  count: 1,
5999
6431
  array: false
6000
6432
  },
6001
6433
  {
6002
- name: "credit_merkle_root",
6434
+ name: "deadline",
6003
6435
  count: 1,
6004
6436
  array: false
6005
6437
  },
6006
6438
  {
6007
- name: "credit_nullifier",
6439
+ name: "delivery_hash_high",
6008
6440
  count: 1,
6009
6441
  array: false
6010
6442
  },
6011
6443
  {
6012
- name: "previous_expiry",
6444
+ name: "delivery_hash_low",
6013
6445
  count: 1,
6014
6446
  array: false
6015
6447
  },
6448
+ {
6449
+ name: "recovery_amounts",
6450
+ count: 120,
6451
+ array: true
6452
+ },
6016
6453
  {
6017
6454
  name: "auth_digest_high",
6018
6455
  count: 1,
@@ -6025,1089 +6462,666 @@ var witness_layouts_default = {
6025
6462
  }
6026
6463
  ],
6027
6464
  private: [
6465
+ "public_key_x",
6466
+ "public_key_y",
6467
+ "signature",
6468
+ "spender_wallet_identity",
6469
+ "owner_payouts",
6470
+ "owner_wallet_identities",
6028
6471
  "input_amounts",
6029
6472
  "input_nonces",
6473
+ "credit_shared_keys",
6030
6474
  "leaf_indices",
6031
6475
  "merkle_paths",
6032
6476
  "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"
6477
+ "draw_amounts"
6048
6478
  ]
6049
6479
  },
6050
- wallet_registration: {
6051
- artifactSha256: "65c3d429f6bc9735af3136f7c383214c2eb222cd32655791f37f7ae5dd428048",
6480
+ credit_cancel: {
6481
+ artifactSha256: "ff278a04f22d2886c9f27f7785a0b8fc317dd242fd4aa9d0d9398d18b7513daf",
6052
6482
  keys: {
6053
- evm: "b8171bdb558489c75293ee71f64c1ac534f533ae3b3f71107378e46dbd93dd48"
6483
+ evm: "1f8a3c20cb081d6a90962556da3124919cc4e5675e59ad31562af39299da02fb"
6054
6484
  },
6055
- publicInputCount: 3,
6485
+ publicInputCount: 11,
6056
6486
  public: [
6057
6487
  {
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}`,
6488
+ name: "chain_id",
6489
+ count: 1,
6490
+ array: false
6491
+ },
6255
6492
  {
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)
6493
+ name: "protocol_address",
6494
+ count: 1,
6495
+ array: false
6287
6496
  },
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
6497
  {
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]
6498
+ name: "token_address",
6499
+ count: 1,
6500
+ array: false
6390
6501
  },
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
6502
  {
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)
6503
+ name: "owner_address",
6504
+ count: 1,
6505
+ array: false
6460
6506
  },
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
6507
  {
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]
6508
+ name: "tree_id",
6509
+ count: 1,
6510
+ array: false
6511
+ },
6512
+ {
6513
+ name: "merkle_root",
6514
+ count: 1,
6515
+ array: false
6516
+ },
6517
+ {
6518
+ name: "nullifier",
6519
+ count: 1,
6520
+ array: false
6521
+ },
6522
+ {
6523
+ name: "amount",
6524
+ count: 1,
6525
+ array: false
6496
6526
  },
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)
6527
+ {
6528
+ name: "deadline",
6529
+ count: 1,
6530
+ array: false
6586
6531
  },
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
- );
6532
+ {
6533
+ name: "auth_digest_high",
6534
+ count: 1,
6535
+ array: false
6536
+ },
6537
+ {
6538
+ name: "auth_digest_low",
6539
+ count: 1,
6540
+ array: false
6541
+ }
6542
+ ],
6543
+ private: [
6544
+ "public_key_x",
6545
+ "public_key_y",
6546
+ "signature",
6547
+ "spender_payout",
6548
+ "spender_wallet_identity",
6549
+ "owner_wallet_identity",
6550
+ "input_nonce",
6551
+ "expiry",
6552
+ "credit_shared_key",
6553
+ "leaf_index",
6554
+ "merkle_path"
6555
+ ]
6556
+ },
6557
+ credit_top_up: {
6558
+ artifactSha256: "fbe662363d9814983f7940f74369117cd6c84783945fbf527b0ed48d011b58a4",
6559
+ keys: {
6560
+ evm: "44436f31414497a708355426da051ee48ba63fdebcb6cfd72347c37c34c98c50"
6561
+ },
6562
+ publicInputCount: 50,
6563
+ public: [
6564
+ {
6565
+ name: "chain_id",
6566
+ count: 1,
6567
+ array: false
6568
+ },
6569
+ {
6570
+ name: "protocol_address",
6571
+ count: 1,
6572
+ array: false
6573
+ },
6574
+ {
6575
+ name: "token_address",
6576
+ count: 1,
6577
+ array: false
6578
+ },
6579
+ {
6580
+ name: "owner_address",
6581
+ count: 1,
6582
+ array: false
6583
+ },
6584
+ {
6585
+ name: "actual_count",
6586
+ count: 1,
6587
+ array: false
6588
+ },
6589
+ {
6590
+ name: "source_count",
6591
+ count: 1,
6592
+ array: false
6593
+ },
6594
+ {
6595
+ name: "input_tree_ids",
6596
+ count: 10,
6597
+ array: true
6598
+ },
6599
+ {
6600
+ name: "merkle_roots",
6601
+ count: 10,
6602
+ array: true
6603
+ },
6604
+ {
6605
+ name: "nullifiers",
6606
+ count: 10,
6607
+ array: true
6608
+ },
6609
+ {
6610
+ name: "credit_commitment",
6611
+ count: 1,
6612
+ array: false
6613
+ },
6614
+ {
6615
+ name: "change_commitment",
6616
+ count: 1,
6617
+ array: false
6618
+ },
6619
+ {
6620
+ name: "delivery_hash_high",
6621
+ count: 1,
6622
+ array: false
6623
+ },
6624
+ {
6625
+ name: "delivery_hash_low",
6626
+ count: 1,
6627
+ array: false
6628
+ },
6629
+ {
6630
+ name: "expiry",
6631
+ count: 1,
6632
+ array: false
6633
+ },
6634
+ {
6635
+ name: "deadline",
6636
+ count: 1,
6637
+ array: false
6638
+ },
6639
+ {
6640
+ name: "deposit_amount",
6641
+ count: 1,
6642
+ array: false
6643
+ },
6644
+ {
6645
+ name: "deposit_payer",
6646
+ count: 1,
6647
+ array: false
6648
+ },
6649
+ {
6650
+ name: "credit_tree_id",
6651
+ count: 1,
6652
+ array: false
6653
+ },
6654
+ {
6655
+ name: "credit_merkle_root",
6656
+ count: 1,
6657
+ array: false
6658
+ },
6659
+ {
6660
+ name: "credit_nullifier",
6661
+ count: 1,
6662
+ array: false
6663
+ },
6664
+ {
6665
+ name: "previous_expiry",
6666
+ count: 1,
6667
+ array: false
6668
+ },
6669
+ {
6670
+ name: "auth_digest_high",
6671
+ count: 1,
6672
+ array: false
6673
+ },
6674
+ {
6675
+ name: "auth_digest_low",
6676
+ count: 1,
6677
+ array: false
6818
6678
  }
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
- };
6679
+ ],
6680
+ private: [
6681
+ "input_amounts",
6682
+ "input_nonces",
6683
+ "leaf_indices",
6684
+ "merkle_paths",
6685
+ "input_source_indices",
6686
+ "public_key_x",
6687
+ "public_key_y",
6688
+ "signature",
6689
+ "spender_payout",
6690
+ "spender_wallet_identity",
6691
+ "owner_wallet_identity",
6692
+ "credit_amount",
6693
+ "credit_nonce",
6694
+ "credit_shared_key",
6695
+ "change_amount",
6696
+ "change_nonce",
6697
+ "previous_credit_amount",
6698
+ "previous_credit_nonce",
6699
+ "previous_credit_leaf_index",
6700
+ "previous_credit_merkle_path"
6701
+ ]
6945
6702
  }
6946
- aggregate(request) {
6947
- return {
6948
- to: this.context.protocolAddress,
6949
- value: 0n,
6950
- ...buildTransactAggregateCalldata({ ...request, context: this.context })
6951
- };
6703
+ };
6704
+
6705
+ // src/witness.ts
6706
+ var pad2 = (values, count, zero) => {
6707
+ if (values.length > count) throw new Error("witness capacity exceeded");
6708
+ return [...values, ...Array.from({ length: count - values.length }, zero)];
6709
+ };
6710
+ var zeros = () => Array(16).fill(0n);
6711
+ var zeroAuthority = () => ({
6712
+ public_key_x: Array(32).fill(0),
6713
+ public_key_y: Array(32).fill(0),
6714
+ signature: Array(64).fill(0)
6715
+ });
6716
+ function check2(ok, message) {
6717
+ if (!ok) throw new Error(message);
6718
+ }
6719
+ function provingRequest(circuitName, privateInputs, expectedPublicInputs, target = "evm") {
6720
+ const schema = witness_layouts_default[circuitName], key = schema.keys[target];
6721
+ check2(typeof key === "string", "unpublished proof target");
6722
+ check2(
6723
+ expectedPublicInputs.length === schema.publicInputCount,
6724
+ "public input order/width mismatch"
6725
+ );
6726
+ check2(
6727
+ Object.keys(privateInputs).length === schema.private.length && schema.private.every((name) => Object.hasOwn(privateInputs, name)),
6728
+ "private witness schema mismatch"
6729
+ );
6730
+ let offset = 0;
6731
+ const publicInputs = {};
6732
+ for (const entry of schema.public) {
6733
+ const values = expectedPublicInputs.slice(offset, offset + entry.count).map((value) => {
6734
+ const n = BigInt(value);
6735
+ check2(n >= 0n && n < FIELD_MODULUS, "noncanonical public input");
6736
+ return n;
6737
+ });
6738
+ publicInputs[entry.name] = entry.array ? values : values[0];
6739
+ offset += entry.count;
6952
6740
  }
6953
- async shield(request) {
6954
- return {
6955
- to: this.context.protocolAddress,
6956
- value: 0n,
6957
- ...await buildShieldCalldata({ ...request, context: this.context })
6958
- };
6741
+ check2(offset === expectedPublicInputs.length, "public input layout mismatch");
6742
+ return {
6743
+ circuitName,
6744
+ target,
6745
+ artifactSha256: schema.artifactSha256,
6746
+ vkSha256: key,
6747
+ expectedPublicInputs: [...expectedPublicInputs],
6748
+ witness: new import_prover.LocalWitness({ ...privateInputs, ...publicInputs })
6749
+ };
6750
+ }
6751
+ var WitnessBuilder = class {
6752
+ #protocol;
6753
+ constructor(protocol) {
6754
+ this.#protocol = protocol;
6959
6755
  }
6960
- createCredit(request) {
6756
+ static statement(circuitName, expectedPublicInputs, target = "evm") {
6757
+ const schema = witness_layouts_default[circuitName], key = schema.keys[target];
6758
+ check2(
6759
+ typeof key === "string" && expectedPublicInputs.length === schema.publicInputCount,
6760
+ "unpublished target or statement width mismatch"
6761
+ );
6961
6762
  return {
6962
- to: this.context.protocolAddress,
6963
- value: 0n,
6964
- ...buildCreateCreditCalldata({ ...request, context: this.context })
6763
+ circuitName,
6764
+ target,
6765
+ artifactSha256: schema.artifactSha256,
6766
+ vkSha256: key,
6767
+ expectedPublicInputs: [...expectedPublicInputs]
6965
6768
  };
6966
6769
  }
6967
- drawCredit(request) {
6968
- return {
6969
- to: this.context.protocolAddress,
6970
- value: 0n,
6971
- ...buildCreditDrawCalldata({ ...request, context: this.context })
6972
- };
6770
+ context(note) {
6771
+ const c = this.#protocol.context;
6772
+ check2(
6773
+ note.chainId === c.chainId && note.protocolAddress === BigInt(c.protocolAddress) && note.tokenAddress === BigInt(c.tokenAddress),
6774
+ "note context mismatch"
6775
+ );
6973
6776
  }
6974
- cancelCredit(request) {
6975
- return {
6976
- to: this.context.protocolAddress,
6977
- value: 0n,
6978
- ...buildCancelCreditCalldata({ ...request, context: this.context })
6777
+ async authority(operation, capacity, words, signed, identity) {
6778
+ check2(!!signed, "private wallet authorization required");
6779
+ const c = this.#protocol.context, request = {
6780
+ context: { chainId: c.chainId, protocolAddress: BigInt(c.protocolAddress) },
6781
+ operation,
6782
+ capacity,
6783
+ words: words.slice(0, -2).map(BigInt)
6979
6784
  };
6785
+ check2(
6786
+ signed.walletIdentity === identity && signed.digest === (0, import_core10.computeWalletAuthorizationDigest)(request),
6787
+ "authorization statement mismatch"
6788
+ );
6789
+ const witness = signed.withWitness((value) => value);
6790
+ check2(
6791
+ await (0, import_core10.verifyWalletAuthorization)(
6792
+ identity,
6793
+ Uint8Array.from([4, ...witness.public_key_x, ...witness.public_key_y]),
6794
+ Uint8Array.from(witness.signature),
6795
+ request
6796
+ ),
6797
+ "invalid wallet authorization"
6798
+ );
6799
+ return witness;
6980
6800
  }
6981
- topUpCredit(request) {
6982
- return {
6983
- to: this.context.protocolAddress,
6984
- value: 0n,
6985
- ...buildTopUpCreditCalldata({ ...request, context: this.context })
6986
- };
6801
+ async membership(leaf, input, sources) {
6802
+ const source = sources.findIndex((value) => value.treeId === input.treeId);
6803
+ check2(
6804
+ source >= 0 && Number.isInteger(input.leafIndex) && input.leafIndex >= 0 && input.leafIndex < 65536 && input.path.length === 16,
6805
+ "invalid membership position"
6806
+ );
6807
+ let root = BigInt(leaf);
6808
+ for (let level = 0; level < 16; level++)
6809
+ root = BigInt(
6810
+ await (0, import_core10.poseidonHash)(
6811
+ input.leafIndex >> level & 1 ? [input.path[level], root] : [root, input.path[level]]
6812
+ )
6813
+ );
6814
+ check2(root === BigInt(sources[source].merkleRoot), "membership root mismatch");
6815
+ return source;
6987
6816
  }
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);
6817
+ async noteLeaf(note) {
6818
+ this.context(note);
6819
+ return (0, import_core10.computeNoteCommitment)(
6820
+ note.chainId,
6821
+ await (0, import_core10.computeNoteIdentity)(BigInt(note.walletIdentity), note.nonce),
6822
+ note.tokenAddress,
6823
+ note.amount
6824
+ );
7002
6825
  }
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 } : {}
6826
+ async creditLeaf(note) {
6827
+ this.context(note);
6828
+ return (0, import_core10.computeCreditCommitment)(
6829
+ note.chainId,
6830
+ note.spenderWalletIdentity,
6831
+ note.ownerWalletIdentity,
6832
+ note.spenderPayout,
6833
+ note.ownerPayout,
6834
+ note.tokenAddress,
6835
+ note.amount,
6836
+ note.nonce,
6837
+ note.expiry,
6838
+ await (0, import_core10.computeCreditSharedKeyHash)(note.creditSharedKey)
7011
6839
  );
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
6840
  }
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");
6841
+ async noteInputs(inputs, sources, nullifiers, identity, authority) {
6842
+ check2(inputs.length === nullifiers.length, "input count mismatch");
6843
+ return Promise.all(
6844
+ inputs.map(async (input, i) => {
6845
+ check2(input.note.walletIdentity === identity, "input wallet mismatch");
6846
+ const leaf = await this.noteLeaf(input.note);
6847
+ check2(
6848
+ await (0, import_core10.computeNoteNullifier)(input.note.chainId, input.note.nonce, leaf) === nullifiers[i],
6849
+ "input nullifier mismatch"
6850
+ );
6851
+ return BigInt(await this.membership(leaf, input, sources));
6852
+ })
6853
+ );
6854
+ }
6855
+ async transact(p) {
6856
+ const c = this.#protocol.context, n = normalizeTransactRequest(c, p.params, p.deliveries, p.funding), words = transactUserPublicInputs(c, p.params, p.deliveries, p.funding);
6857
+ check2(
6858
+ p.inputs.length === n.inputCount && p.outputs.length === n.outputCount,
6859
+ "note count mismatch"
6860
+ );
6861
+ const identity = p.inputs[0]?.note.walletIdentity;
6862
+ const unsignedSweep = !!identity && !p.authorization && n.outputCount === 0 && n.depositAmount === 0n && BigInt(p.params.withdrawalAddress) === BigInt(identity);
6863
+ const authority = identity && !unsignedSweep ? await this.authority("transact", n.capacity, words, p.authorization, identity) : zeroAuthority();
6864
+ const sources = await this.noteInputs(
6865
+ p.inputs,
6866
+ p.params.sources,
6867
+ p.params.nullifiers,
6868
+ identity ?? "0x" + "00".repeat(32),
6869
+ authority
6870
+ );
6871
+ for (const [i, note] of p.outputs.entries())
6872
+ check2(
6873
+ await this.noteLeaf(note) === p.params.outputCommitments[i],
6874
+ "output commitment mismatch"
6875
+ );
6876
+ const all = [...p.inputs.map((input) => input.note), ...p.outputs];
6877
+ return provingRequest(
6878
+ `transact_user_slots${n.capacity}`,
6879
+ {
6880
+ wallet_identity: identity ? BigInt(identity) : 0n,
6881
+ ...authority,
6882
+ output_wallet_identities: pad2(
6883
+ [
6884
+ ...p.inputs.map(() => 0n),
6885
+ ...p.outputs.map((note) => BigInt(note.walletIdentity))
6886
+ ],
6887
+ n.capacity,
6888
+ () => 0n
6889
+ ),
6890
+ amounts: pad2(
6891
+ all.map((note) => note.amount),
6892
+ n.capacity,
6893
+ () => 0n
6894
+ ),
6895
+ nonces: pad2(
6896
+ all.map((note) => note.nonce),
6897
+ n.capacity,
6898
+ () => 0n
6899
+ ),
6900
+ leaf_indices: pad2(
6901
+ p.inputs.map((input) => BigInt(input.leafIndex)),
6902
+ n.capacity,
6903
+ () => 0n
6904
+ ),
6905
+ merkle_paths: pad2(
6906
+ p.inputs.map((input) => [...input.path]),
6907
+ n.capacity,
6908
+ zeros
6909
+ ),
6910
+ input_source_indices: pad2(sources, n.capacity, () => 0n)
6911
+ },
6912
+ words,
6913
+ p.target
6914
+ );
7036
6915
  }
7037
- aggregate(request) {
6916
+ async creation(p, operation, words) {
6917
+ const state = (0, import_core10.normalizeCreditDeliveryState)(p.state), note = state.note;
6918
+ check2(
6919
+ await this.creditLeaf(note) === p.params.creditCommitment && note.ownerPayout === BigInt(p.params.owner) && note.expiry === p.params.expiry,
6920
+ "Credit creation mismatch"
6921
+ );
6922
+ const authority = await this.authority(
6923
+ operation,
6924
+ 10,
6925
+ words,
6926
+ p.authorization,
6927
+ note.ownerWalletIdentity
6928
+ );
6929
+ const sources = await this.noteInputs(
6930
+ p.inputs,
6931
+ p.params.sources,
6932
+ p.params.nullifiers,
6933
+ note.ownerWalletIdentity,
6934
+ authority
6935
+ );
6936
+ if (p.change)
6937
+ check2(
6938
+ p.change.walletIdentity === note.ownerWalletIdentity && await this.noteLeaf(p.change) === p.params.changeCommitment,
6939
+ "change commitment mismatch"
6940
+ );
6941
+ else check2(BigInt(p.params.changeCommitment) === 0n, "missing change note");
7038
6942
  return {
7039
- to: this.context.protocolAddress,
7040
- value: 0n,
7041
- ...buildTransactAggregateCalldata({ ...request, context: this.context })
6943
+ ...authority,
6944
+ input_amounts: pad2(
6945
+ p.inputs.map((input) => input.note.amount),
6946
+ 10,
6947
+ () => 0n
6948
+ ),
6949
+ input_nonces: pad2(
6950
+ p.inputs.map((input) => input.note.nonce),
6951
+ 10,
6952
+ () => 0n
6953
+ ),
6954
+ leaf_indices: pad2(
6955
+ p.inputs.map((input) => BigInt(input.leafIndex)),
6956
+ 10,
6957
+ () => 0n
6958
+ ),
6959
+ merkle_paths: pad2(
6960
+ p.inputs.map((input) => [...input.path]),
6961
+ 10,
6962
+ zeros
6963
+ ),
6964
+ input_source_indices: pad2(sources, 10, () => 0n),
6965
+ spender_payout: note.spenderPayout,
6966
+ spender_wallet_identity: BigInt(note.spenderWalletIdentity),
6967
+ owner_wallet_identity: BigInt(note.ownerWalletIdentity),
6968
+ credit_amount: note.amount,
6969
+ credit_nonce: note.nonce,
6970
+ credit_shared_key: note.creditSharedKey,
6971
+ change_amount: p.change?.amount ?? 0n,
6972
+ change_nonce: p.change?.nonce ?? 0n
7042
6973
  };
7043
6974
  }
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 }
6975
+ async createCredit(p) {
6976
+ const words = createCreditPublicInputs(
6977
+ this.#protocol.context,
6978
+ p.params,
6979
+ p.deliveries,
6980
+ p.funding
6981
+ );
6982
+ return provingRequest(
6983
+ "create_credit",
6984
+ await this.creation(p, "create-credit", words),
6985
+ words
7049
6986
  );
7050
6987
  }
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");
6988
+ async cancelCredit(p) {
6989
+ const note = (0, import_core10.normalizeCreditDeliveryState)(p.input.state).note, leaf = await this.creditLeaf(note), c = this.#protocol.context;
6990
+ check2(
6991
+ await (0, import_core10.computeCreditNullifier)(c.chainId, note.creditSharedKey, leaf) === p.params.nullifier && note.amount === p.params.amount && note.ownerPayout === BigInt(p.params.owner),
6992
+ "Credit cancellation mismatch"
6993
+ );
6994
+ await this.membership(leaf, p.input, [p.params.source]);
6995
+ const words = cancelCreditPublicInputs(c, p.params), authority = await this.authority(
6996
+ "cancel-credit",
6997
+ 1,
6998
+ words,
6999
+ p.authorization,
7000
+ note.ownerWalletIdentity
7001
+ );
7002
+ return provingRequest(
7003
+ "credit_cancel",
7004
+ {
7005
+ ...authority,
7006
+ spender_payout: note.spenderPayout,
7007
+ spender_wallet_identity: BigInt(note.spenderWalletIdentity),
7008
+ owner_wallet_identity: BigInt(note.ownerWalletIdentity),
7009
+ input_nonce: note.nonce,
7010
+ expiry: note.expiry,
7011
+ credit_shared_key: note.creditSharedKey,
7012
+ leaf_index: BigInt(p.input.leafIndex),
7013
+ merkle_path: [...p.input.path]
7014
+ },
7015
+ words
7016
+ );
7088
7017
  }
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
7018
+ async drawCredit(p) {
7019
+ const c = this.#protocol.context, profile = selectCreditDrawCircuit(p.inputs.length), capacity = profile.maxSize;
7020
+ check2(
7021
+ p.inputs.length === p.amounts.length && p.inputs.length === p.params.nullifiers.length,
7022
+ "draw input count mismatch"
7023
+ );
7024
+ const notes2 = p.inputs.map((input) => (0, import_core10.normalizeCreditDeliveryState)(input.state).note), identity = notes2[0].spenderWalletIdentity;
7025
+ const words = creditDrawPublicInputs(c, p.params, p.deliveries), authority = await this.authority(
7026
+ "credit-draw",
7027
+ capacity,
7028
+ words,
7029
+ p.authorization,
7030
+ identity
7031
+ );
7032
+ const sourceIndices = await Promise.all(
7033
+ notes2.map(async (note, i) => {
7034
+ const leaf = await this.creditLeaf(note);
7035
+ check2(
7036
+ 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],
7037
+ "Credit draw mismatch"
7038
+ );
7039
+ return BigInt(await this.membership(leaf, p.inputs[i], p.params.sources));
7040
+ })
7041
+ );
7042
+ return provingRequest(
7043
+ profile.name,
7044
+ {
7045
+ ...authority,
7046
+ spender_wallet_identity: BigInt(identity),
7047
+ owner_payouts: pad2(
7048
+ notes2.map((note) => note.ownerPayout),
7049
+ capacity,
7050
+ () => 0n
7051
+ ),
7052
+ owner_wallet_identities: pad2(
7053
+ notes2.map((note) => BigInt(note.ownerWalletIdentity)),
7054
+ capacity,
7055
+ () => 0n
7056
+ ),
7057
+ input_amounts: pad2(
7058
+ notes2.map((note) => note.amount),
7059
+ capacity,
7060
+ () => 0n
7061
+ ),
7062
+ input_nonces: pad2(
7063
+ notes2.map((note) => note.nonce),
7064
+ capacity,
7065
+ () => 0n
7066
+ ),
7067
+ credit_shared_keys: pad2(
7068
+ notes2.map((note) => note.creditSharedKey),
7069
+ capacity,
7070
+ () => 0n
7071
+ ),
7072
+ leaf_indices: pad2(
7073
+ p.inputs.map((input) => BigInt(input.leafIndex)),
7074
+ capacity,
7075
+ () => 0n
7076
+ ),
7077
+ merkle_paths: pad2(
7078
+ p.inputs.map((input) => [...input.path]),
7079
+ capacity,
7080
+ zeros
7081
+ ),
7082
+ input_source_indices: pad2(sourceIndices, capacity, () => 0n),
7083
+ draw_amounts: pad2(p.amounts, capacity, () => 0n)
7084
+ },
7085
+ words
7101
7086
  );
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
7087
  }
7107
- if (r.withdrawalAmount !== total)
7108
- throw new Error("withdrawal must equal the full input balance");
7109
- return buildTransactCalldata({ ...p, deliveries: [] });
7110
- }
7088
+ async topUpCredit(p) {
7089
+ 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);
7090
+ for (const field2 of [
7091
+ "spenderWalletIdentity",
7092
+ "ownerWalletIdentity",
7093
+ "spenderPayout",
7094
+ "ownerPayout",
7095
+ "creditSharedKey"
7096
+ ])
7097
+ check2(old[field2] === note[field2], "Credit role or payout changed");
7098
+ check2(
7099
+ JSON.stringify(previous.ownerReceivingKeys) === JSON.stringify(next.ownerReceivingKeys) && JSON.stringify(previous.spenderReceivingKeys) === JSON.stringify(next.spenderReceivingKeys),
7100
+ "Credit receiving snapshots changed"
7101
+ );
7102
+ check2(
7103
+ old.amount < note.amount && old.expiry <= note.expiry && old.expiry === p.params.previousExpiry && (c.now === void 0 || old.expiry > c.now),
7104
+ "invalid Credit top-up"
7105
+ );
7106
+ check2(
7107
+ await (0, import_core10.computeCreditNullifier)(c.chainId, old.creditSharedKey, leaf) === p.params.creditNullifier,
7108
+ "previous Credit nullifier mismatch"
7109
+ );
7110
+ await this.membership(leaf, p.previous, [p.params.creditSource]);
7111
+ const words = topUpCreditPublicInputs(c, p.params, p.deliveries, p.funding), base = await this.creation({ ...p, params: p.params.creation }, "top-up-credit", words);
7112
+ return provingRequest(
7113
+ "credit_top_up",
7114
+ {
7115
+ ...base,
7116
+ previous_credit_amount: old.amount,
7117
+ previous_credit_nonce: old.nonce,
7118
+ previous_credit_leaf_index: BigInt(p.previous.leafIndex),
7119
+ previous_credit_merkle_path: [...p.previous.path]
7120
+ },
7121
+ words
7122
+ );
7123
+ }
7124
+ };
7111
7125
 
7112
7126
  // src/factory.ts
7113
7127
  var import_ethers10 = require("ethers");
@@ -7180,8 +7194,7 @@ async function resolveInstanceAddress(client, factoryAddress, salt) {
7180
7194
  normalizeTransactRequest,
7181
7195
  notes,
7182
7196
  pad,
7183
- registrationAuthorizationRequest,
7184
- registrationPublicInputs,
7197
+ registrationDigest,
7185
7198
  registrationTypedData,
7186
7199
  resolveInstanceAddress,
7187
7200
  selectCreditDrawCircuit,