@tokenops/sdk 2.0.0-alpha.2 → 2.0.0-alpha.3

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.
Files changed (80) hide show
  1. package/CHANGELOG.md +39 -3
  2. package/README.md +11 -5
  3. package/dist/{chunk-PZZK3O3S.cjs → chunk-4AWQJQXY.cjs} +391 -43
  4. package/dist/{chunk-SPLNGUFF.js → chunk-4IB4IY5Y.js} +1 -1
  5. package/dist/{chunk-A4DCEE33.js → chunk-6HCT4QIX.js} +11 -10
  6. package/dist/{chunk-MM5BV5CS.cjs → chunk-6XOAYDC6.cjs} +4 -4
  7. package/dist/{chunk-FEDX7B6T.cjs → chunk-AHU2HMNE.cjs} +3 -3
  8. package/dist/{chunk-IGO5XSPS.js → chunk-BPIVVCSQ.js} +2 -2
  9. package/dist/{chunk-X7WBPCEU.js → chunk-BXX5TETM.js} +375 -27
  10. package/dist/{chunk-GADGBQJO.js → chunk-GCJFAY4X.js} +2 -2
  11. package/dist/{chunk-IUKKNJ2R.cjs → chunk-GKYZQJGP.cjs} +7 -7
  12. package/dist/{chunk-3YHBO2DL.cjs → chunk-IEKTGJ4J.cjs} +2 -2
  13. package/dist/{chunk-UHHMVBLU.cjs → chunk-JVNJSDQ4.cjs} +2 -2
  14. package/dist/{chunk-VW356KR3.js → chunk-LEYYG4RF.js} +126 -3
  15. package/dist/{chunk-PYYSB5ZN.js → chunk-NGU4JYIR.js} +1 -1
  16. package/dist/{chunk-FT5H2Q7Y.cjs → chunk-PG3WXT3K.cjs} +11 -10
  17. package/dist/{chunk-44YJPMQC.js → chunk-PK6Q6J5F.js} +1 -1
  18. package/dist/{chunk-EBLBPUPI.cjs → chunk-TND5NDV7.cjs} +18 -10
  19. package/dist/{chunk-EYDA6Q6C.js → chunk-U3TBQRT7.js} +10 -2
  20. package/dist/{chunk-WJMEBBU7.js → chunk-WRWRA4TN.js} +1 -1
  21. package/dist/{chunk-FHWSBGWE.cjs → chunk-YABHXJNH.cjs} +5 -5
  22. package/dist/{chunk-AREQJHKA.cjs → chunk-YTIYTV4K.cjs} +129 -2
  23. package/dist/core/addresses.d.ts +4 -4
  24. package/dist/core/errors.d.ts +1 -1
  25. package/dist/fhe-airdrop/abis/airdrop-base.d.ts +19 -0
  26. package/dist/fhe-airdrop/abis/ecdsa.d.ts +19 -0
  27. package/dist/fhe-airdrop/abis/factory.d.ts +113 -0
  28. package/dist/fhe-airdrop/abis/merkle.d.ts +19 -0
  29. package/dist/fhe-airdrop/advanced/index.cjs +4 -4
  30. package/dist/fhe-airdrop/advanced/index.js +1 -1
  31. package/dist/fhe-airdrop/advanced/react/index.cjs +110 -80
  32. package/dist/fhe-airdrop/advanced/react/index.d.cts +1 -0
  33. package/dist/fhe-airdrop/advanced/react/index.d.ts +1 -0
  34. package/dist/fhe-airdrop/advanced/react/index.js +34 -5
  35. package/dist/fhe-airdrop/advanced/react/useDisableCustomFee.d.ts +2 -1
  36. package/dist/fhe-airdrop/advanced/react/useFactoryRenounceRole.d.ts +4 -3
  37. package/dist/fhe-airdrop/advanced/react/useFactoryRevokeRole.d.ts +9 -7
  38. package/dist/fhe-airdrop/advanced/react/useFactoryRoleMembers.d.ts +6 -5
  39. package/dist/fhe-airdrop/advanced/react/useSetCustomFee.d.ts +2 -1
  40. package/dist/fhe-airdrop/advanced/react/useSetDefaultGasFee.d.ts +5 -3
  41. package/dist/fhe-airdrop/advanced/react/useSetMaxGasFee.d.ts +33 -0
  42. package/dist/fhe-airdrop/airdrop-base.d.ts +47 -8
  43. package/dist/fhe-airdrop/constants.d.ts +9 -1
  44. package/dist/fhe-airdrop/ecdsa.d.ts +13 -0
  45. package/dist/fhe-airdrop/errors.d.ts +59 -0
  46. package/dist/fhe-airdrop/factory.d.ts +62 -22
  47. package/dist/fhe-airdrop/guards.d.ts +87 -2
  48. package/dist/fhe-airdrop/index.cjs +67 -55
  49. package/dist/fhe-airdrop/index.d.cts +3 -3
  50. package/dist/fhe-airdrop/index.d.ts +3 -3
  51. package/dist/fhe-airdrop/index.js +4 -4
  52. package/dist/fhe-airdrop/react/index.cjs +237 -177
  53. package/dist/fhe-airdrop/react/index.d.cts +4 -1
  54. package/dist/fhe-airdrop/react/index.d.ts +4 -1
  55. package/dist/fhe-airdrop/react/index.js +72 -15
  56. package/dist/fhe-airdrop/react/keys.d.ts +8 -0
  57. package/dist/fhe-airdrop/react/useFactoryFees.d.ts +11 -4
  58. package/dist/fhe-airdrop/react/useIsAirdrop.d.ts +44 -0
  59. package/dist/fhe-airdrop/react/useRefreshComplianceBalance.d.ts +36 -0
  60. package/dist/fhe-airdrop/react/useResolveGasFee.d.ts +30 -0
  61. package/dist/fhe-airdrop/types.d.ts +13 -0
  62. package/dist/fhe-disperse/index.cjs +21 -21
  63. package/dist/fhe-disperse/index.js +2 -2
  64. package/dist/fhe-disperse/react/index.cjs +22 -22
  65. package/dist/fhe-disperse/react/index.js +3 -3
  66. package/dist/fhe-vesting/advanced/index.cjs +5 -5
  67. package/dist/fhe-vesting/advanced/index.js +3 -3
  68. package/dist/fhe-vesting/advanced/react/index.cjs +7 -7
  69. package/dist/fhe-vesting/advanced/react/index.js +4 -4
  70. package/dist/fhe-vesting/index.cjs +8 -8
  71. package/dist/fhe-vesting/index.js +2 -2
  72. package/dist/fhe-vesting/react/index.cjs +114 -114
  73. package/dist/fhe-vesting/react/index.js +3 -3
  74. package/dist/index.cjs +18 -18
  75. package/dist/index.js +1 -1
  76. package/dist/testnet-faucet/index.cjs +14 -14
  77. package/dist/testnet-faucet/index.js +2 -2
  78. package/dist/testnet-faucet/react/index.cjs +8 -8
  79. package/dist/testnet-faucet/react/index.js +3 -3
  80. package/package.json +1 -1
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
- var chunkAREQJHKA_cjs = require('./chunk-AREQJHKA.cjs');
3
+ var chunkYTIYTV4K_cjs = require('./chunk-YTIYTV4K.cjs');
4
4
  var chunkFAXIIH5R_cjs = require('./chunk-FAXIIH5R.cjs');
5
5
  var chunkUG5RKLU2_cjs = require('./chunk-UG5RKLU2.cjs');
6
6
  var chunkMVDQMV25_cjs = require('./chunk-MVDQMV25.cjs');
7
- var chunkFT5H2Q7Y_cjs = require('./chunk-FT5H2Q7Y.cjs');
7
+ var chunkPG3WXT3K_cjs = require('./chunk-PG3WXT3K.cjs');
8
8
  var chunkJK4XMMKM_cjs = require('./chunk-JK4XMMKM.cjs');
9
9
  var chunk66IHPTOK_cjs = require('./chunk-66IHPTOK.cjs');
10
10
  var chunk67OV5CX2_cjs = require('./chunk-67OV5CX2.cjs');
@@ -71,6 +71,11 @@ var airdropFactoryAbi = [
71
71
  internalType: "uint96",
72
72
  name: "defaultGasFee_",
73
73
  type: "uint96"
74
+ },
75
+ {
76
+ internalType: "uint96",
77
+ name: "maxGasFee_",
78
+ type: "uint96"
74
79
  }
75
80
  ],
76
81
  stateMutability: "nonpayable",
@@ -175,6 +180,38 @@ var airdropFactoryAbi = [
175
180
  name: "FailedDeployment",
176
181
  type: "error"
177
182
  },
183
+ {
184
+ inputs: [
185
+ {
186
+ internalType: "uint96",
187
+ name: "gasFee",
188
+ type: "uint96"
189
+ },
190
+ {
191
+ internalType: "uint96",
192
+ name: "maxGasFee",
193
+ type: "uint96"
194
+ }
195
+ ],
196
+ name: "GasFeeExceedsMaximum",
197
+ type: "error"
198
+ },
199
+ {
200
+ inputs: [
201
+ {
202
+ internalType: "uint96",
203
+ name: "resolvedFee",
204
+ type: "uint96"
205
+ },
206
+ {
207
+ internalType: "uint96",
208
+ name: "maxAcceptedGasFee",
209
+ type: "uint96"
210
+ }
211
+ ],
212
+ name: "GasFeeNotAccepted",
213
+ type: "error"
214
+ },
178
215
  {
179
216
  inputs: [
180
217
  {
@@ -393,6 +430,11 @@ var airdropFactoryAbi = [
393
430
  name: "ZeroToken",
394
431
  type: "error"
395
432
  },
433
+ {
434
+ inputs: [],
435
+ name: "ZeroUnwrapRequestId",
436
+ type: "error"
437
+ },
396
438
  {
397
439
  anonymous: false,
398
440
  inputs: [
@@ -425,6 +467,12 @@ var airdropFactoryAbi = [
425
467
  internalType: "uint256",
426
468
  name: "deploymentBlockNumber",
427
469
  type: "uint256"
470
+ },
471
+ {
472
+ indexed: false,
473
+ internalType: "uint256",
474
+ name: "gasFee",
475
+ type: "uint256"
428
476
  }
429
477
  ],
430
478
  name: "AirdropInitialized",
@@ -929,6 +977,19 @@ var airdropFactoryAbi = [
929
977
  name: "SetDefaultGasFee",
930
978
  type: "event"
931
979
  },
980
+ {
981
+ anonymous: false,
982
+ inputs: [
983
+ {
984
+ indexed: false,
985
+ internalType: "uint256",
986
+ name: "maxGasFee",
987
+ type: "uint256"
988
+ }
989
+ ],
990
+ name: "SetMaxGasFee",
991
+ type: "event"
992
+ },
932
993
  {
933
994
  anonymous: false,
934
995
  inputs: [
@@ -1220,6 +1281,11 @@ var airdropFactoryAbi = [
1220
1281
  internalType: "address",
1221
1282
  name: "complianceAdmin",
1222
1283
  type: "address"
1284
+ },
1285
+ {
1286
+ internalType: "uint96",
1287
+ name: "maxAcceptedGasFee",
1288
+ type: "uint96"
1223
1289
  }
1224
1290
  ],
1225
1291
  internalType: "struct IAirdropFactory.CommonAirdropParams",
@@ -1308,6 +1374,11 @@ var airdropFactoryAbi = [
1308
1374
  internalType: "address",
1309
1375
  name: "complianceAdmin",
1310
1376
  type: "address"
1377
+ },
1378
+ {
1379
+ internalType: "uint96",
1380
+ name: "maxAcceptedGasFee",
1381
+ type: "uint96"
1311
1382
  }
1312
1383
  ],
1313
1384
  internalType: "struct IAirdropFactory.CommonAirdropParams",
@@ -1396,6 +1467,11 @@ var airdropFactoryAbi = [
1396
1467
  internalType: "address",
1397
1468
  name: "complianceAdmin",
1398
1469
  type: "address"
1470
+ },
1471
+ {
1472
+ internalType: "uint96",
1473
+ name: "maxAcceptedGasFee",
1474
+ type: "uint96"
1399
1475
  }
1400
1476
  ],
1401
1477
  internalType: "struct IAirdropFactory.CommonAirdropParams",
@@ -1474,6 +1550,11 @@ var airdropFactoryAbi = [
1474
1550
  internalType: "address",
1475
1551
  name: "complianceAdmin",
1476
1552
  type: "address"
1553
+ },
1554
+ {
1555
+ internalType: "uint96",
1556
+ name: "maxAcceptedGasFee",
1557
+ type: "uint96"
1477
1558
  }
1478
1559
  ],
1479
1560
  internalType: "struct IAirdropFactory.CommonAirdropParams",
@@ -1740,6 +1821,11 @@ var airdropFactoryAbi = [
1740
1821
  internalType: "address",
1741
1822
  name: "complianceAdmin",
1742
1823
  type: "address"
1824
+ },
1825
+ {
1826
+ internalType: "uint96",
1827
+ name: "maxAcceptedGasFee",
1828
+ type: "uint96"
1743
1829
  }
1744
1830
  ],
1745
1831
  internalType: "struct IAirdropFactory.CommonAirdropParams",
@@ -1813,6 +1899,11 @@ var airdropFactoryAbi = [
1813
1899
  internalType: "address",
1814
1900
  name: "complianceAdmin",
1815
1901
  type: "address"
1902
+ },
1903
+ {
1904
+ internalType: "uint96",
1905
+ name: "maxAcceptedGasFee",
1906
+ type: "uint96"
1816
1907
  }
1817
1908
  ],
1818
1909
  internalType: "struct IAirdropFactory.CommonAirdropParams",
@@ -2005,6 +2096,38 @@ var airdropFactoryAbi = [
2005
2096
  stateMutability: "view",
2006
2097
  type: "function"
2007
2098
  },
2099
+ {
2100
+ inputs: [
2101
+ {
2102
+ internalType: "address",
2103
+ name: "candidate",
2104
+ type: "address"
2105
+ }
2106
+ ],
2107
+ name: "isAirdrop",
2108
+ outputs: [
2109
+ {
2110
+ internalType: "bool",
2111
+ name: "",
2112
+ type: "bool"
2113
+ }
2114
+ ],
2115
+ stateMutability: "view",
2116
+ type: "function"
2117
+ },
2118
+ {
2119
+ inputs: [],
2120
+ name: "maxGasFee",
2121
+ outputs: [
2122
+ {
2123
+ internalType: "uint256",
2124
+ name: "",
2125
+ type: "uint256"
2126
+ }
2127
+ ],
2128
+ stateMutability: "view",
2129
+ type: "function"
2130
+ },
2008
2131
  {
2009
2132
  inputs: [],
2010
2133
  name: "merkleImplementation",
@@ -2053,6 +2176,11 @@ var airdropFactoryAbi = [
2053
2176
  internalType: "address",
2054
2177
  name: "complianceAdmin",
2055
2178
  type: "address"
2179
+ },
2180
+ {
2181
+ internalType: "uint96",
2182
+ name: "maxAcceptedGasFee",
2183
+ type: "uint96"
2056
2184
  }
2057
2185
  ],
2058
2186
  internalType: "struct IAirdropFactory.CommonAirdropParams",
@@ -2136,6 +2264,11 @@ var airdropFactoryAbi = [
2136
2264
  internalType: "address",
2137
2265
  name: "complianceAdmin",
2138
2266
  type: "address"
2267
+ },
2268
+ {
2269
+ internalType: "uint96",
2270
+ name: "maxAcceptedGasFee",
2271
+ type: "uint96"
2139
2272
  }
2140
2273
  ],
2141
2274
  internalType: "struct IAirdropFactory.CommonAirdropParams",
@@ -2347,6 +2480,19 @@ var airdropFactoryAbi = [
2347
2480
  stateMutability: "nonpayable",
2348
2481
  type: "function"
2349
2482
  },
2483
+ {
2484
+ inputs: [
2485
+ {
2486
+ internalType: "uint96",
2487
+ name: "maxGasFee_",
2488
+ type: "uint96"
2489
+ }
2490
+ ],
2491
+ name: "setMaxGasFee",
2492
+ outputs: [],
2493
+ stateMutability: "nonpayable",
2494
+ type: "function"
2495
+ },
2350
2496
  {
2351
2497
  inputs: [
2352
2498
  {
@@ -2765,6 +2911,11 @@ var ecdsaConfidentialAirdropAbi = [
2765
2911
  name: "ZeroToken",
2766
2912
  type: "error"
2767
2913
  },
2914
+ {
2915
+ inputs: [],
2916
+ name: "ZeroUnwrapRequestId",
2917
+ type: "error"
2918
+ },
2768
2919
  {
2769
2920
  anonymous: false,
2770
2921
  inputs: [
@@ -2797,6 +2948,12 @@ var ecdsaConfidentialAirdropAbi = [
2797
2948
  internalType: "uint256",
2798
2949
  name: "deploymentBlockNumber",
2799
2950
  type: "uint256"
2951
+ },
2952
+ {
2953
+ indexed: false,
2954
+ internalType: "uint256",
2955
+ name: "gasFee",
2956
+ type: "uint256"
2800
2957
  }
2801
2958
  ],
2802
2959
  name: "AirdropInitialized",
@@ -3909,6 +4066,19 @@ var ecdsaConfidentialAirdropAbi = [
3909
4066
  stateMutability: "view",
3910
4067
  type: "function"
3911
4068
  },
4069
+ {
4070
+ inputs: [],
4071
+ name: "refreshComplianceBalance",
4072
+ outputs: [
4073
+ {
4074
+ internalType: "euint64",
4075
+ name: "balance",
4076
+ type: "bytes32"
4077
+ }
4078
+ ],
4079
+ stateMutability: "nonpayable",
4080
+ type: "function"
4081
+ },
3912
4082
  {
3913
4083
  inputs: [
3914
4084
  {
@@ -4296,6 +4466,11 @@ var confidentialAirdropBaseAbi = [
4296
4466
  name: "ZeroToken",
4297
4467
  type: "error"
4298
4468
  },
4469
+ {
4470
+ inputs: [],
4471
+ name: "ZeroUnwrapRequestId",
4472
+ type: "error"
4473
+ },
4299
4474
  {
4300
4475
  anonymous: false,
4301
4476
  inputs: [
@@ -4328,6 +4503,12 @@ var confidentialAirdropBaseAbi = [
4328
4503
  internalType: "uint256",
4329
4504
  name: "deploymentBlockNumber",
4330
4505
  type: "uint256"
4506
+ },
4507
+ {
4508
+ indexed: false,
4509
+ internalType: "uint256",
4510
+ name: "gasFee",
4511
+ type: "uint256"
4331
4512
  }
4332
4513
  ],
4333
4514
  name: "AirdropInitialized",
@@ -4804,6 +4985,19 @@ var confidentialAirdropBaseAbi = [
4804
4985
  stateMutability: "nonpayable",
4805
4986
  type: "function"
4806
4987
  },
4988
+ {
4989
+ inputs: [],
4990
+ name: "refreshComplianceBalance",
4991
+ outputs: [
4992
+ {
4993
+ internalType: "euint64",
4994
+ name: "balance",
4995
+ type: "bytes32"
4996
+ }
4997
+ ],
4998
+ stateMutability: "nonpayable",
4999
+ type: "function"
5000
+ },
4807
5001
  {
4808
5002
  inputs: [
4809
5003
  {
@@ -5101,7 +5295,7 @@ var AirdropBaseClient = class {
5101
5295
  clientLabel: "AirdropBaseClient"
5102
5296
  });
5103
5297
  }
5104
- chunkAREQJHKA_cjs.assertSupportedChain(chainId);
5298
+ chunkYTIYTV4K_cjs.assertSupportedChain(chainId);
5105
5299
  this.chainId = chainId;
5106
5300
  this.address = chunkJK4XMMKM_cjs.normaliseAddress(config.address);
5107
5301
  this.aclAddress = config.aclAddress ? chunkJK4XMMKM_cjs.normaliseAddress(config.aclAddress) : chunkFAXIIH5R_cjs.requireFhevmAclAddress(chainId, "AirdropBaseClient");
@@ -5203,8 +5397,12 @@ var AirdropBaseClient = class {
5203
5397
  * Sweep a plain ERC-20 that was sent to the instance by mistake. Requires
5204
5398
  * `RESCUER_ROLE`.
5205
5399
  *
5206
- * The campaign's own token is ERC-7984, not ERC-20, so it cannot be reached
5207
- * through this path — use {@link withdrawConfidential} for the pool.
5400
+ * Passing the campaign's own token reverts `CannotRescueAirdropToken`
5401
+ * (audit-05), matching {@link rescueOtherConfidentialToken}. ERC-7984 and
5402
+ * ERC-20 are not disjoint in practice - a wrapper token answers both
5403
+ * interfaces - so "the pool token is confidential, therefore out of reach
5404
+ * here" was never a guarantee, only an assumption. Use
5405
+ * {@link withdrawConfidential} for the pool.
5208
5406
  *
5209
5407
  * @returns The transaction hash.
5210
5408
  */
@@ -5564,17 +5762,56 @@ var AirdropBaseClient = class {
5564
5762
  // DISCLOSURE (ENCRYPTED)
5565
5763
  // ============================================================
5566
5764
  //
5567
- // The first three read like getters and are `nonpayable` in the ABI: they
5765
+ // The first four read like getters and are `nonpayable` in the ABI: they
5568
5766
  // call `FHE.allow`, which writes ACL state. They therefore submit a
5569
5767
  // transaction and recover their `euint64` result from the receipt — never
5570
5768
  // from a simulation. See `extractGrantedHandle`.
5571
5769
  //
5770
+ // Three of those four grant the CALLER; `refreshComplianceBalance` grants the
5771
+ // compliance clone instead, which is why it resolves the clone address and
5772
+ // passes it as `grantee`.
5773
+ //
5572
5774
  // The last two return nothing on-chain and are ordinary writes: they grant a
5573
5775
  // handle the caller already has, so there is no new handle to recover.
5776
+ /**
5777
+ * Re-grant the compliance-manager clone on the instance's current pool
5778
+ * balance, and return the handle it was granted on.
5779
+ *
5780
+ * **Permissionless, and deliberately so** (audit-04). The token rotates the
5781
+ * instance's balance handle on every incoming transfer, including one no
5782
+ * airdrop code observes - a third party transferring in directly - and
5783
+ * grants the fresh handle to the token and the holder only. Without this the
5784
+ * compliance clone's grant can be stranded on a handle the token has already
5785
+ * replaced, with no admin necessarily around to restore it. There is no
5786
+ * argument to abuse: the only handle read is `address(this)`'s own balance,
5787
+ * and the only grantee is the clone wired at initialization.
5788
+ *
5789
+ * This is therefore the normative way to obtain a readable live-balance
5790
+ * handle - and it is a **snapshot, not a subscription**. Grants are
5791
+ * append-only, so the handle this returns stays readable forever; but the
5792
+ * next incoming transfer rotates the instance to a NEW handle the clone was
5793
+ * never granted on. A compliance reader that refreshes once and stops is
5794
+ * reading a stale balance, not a live one. Call it again after any transfer
5795
+ * in, or before each read.
5796
+ *
5797
+ * @returns `{ handle, hash }` - the handle the compliance clone may now decrypt.
5798
+ * @throws {@link ReceiptEventNotFoundError} when the transaction granted no ACL to the clone.
5799
+ */
5800
+ async refreshComplianceBalance(args = {}) {
5801
+ const grantee = await this.complianceManager();
5802
+ return this.encryptedView({
5803
+ functionName: "refreshComplianceBalance",
5804
+ grantee,
5805
+ account: args.account
5806
+ });
5807
+ }
5574
5808
  /**
5575
5809
  * Read the instance's own remaining pool balance as a handle the **caller**
5576
5810
  * can decrypt. Requires `DISCLOSURE_ADMIN_ROLE`.
5577
5811
  *
5812
+ * Also re-grants the compliance-manager clone on the same handle (audit-04),
5813
+ * so an admin read doubles as a {@link refreshComplianceBalance}.
5814
+ *
5578
5815
  * @returns `{ handle, hash }` — pass `handle` to the Zama relayer's `userDecrypt`.
5579
5816
  * @throws {@link ReceiptEventNotFoundError} when the transaction granted no ACL to the caller.
5580
5817
  */
@@ -5650,11 +5887,18 @@ var AirdropBaseClient = class {
5650
5887
  /**
5651
5888
  * Grant `party` decrypt access to a handle you already hold.
5652
5889
  *
5653
- * Two gates apply on-chain: the caller must itself be allowed on the handle
5654
- * (bypassed by `DISCLOSURE_ADMIN_ROLE`), and the *instance* must be allowed
5655
- * on it — so an arbitrary handle from another contract cannot be laundered
5656
- * through this campaign. A failure of the first surfaces as
5657
- * `FheHandleNotAllowedError`.
5890
+ * Two gates apply on-chain. Gate #1: the handle must be **persistently**
5891
+ * user-decryptable in the `(caller, instance)` context - BOTH legs, and a
5892
+ * transient allowance does not satisfy either (audit-06). `DISCLOSURE_ADMIN_ROLE`
5893
+ * bypasses gate #1 only. Gate #2: the instance must be allowed on the handle,
5894
+ * so an arbitrary handle from another contract cannot be laundered through
5895
+ * this campaign.
5896
+ *
5897
+ * **The transient case is the trap.** An `euint64` that just came back from
5898
+ * an FHE op carries a transient allowance, which used to be enough here and
5899
+ * no longer is. Handles worth disclosing come from the encrypted views on
5900
+ * this client, whose grants are persistent. A gate #1 failure surfaces as
5901
+ * `FheHandleNotAllowedError` carrying the offending handle.
5658
5902
  *
5659
5903
  * @param args.handle An existing `euint64` handle — a public pointer, not a value.
5660
5904
  * @returns The transaction hash. No new handle is produced.
@@ -5788,7 +6032,7 @@ var AirdropBaseClient = class {
5788
6032
  method,
5789
6033
  contractAddress: this.address,
5790
6034
  abi: this.abi,
5791
- productMapper: chunkAREQJHKA_cjs.airdropProductMapper,
6035
+ productMapper: chunkYTIYTV4K_cjs.airdropProductMapper,
5792
6036
  account: accountAddress(account),
5793
6037
  productContext: {
5794
6038
  creator: accountAddress(account),
@@ -5924,11 +6168,24 @@ var EcdsaAirdropClient = class extends AirdropBaseClient {
5924
6168
  * consuming either replay guard — the same input can still be claimed for
5925
6169
  * real afterwards. No fee.
5926
6170
  *
6171
+ * **It is repeatable, not unconditional** (audit-07). While the claim is
6172
+ * still available this may be called any number of times; once it is not,
6173
+ * this reverts with the same error the consuming claim would raise, in the
6174
+ * same order: the mode's dedup slot first (`AddressAlreadyClaimed` /
6175
+ * `DedupIdAlreadyClaimed`), the EIP-712 digest second (`SignatureAlreadyUsed`).
6176
+ * A rejected preview performs no FHE op, grants no ACL and emits nothing.
6177
+ *
6178
+ * So this is not a probe for "has this been claimed" - use
6179
+ * {@link isSignatureValid}, which never reverts and answers the same
6180
+ * question for free. Reach for this when you want the AMOUNT.
6181
+ *
5927
6182
  * An encrypted view: the contract calls `FHE.allow(amount, msg.sender)`, so
5928
6183
  * the result is recovered from the receipt's ACL `Allowed` event, never
5929
6184
  * from a simulation. See {@link AirdropBaseClient}'s class TSDoc.
5930
6185
  *
5931
6186
  * @returns `{ handle, hash }` — pass `handle` to the Zama relayer's `userDecrypt`.
6187
+ * @throws {@link AlreadyClaimedError} when this recipient's dedup slot is consumed.
6188
+ * @throws {@link DedupIdConsumedError} when this `dedupId`'s slot is consumed.
5932
6189
  */
5933
6190
  async getClaimAmount(args) {
5934
6191
  return this.encryptedView({
@@ -6119,7 +6376,7 @@ async function signClaimAuthorization(args) {
6119
6376
  return chunk66IHPTOK_cjs.asSignature(sig);
6120
6377
  }
6121
6378
  function toDeploymentModeOrdinal(mode) {
6122
- return chunkAREQJHKA_cjs.DEPLOYMENT_MODE[mode];
6379
+ return chunkYTIYTV4K_cjs.DEPLOYMENT_MODE[mode];
6123
6380
  }
6124
6381
  function toContractCommonParams(common) {
6125
6382
  return {
@@ -6128,14 +6385,15 @@ function toContractCommonParams(common) {
6128
6385
  endTime: common.endTime,
6129
6386
  canExtendClaimWindow: common.canExtendClaimWindow,
6130
6387
  unwrappable: common.unwrappable,
6131
- complianceAdmin: common.complianceAdmin
6388
+ complianceAdmin: common.complianceAdmin,
6389
+ maxAcceptedGasFee: common.maxAcceptedGasFee
6132
6390
  };
6133
6391
  }
6134
6392
  function toContractEcdsaParams(params) {
6135
6393
  return {
6136
6394
  common: toContractCommonParams(params.common),
6137
6395
  signer: params.signer,
6138
- dedupMode: chunkAREQJHKA_cjs.DEDUP_MODE[params.dedupMode]
6396
+ dedupMode: chunkYTIYTV4K_cjs.DEDUP_MODE[params.dedupMode]
6139
6397
  };
6140
6398
  }
6141
6399
  function toContractMerkleParams(params) {
@@ -6166,9 +6424,9 @@ var ConfidentialAirdropFactoryClient = class {
6166
6424
  clientLabel: "ConfidentialAirdropFactoryClient"
6167
6425
  });
6168
6426
  }
6169
- chunkAREQJHKA_cjs.assertSupportedChain(chainId);
6427
+ chunkYTIYTV4K_cjs.assertSupportedChain(chainId);
6170
6428
  this.chainId = chainId;
6171
- this.address = config.address ? chunkJK4XMMKM_cjs.normaliseAddress(config.address) : chunkFT5H2Q7Y_cjs.requireFheAirdropFactoryAddress(chainId);
6429
+ this.address = config.address ? chunkJK4XMMKM_cjs.normaliseAddress(config.address) : chunkPG3WXT3K_cjs.requireFheAirdropFactoryAddress(chainId);
6172
6430
  this.#telemetry = config.telemetry;
6173
6431
  this.#telemetry?.event("fhe-airdrop.client.init", {
6174
6432
  surface: "factory",
@@ -6239,7 +6497,7 @@ var ConfidentialAirdropFactoryClient = class {
6239
6497
  * @throws {@link InvalidArgumentError} when the root is zero and `isMerkleRootMutable` is false, or the salt was already used.
6240
6498
  */
6241
6499
  async createMerkleAirdrop(args) {
6242
- chunkAREQJHKA_cjs.assertMerkleModeSupported(args.mode);
6500
+ chunkYTIYTV4K_cjs.assertMerkleModeSupported(args.mode);
6243
6501
  return chunkVJKZWYYJ_cjs.withTelemetry(this.#telemetry, "fhe-airdrop.factory.createMerkleAirdrop", async () => {
6244
6502
  const method = "createMerkleAirdrop";
6245
6503
  const account = this.#senderFor(args.account, method);
@@ -6331,7 +6589,7 @@ var ConfidentialAirdropFactoryClient = class {
6331
6589
  * @throws {@link MissingEncryptorError} when `amount` is given and no encryptor is resolvable.
6332
6590
  */
6333
6591
  async createAndFundMerkleAirdrop(args) {
6334
- chunkAREQJHKA_cjs.assertMerkleModeSupported(args.mode);
6592
+ chunkYTIYTV4K_cjs.assertMerkleModeSupported(args.mode);
6335
6593
  return chunkVJKZWYYJ_cjs.withTelemetry(
6336
6594
  this.#telemetry,
6337
6595
  "fhe-airdrop.factory.createAndFundMerkleAirdrop",
@@ -6485,11 +6743,28 @@ var ConfidentialAirdropFactoryClient = class {
6485
6743
  async airdrops(offset, limit) {
6486
6744
  return this.#read("airdrops", [offset, limit]);
6487
6745
  }
6746
+ /**
6747
+ * Whether THIS factory created `candidate` - the genuineness check (audit-10).
6748
+ *
6749
+ * Nothing observable at an instance proves which factory, if any, deployed
6750
+ * it: an attacker can deploy a contract with the same ABI, the same events
6751
+ * and a pool it controls. The only trustworthy question is whether the
6752
+ * canonical factory's own registry contains the address, which is why this
6753
+ * read has to be addressed to a factory taken from
6754
+ * `src/core/addresses.ts` rather than one the instance names.
6755
+ *
6756
+ * @param candidate The address to check.
6757
+ * @returns True when this factory's registry contains `candidate`.
6758
+ */
6759
+ async isAirdrop(candidate) {
6760
+ return this.#read("isAirdrop", [candidate]);
6761
+ }
6488
6762
  /**
6489
6763
  * The compliance-manager clone bound to an instance.
6490
6764
  *
6491
- * Doubles as a provenance check: the factory records this mapping only for
6492
- * instances it deployed, so a zero address means the instance is not ours.
6765
+ * Doubles as a provenance check, though a weaker one than {@link isAirdrop}:
6766
+ * the factory records this mapping only for instances it deployed, so a zero
6767
+ * address means the instance is not ours.
6493
6768
  *
6494
6769
  * @param airdrop Instance address.
6495
6770
  * @returns The clone address, or the zero address when unknown to this factory.
@@ -6543,6 +6818,47 @@ var ConfidentialAirdropFactoryClient = class {
6543
6818
  async defaultGasFee() {
6544
6819
  return this.#read("defaultGasFee");
6545
6820
  }
6821
+ /** The factory's own ceiling on every configurable fee and every create-time resolved fee. */
6822
+ async maxGasFee() {
6823
+ return this.#read("maxGasFee");
6824
+ }
6825
+ /**
6826
+ * Set the factory's ceiling on every fee `setDefaultGasFee`/`setCustomFee`
6827
+ * may configure, and on the fee resolved at create.
6828
+ *
6829
+ * Requires `DEFAULT_ADMIN_ROLE`, deliberately not `FEE_MANAGER_ROLE`: the fee
6830
+ * manager moves fees only within a bound the admin controls. `0n` admits a
6831
+ * zero fee and nothing else.
6832
+ *
6833
+ * Lowering it below an already-configured fee does not rewrite that fee - the
6834
+ * stale value stays in storage and reverts `GasFeeExceedsMaximum` at the next
6835
+ * create until it is lowered too.
6836
+ *
6837
+ * @throws {@link InvalidArgumentError} when `maxGasFee` is below a currently configured fee (`GasFeeExceedsMaximum`).
6838
+ */
6839
+ async setMaxGasFee(maxGasFee, account) {
6840
+ return this.#write("setMaxGasFee", [maxGasFee], account, "setMaxGasFee");
6841
+ }
6842
+ /**
6843
+ * The per-claim fee a `create*` from `creator` would freeze into the new
6844
+ * instance right now: their {@link getCustomFee} override when enabled, else
6845
+ * {@link defaultGasFee}.
6846
+ *
6847
+ * This is the number `CommonAirdropParams.maxAcceptedGasFee` is checked
6848
+ * against, so it is also what to show a creator before they choose a bound.
6849
+ * It is a snapshot, not a quote: `FEE_MANAGER_ROLE` can move it between this
6850
+ * read and the create, which is exactly what the bound exists to catch.
6851
+ *
6852
+ * @param creator The account that will send `create*`.
6853
+ * @returns The resolved fee in wei.
6854
+ */
6855
+ async resolveGasFee(creator) {
6856
+ const [custom, fallback] = await Promise.all([
6857
+ this.getCustomFee(creator),
6858
+ this.defaultGasFee()
6859
+ ]);
6860
+ return custom.enabled ? custom.gasFee : fallback;
6861
+ }
6546
6862
  // ----------------------- implementation admin -----------------------
6547
6863
  /**
6548
6864
  * Point future `createEcdsaAirdrop*` calls at a new ECDSA implementation.
@@ -6807,17 +7123,15 @@ var ConfidentialAirdropFactoryClient = class {
6807
7123
  /**
6808
7124
  * Revoke `role` from `holder`. Requires the role's admin role.
6809
7125
  *
6810
- * Unlike an airdrop instance, the factory declares no "never empty" floor:
6811
- * revoking the last `DEFAULT_ADMIN_ROLE` member succeeds, and what it
6812
- * freezes is **role administration**, permanently. `DEFAULT_ADMIN_ROLE`
6813
- * administers all four operational roles and itself, so with the set empty
6814
- * no role can ever be granted or revoked again - including putting an admin
6815
- * back. The four operational roles keep working for whoever already holds
6816
- * them: a `FEE_MANAGER_ROLE` holder can still call {@link setDefaultGasFee},
6817
- * an `IMPL_MANAGER_ROLE` holder can still rotate an implementation. The
6818
- * factory therefore keeps running with exactly the role holders it had at
6819
- * that moment, with no way to rotate or remove them. Grant the successor
6820
- * first.
7126
+ * **The factory floors `DEFAULT_ADMIN_ROLE` at one live member** (audit-14),
7127
+ * matching the instances. Renouncing or revoking the sole holder reverts
7128
+ * `LastAdmin`, and granting the role to the zero address reverts
7129
+ * `ZeroAdminGrant`, so the set can neither be emptied nor satisfied by a
7130
+ * member nobody controls. Before audit-14 this succeeded and froze role
7131
+ * administration permanently; it no longer does.
7132
+ *
7133
+ * A handover is still available and is the supported way out: grant the
7134
+ * successor first, then renounce.
6821
7135
  *
6822
7136
  * @returns The transaction hash.
6823
7137
  */
@@ -6889,11 +7203,15 @@ var ConfidentialAirdropFactoryClient = class {
6889
7203
  /**
6890
7204
  * The create-time guardrails that need a read, run before anything is sent.
6891
7205
  *
6892
- * Two checks, in the order a failure is cheapest to discover:
7206
+ * Three checks, in the order a failure is cheapest to discover:
6893
7207
  *
6894
- * 1. **Stock wrapper.** Only when `unwrappable` is requested; one
7208
+ * 1. **Accepted gas fee.** The fee is frozen into the instance at
7209
+ * initialization and immutable after, so a bound that no longer holds must
7210
+ * stop the transaction before anything else is spent on it (see
7211
+ * {@link GasFeeNotAcceptedError}).
7212
+ * 2. **Stock wrapper.** Only when `unwrappable` is requested; one
6895
7213
  * `underlying()` probe (see {@link NonStockWrapperError}).
6896
- * 2. **Salt collision.** A predicted address commits to `(implementation,
7214
+ * 3. **Salt collision.** A predicted address commits to `(implementation,
6897
7215
  * mode, deployer, userSalt)` and ignores the params struct entirely, so
6898
7216
  * two campaigns differing only in token, window, signer or root still
6899
7217
  * land on one address. The prediction plus one `eth_getCode` turns that
@@ -6904,7 +7222,13 @@ var ConfidentialAirdropFactoryClient = class {
6904
7222
  */
6905
7223
  async #guardCreate(input) {
6906
7224
  const { variant, args, deployer, method } = input;
6907
- await chunkAREQJHKA_cjs.assertStockWrapper({
7225
+ await chunkYTIYTV4K_cjs.assertGasFeeAccepted({
7226
+ factory: this,
7227
+ creator: deployer,
7228
+ maxAcceptedGasFee: args.params.common.maxAcceptedGasFee,
7229
+ method
7230
+ });
7231
+ await chunkYTIYTV4K_cjs.assertStockWrapper({
6908
7232
  publicClient: this.publicClient,
6909
7233
  token: args.params.common.token,
6910
7234
  unwrappable: args.params.common.unwrappable
@@ -6917,7 +7241,7 @@ var ConfidentialAirdropFactoryClient = class {
6917
7241
  params: args.params,
6918
7242
  ...predictArgs
6919
7243
  });
6920
- await chunkAREQJHKA_cjs.assertSaltAvailable({
7244
+ await chunkYTIYTV4K_cjs.assertSaltAvailable({
6921
7245
  publicClient: this.publicClient,
6922
7246
  predictedAddress,
6923
7247
  variant,
@@ -7020,7 +7344,7 @@ var ConfidentialAirdropFactoryClient = class {
7020
7344
  method,
7021
7345
  contractAddress: this.address,
7022
7346
  abi: airdropFactoryAbi,
7023
- productMapper: chunkAREQJHKA_cjs.airdropProductMapper,
7347
+ productMapper: chunkYTIYTV4K_cjs.airdropProductMapper,
7024
7348
  account: accountAddress2(account),
7025
7349
  // `UpgradeabilityNotAllowed` and `ZamaProtocolUnsupported` carry no args
7026
7350
  // on-chain; the mapper can only name the creator and chain if we forward
@@ -7435,6 +7759,11 @@ var merkleConfidentialAirdropAbi = [
7435
7759
  name: "ZeroToken",
7436
7760
  type: "error"
7437
7761
  },
7762
+ {
7763
+ inputs: [],
7764
+ name: "ZeroUnwrapRequestId",
7765
+ type: "error"
7766
+ },
7438
7767
  {
7439
7768
  anonymous: false,
7440
7769
  inputs: [
@@ -7467,6 +7796,12 @@ var merkleConfidentialAirdropAbi = [
7467
7796
  internalType: "uint256",
7468
7797
  name: "deploymentBlockNumber",
7469
7798
  type: "uint256"
7799
+ },
7800
+ {
7801
+ indexed: false,
7802
+ internalType: "uint256",
7803
+ name: "gasFee",
7804
+ type: "uint256"
7470
7805
  }
7471
7806
  ],
7472
7807
  name: "AirdropInitialized",
@@ -8494,6 +8829,19 @@ var merkleConfidentialAirdropAbi = [
8494
8829
  stateMutability: "view",
8495
8830
  type: "function"
8496
8831
  },
8832
+ {
8833
+ inputs: [],
8834
+ name: "refreshComplianceBalance",
8835
+ outputs: [
8836
+ {
8837
+ internalType: "euint64",
8838
+ name: "balance",
8839
+ type: "bytes32"
8840
+ }
8841
+ ],
8842
+ stateMutability: "nonpayable",
8843
+ type: "function"
8844
+ },
8497
8845
  {
8498
8846
  inputs: [
8499
8847
  {
@@ -8728,7 +9076,7 @@ var MerkleAirdropClient = class extends AirdropBaseClient {
8728
9076
  async claim(args) {
8729
9077
  return chunkVJKZWYYJ_cjs.withTelemetry(this.telemetry, `${this.spanPrefix}.claim`, async () => {
8730
9078
  const submitter = this.resolveSender(args.account, "claim");
8731
- chunkAREQJHKA_cjs.assertMerkleClaimIdentity({
9079
+ chunkYTIYTV4K_cjs.assertMerkleClaimIdentity({
8732
9080
  method: "claim",
8733
9081
  account: args.entry.account,
8734
9082
  boundTo: args.entry.boundTo,
@@ -8775,7 +9123,7 @@ var MerkleAirdropClient = class extends AirdropBaseClient {
8775
9123
  async claimAndUnwrap(args) {
8776
9124
  return chunkVJKZWYYJ_cjs.withTelemetry(this.telemetry, `${this.spanPrefix}.claimAndUnwrap`, async () => {
8777
9125
  const submitter = this.resolveSender(args.account, "claimAndUnwrap");
8778
- chunkAREQJHKA_cjs.assertMerkleClaimIdentity({
9126
+ chunkYTIYTV4K_cjs.assertMerkleClaimIdentity({
8779
9127
  method: "claimAndUnwrap",
8780
9128
  account: args.entry.account,
8781
9129
  boundTo: args.entry.boundTo,
@@ -8810,7 +9158,7 @@ var MerkleAirdropClient = class extends AirdropBaseClient {
8810
9158
  */
8811
9159
  async getClaimAmount(args) {
8812
9160
  const submitter = this.resolveSender(args.account, "getClaimAmount");
8813
- chunkAREQJHKA_cjs.assertMerkleClaimIdentity({
9161
+ chunkYTIYTV4K_cjs.assertMerkleClaimIdentity({
8814
9162
  method: "getClaimAmount",
8815
9163
  account: args.entry.account,
8816
9164
  boundTo: args.entry.boundTo,
@@ -9503,7 +9851,7 @@ var ComplianceManagerClient = class {
9503
9851
  clientLabel: "ComplianceManagerClient"
9504
9852
  });
9505
9853
  }
9506
- chunkAREQJHKA_cjs.assertSupportedChain(chainId);
9854
+ chunkYTIYTV4K_cjs.assertSupportedChain(chainId);
9507
9855
  this.chainId = chainId;
9508
9856
  this.address = chunkJK4XMMKM_cjs.normaliseAddress(config.address);
9509
9857
  this.#telemetry = config.telemetry;
@@ -9787,7 +10135,7 @@ var ComplianceManagerClient = class {
9787
10135
  method,
9788
10136
  contractAddress: this.address,
9789
10137
  abi: complianceRoleManagerAbi,
9790
- productMapper: chunkAREQJHKA_cjs.airdropProductMapper,
10138
+ productMapper: chunkYTIYTV4K_cjs.airdropProductMapper,
9791
10139
  account: accountAddress3(account),
9792
10140
  productContext: {
9793
10141
  creator: accountAddress3(account),