@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,8 +1,8 @@
1
- import { assertSupportedChain, airdropProductMapper, assertMerkleModeSupported, assertStockWrapper, assertSaltAvailable, assertMerkleClaimIdentity, DEDUP_MODE, DEPLOYMENT_MODE } from './chunk-VW356KR3.js';
1
+ import { assertSupportedChain, airdropProductMapper, assertMerkleModeSupported, assertGasFeeAccepted, assertStockWrapper, assertSaltAvailable, assertMerkleClaimIdentity, DEDUP_MODE, DEPLOYMENT_MODE } from './chunk-LEYYG4RF.js';
2
2
  import { requireFhevmAclAddress, ACL_ALLOWED_EVENT } from './chunk-ZWXJTBZO.js';
3
3
  import { SDK_VERSION } from './chunk-NWFMBLSQ.js';
4
4
  import { isContractRevert, mapContractRevert } from './chunk-4RAAATVY.js';
5
- import { requireFheAirdropFactoryAddress } from './chunk-A4DCEE33.js';
5
+ import { requireFheAirdropFactoryAddress } from './chunk-6HCT4QIX.js';
6
6
  import { normaliseAddress } from './chunk-ZA673I3O.js';
7
7
  import { asTxHash, asEncryptedHandle, asExternalInputProof, asSignature } from './chunk-KWFFIJYX.js';
8
8
  import { DeploymentAddressUnavailableError, InvalidArgumentError, MissingWalletClientError, MissingAccountError, TokenOpsSdkError, MissingEncryptorError, ReceiptEventNotFoundError } from './chunk-QBJ7O2B4.js';
@@ -69,6 +69,11 @@ var airdropFactoryAbi = [
69
69
  internalType: "uint96",
70
70
  name: "defaultGasFee_",
71
71
  type: "uint96"
72
+ },
73
+ {
74
+ internalType: "uint96",
75
+ name: "maxGasFee_",
76
+ type: "uint96"
72
77
  }
73
78
  ],
74
79
  stateMutability: "nonpayable",
@@ -173,6 +178,38 @@ var airdropFactoryAbi = [
173
178
  name: "FailedDeployment",
174
179
  type: "error"
175
180
  },
181
+ {
182
+ inputs: [
183
+ {
184
+ internalType: "uint96",
185
+ name: "gasFee",
186
+ type: "uint96"
187
+ },
188
+ {
189
+ internalType: "uint96",
190
+ name: "maxGasFee",
191
+ type: "uint96"
192
+ }
193
+ ],
194
+ name: "GasFeeExceedsMaximum",
195
+ type: "error"
196
+ },
197
+ {
198
+ inputs: [
199
+ {
200
+ internalType: "uint96",
201
+ name: "resolvedFee",
202
+ type: "uint96"
203
+ },
204
+ {
205
+ internalType: "uint96",
206
+ name: "maxAcceptedGasFee",
207
+ type: "uint96"
208
+ }
209
+ ],
210
+ name: "GasFeeNotAccepted",
211
+ type: "error"
212
+ },
176
213
  {
177
214
  inputs: [
178
215
  {
@@ -391,6 +428,11 @@ var airdropFactoryAbi = [
391
428
  name: "ZeroToken",
392
429
  type: "error"
393
430
  },
431
+ {
432
+ inputs: [],
433
+ name: "ZeroUnwrapRequestId",
434
+ type: "error"
435
+ },
394
436
  {
395
437
  anonymous: false,
396
438
  inputs: [
@@ -423,6 +465,12 @@ var airdropFactoryAbi = [
423
465
  internalType: "uint256",
424
466
  name: "deploymentBlockNumber",
425
467
  type: "uint256"
468
+ },
469
+ {
470
+ indexed: false,
471
+ internalType: "uint256",
472
+ name: "gasFee",
473
+ type: "uint256"
426
474
  }
427
475
  ],
428
476
  name: "AirdropInitialized",
@@ -927,6 +975,19 @@ var airdropFactoryAbi = [
927
975
  name: "SetDefaultGasFee",
928
976
  type: "event"
929
977
  },
978
+ {
979
+ anonymous: false,
980
+ inputs: [
981
+ {
982
+ indexed: false,
983
+ internalType: "uint256",
984
+ name: "maxGasFee",
985
+ type: "uint256"
986
+ }
987
+ ],
988
+ name: "SetMaxGasFee",
989
+ type: "event"
990
+ },
930
991
  {
931
992
  anonymous: false,
932
993
  inputs: [
@@ -1218,6 +1279,11 @@ var airdropFactoryAbi = [
1218
1279
  internalType: "address",
1219
1280
  name: "complianceAdmin",
1220
1281
  type: "address"
1282
+ },
1283
+ {
1284
+ internalType: "uint96",
1285
+ name: "maxAcceptedGasFee",
1286
+ type: "uint96"
1221
1287
  }
1222
1288
  ],
1223
1289
  internalType: "struct IAirdropFactory.CommonAirdropParams",
@@ -1306,6 +1372,11 @@ var airdropFactoryAbi = [
1306
1372
  internalType: "address",
1307
1373
  name: "complianceAdmin",
1308
1374
  type: "address"
1375
+ },
1376
+ {
1377
+ internalType: "uint96",
1378
+ name: "maxAcceptedGasFee",
1379
+ type: "uint96"
1309
1380
  }
1310
1381
  ],
1311
1382
  internalType: "struct IAirdropFactory.CommonAirdropParams",
@@ -1394,6 +1465,11 @@ var airdropFactoryAbi = [
1394
1465
  internalType: "address",
1395
1466
  name: "complianceAdmin",
1396
1467
  type: "address"
1468
+ },
1469
+ {
1470
+ internalType: "uint96",
1471
+ name: "maxAcceptedGasFee",
1472
+ type: "uint96"
1397
1473
  }
1398
1474
  ],
1399
1475
  internalType: "struct IAirdropFactory.CommonAirdropParams",
@@ -1472,6 +1548,11 @@ var airdropFactoryAbi = [
1472
1548
  internalType: "address",
1473
1549
  name: "complianceAdmin",
1474
1550
  type: "address"
1551
+ },
1552
+ {
1553
+ internalType: "uint96",
1554
+ name: "maxAcceptedGasFee",
1555
+ type: "uint96"
1475
1556
  }
1476
1557
  ],
1477
1558
  internalType: "struct IAirdropFactory.CommonAirdropParams",
@@ -1738,6 +1819,11 @@ var airdropFactoryAbi = [
1738
1819
  internalType: "address",
1739
1820
  name: "complianceAdmin",
1740
1821
  type: "address"
1822
+ },
1823
+ {
1824
+ internalType: "uint96",
1825
+ name: "maxAcceptedGasFee",
1826
+ type: "uint96"
1741
1827
  }
1742
1828
  ],
1743
1829
  internalType: "struct IAirdropFactory.CommonAirdropParams",
@@ -1811,6 +1897,11 @@ var airdropFactoryAbi = [
1811
1897
  internalType: "address",
1812
1898
  name: "complianceAdmin",
1813
1899
  type: "address"
1900
+ },
1901
+ {
1902
+ internalType: "uint96",
1903
+ name: "maxAcceptedGasFee",
1904
+ type: "uint96"
1814
1905
  }
1815
1906
  ],
1816
1907
  internalType: "struct IAirdropFactory.CommonAirdropParams",
@@ -2003,6 +2094,38 @@ var airdropFactoryAbi = [
2003
2094
  stateMutability: "view",
2004
2095
  type: "function"
2005
2096
  },
2097
+ {
2098
+ inputs: [
2099
+ {
2100
+ internalType: "address",
2101
+ name: "candidate",
2102
+ type: "address"
2103
+ }
2104
+ ],
2105
+ name: "isAirdrop",
2106
+ outputs: [
2107
+ {
2108
+ internalType: "bool",
2109
+ name: "",
2110
+ type: "bool"
2111
+ }
2112
+ ],
2113
+ stateMutability: "view",
2114
+ type: "function"
2115
+ },
2116
+ {
2117
+ inputs: [],
2118
+ name: "maxGasFee",
2119
+ outputs: [
2120
+ {
2121
+ internalType: "uint256",
2122
+ name: "",
2123
+ type: "uint256"
2124
+ }
2125
+ ],
2126
+ stateMutability: "view",
2127
+ type: "function"
2128
+ },
2006
2129
  {
2007
2130
  inputs: [],
2008
2131
  name: "merkleImplementation",
@@ -2051,6 +2174,11 @@ var airdropFactoryAbi = [
2051
2174
  internalType: "address",
2052
2175
  name: "complianceAdmin",
2053
2176
  type: "address"
2177
+ },
2178
+ {
2179
+ internalType: "uint96",
2180
+ name: "maxAcceptedGasFee",
2181
+ type: "uint96"
2054
2182
  }
2055
2183
  ],
2056
2184
  internalType: "struct IAirdropFactory.CommonAirdropParams",
@@ -2134,6 +2262,11 @@ var airdropFactoryAbi = [
2134
2262
  internalType: "address",
2135
2263
  name: "complianceAdmin",
2136
2264
  type: "address"
2265
+ },
2266
+ {
2267
+ internalType: "uint96",
2268
+ name: "maxAcceptedGasFee",
2269
+ type: "uint96"
2137
2270
  }
2138
2271
  ],
2139
2272
  internalType: "struct IAirdropFactory.CommonAirdropParams",
@@ -2345,6 +2478,19 @@ var airdropFactoryAbi = [
2345
2478
  stateMutability: "nonpayable",
2346
2479
  type: "function"
2347
2480
  },
2481
+ {
2482
+ inputs: [
2483
+ {
2484
+ internalType: "uint96",
2485
+ name: "maxGasFee_",
2486
+ type: "uint96"
2487
+ }
2488
+ ],
2489
+ name: "setMaxGasFee",
2490
+ outputs: [],
2491
+ stateMutability: "nonpayable",
2492
+ type: "function"
2493
+ },
2348
2494
  {
2349
2495
  inputs: [
2350
2496
  {
@@ -2763,6 +2909,11 @@ var ecdsaConfidentialAirdropAbi = [
2763
2909
  name: "ZeroToken",
2764
2910
  type: "error"
2765
2911
  },
2912
+ {
2913
+ inputs: [],
2914
+ name: "ZeroUnwrapRequestId",
2915
+ type: "error"
2916
+ },
2766
2917
  {
2767
2918
  anonymous: false,
2768
2919
  inputs: [
@@ -2795,6 +2946,12 @@ var ecdsaConfidentialAirdropAbi = [
2795
2946
  internalType: "uint256",
2796
2947
  name: "deploymentBlockNumber",
2797
2948
  type: "uint256"
2949
+ },
2950
+ {
2951
+ indexed: false,
2952
+ internalType: "uint256",
2953
+ name: "gasFee",
2954
+ type: "uint256"
2798
2955
  }
2799
2956
  ],
2800
2957
  name: "AirdropInitialized",
@@ -3907,6 +4064,19 @@ var ecdsaConfidentialAirdropAbi = [
3907
4064
  stateMutability: "view",
3908
4065
  type: "function"
3909
4066
  },
4067
+ {
4068
+ inputs: [],
4069
+ name: "refreshComplianceBalance",
4070
+ outputs: [
4071
+ {
4072
+ internalType: "euint64",
4073
+ name: "balance",
4074
+ type: "bytes32"
4075
+ }
4076
+ ],
4077
+ stateMutability: "nonpayable",
4078
+ type: "function"
4079
+ },
3910
4080
  {
3911
4081
  inputs: [
3912
4082
  {
@@ -4294,6 +4464,11 @@ var confidentialAirdropBaseAbi = [
4294
4464
  name: "ZeroToken",
4295
4465
  type: "error"
4296
4466
  },
4467
+ {
4468
+ inputs: [],
4469
+ name: "ZeroUnwrapRequestId",
4470
+ type: "error"
4471
+ },
4297
4472
  {
4298
4473
  anonymous: false,
4299
4474
  inputs: [
@@ -4326,6 +4501,12 @@ var confidentialAirdropBaseAbi = [
4326
4501
  internalType: "uint256",
4327
4502
  name: "deploymentBlockNumber",
4328
4503
  type: "uint256"
4504
+ },
4505
+ {
4506
+ indexed: false,
4507
+ internalType: "uint256",
4508
+ name: "gasFee",
4509
+ type: "uint256"
4329
4510
  }
4330
4511
  ],
4331
4512
  name: "AirdropInitialized",
@@ -4802,6 +4983,19 @@ var confidentialAirdropBaseAbi = [
4802
4983
  stateMutability: "nonpayable",
4803
4984
  type: "function"
4804
4985
  },
4986
+ {
4987
+ inputs: [],
4988
+ name: "refreshComplianceBalance",
4989
+ outputs: [
4990
+ {
4991
+ internalType: "euint64",
4992
+ name: "balance",
4993
+ type: "bytes32"
4994
+ }
4995
+ ],
4996
+ stateMutability: "nonpayable",
4997
+ type: "function"
4998
+ },
4805
4999
  {
4806
5000
  inputs: [
4807
5001
  {
@@ -5201,8 +5395,12 @@ var AirdropBaseClient = class {
5201
5395
  * Sweep a plain ERC-20 that was sent to the instance by mistake. Requires
5202
5396
  * `RESCUER_ROLE`.
5203
5397
  *
5204
- * The campaign's own token is ERC-7984, not ERC-20, so it cannot be reached
5205
- * through this path — use {@link withdrawConfidential} for the pool.
5398
+ * Passing the campaign's own token reverts `CannotRescueAirdropToken`
5399
+ * (audit-05), matching {@link rescueOtherConfidentialToken}. ERC-7984 and
5400
+ * ERC-20 are not disjoint in practice - a wrapper token answers both
5401
+ * interfaces - so "the pool token is confidential, therefore out of reach
5402
+ * here" was never a guarantee, only an assumption. Use
5403
+ * {@link withdrawConfidential} for the pool.
5206
5404
  *
5207
5405
  * @returns The transaction hash.
5208
5406
  */
@@ -5562,17 +5760,56 @@ var AirdropBaseClient = class {
5562
5760
  // DISCLOSURE (ENCRYPTED)
5563
5761
  // ============================================================
5564
5762
  //
5565
- // The first three read like getters and are `nonpayable` in the ABI: they
5763
+ // The first four read like getters and are `nonpayable` in the ABI: they
5566
5764
  // call `FHE.allow`, which writes ACL state. They therefore submit a
5567
5765
  // transaction and recover their `euint64` result from the receipt — never
5568
5766
  // from a simulation. See `extractGrantedHandle`.
5569
5767
  //
5768
+ // Three of those four grant the CALLER; `refreshComplianceBalance` grants the
5769
+ // compliance clone instead, which is why it resolves the clone address and
5770
+ // passes it as `grantee`.
5771
+ //
5570
5772
  // The last two return nothing on-chain and are ordinary writes: they grant a
5571
5773
  // handle the caller already has, so there is no new handle to recover.
5774
+ /**
5775
+ * Re-grant the compliance-manager clone on the instance's current pool
5776
+ * balance, and return the handle it was granted on.
5777
+ *
5778
+ * **Permissionless, and deliberately so** (audit-04). The token rotates the
5779
+ * instance's balance handle on every incoming transfer, including one no
5780
+ * airdrop code observes - a third party transferring in directly - and
5781
+ * grants the fresh handle to the token and the holder only. Without this the
5782
+ * compliance clone's grant can be stranded on a handle the token has already
5783
+ * replaced, with no admin necessarily around to restore it. There is no
5784
+ * argument to abuse: the only handle read is `address(this)`'s own balance,
5785
+ * and the only grantee is the clone wired at initialization.
5786
+ *
5787
+ * This is therefore the normative way to obtain a readable live-balance
5788
+ * handle - and it is a **snapshot, not a subscription**. Grants are
5789
+ * append-only, so the handle this returns stays readable forever; but the
5790
+ * next incoming transfer rotates the instance to a NEW handle the clone was
5791
+ * never granted on. A compliance reader that refreshes once and stops is
5792
+ * reading a stale balance, not a live one. Call it again after any transfer
5793
+ * in, or before each read.
5794
+ *
5795
+ * @returns `{ handle, hash }` - the handle the compliance clone may now decrypt.
5796
+ * @throws {@link ReceiptEventNotFoundError} when the transaction granted no ACL to the clone.
5797
+ */
5798
+ async refreshComplianceBalance(args = {}) {
5799
+ const grantee = await this.complianceManager();
5800
+ return this.encryptedView({
5801
+ functionName: "refreshComplianceBalance",
5802
+ grantee,
5803
+ account: args.account
5804
+ });
5805
+ }
5572
5806
  /**
5573
5807
  * Read the instance's own remaining pool balance as a handle the **caller**
5574
5808
  * can decrypt. Requires `DISCLOSURE_ADMIN_ROLE`.
5575
5809
  *
5810
+ * Also re-grants the compliance-manager clone on the same handle (audit-04),
5811
+ * so an admin read doubles as a {@link refreshComplianceBalance}.
5812
+ *
5576
5813
  * @returns `{ handle, hash }` — pass `handle` to the Zama relayer's `userDecrypt`.
5577
5814
  * @throws {@link ReceiptEventNotFoundError} when the transaction granted no ACL to the caller.
5578
5815
  */
@@ -5648,11 +5885,18 @@ var AirdropBaseClient = class {
5648
5885
  /**
5649
5886
  * Grant `party` decrypt access to a handle you already hold.
5650
5887
  *
5651
- * Two gates apply on-chain: the caller must itself be allowed on the handle
5652
- * (bypassed by `DISCLOSURE_ADMIN_ROLE`), and the *instance* must be allowed
5653
- * on it — so an arbitrary handle from another contract cannot be laundered
5654
- * through this campaign. A failure of the first surfaces as
5655
- * `FheHandleNotAllowedError`.
5888
+ * Two gates apply on-chain. Gate #1: the handle must be **persistently**
5889
+ * user-decryptable in the `(caller, instance)` context - BOTH legs, and a
5890
+ * transient allowance does not satisfy either (audit-06). `DISCLOSURE_ADMIN_ROLE`
5891
+ * bypasses gate #1 only. Gate #2: the instance must be allowed on the handle,
5892
+ * so an arbitrary handle from another contract cannot be laundered through
5893
+ * this campaign.
5894
+ *
5895
+ * **The transient case is the trap.** An `euint64` that just came back from
5896
+ * an FHE op carries a transient allowance, which used to be enough here and
5897
+ * no longer is. Handles worth disclosing come from the encrypted views on
5898
+ * this client, whose grants are persistent. A gate #1 failure surfaces as
5899
+ * `FheHandleNotAllowedError` carrying the offending handle.
5656
5900
  *
5657
5901
  * @param args.handle An existing `euint64` handle — a public pointer, not a value.
5658
5902
  * @returns The transaction hash. No new handle is produced.
@@ -5922,11 +6166,24 @@ var EcdsaAirdropClient = class extends AirdropBaseClient {
5922
6166
  * consuming either replay guard — the same input can still be claimed for
5923
6167
  * real afterwards. No fee.
5924
6168
  *
6169
+ * **It is repeatable, not unconditional** (audit-07). While the claim is
6170
+ * still available this may be called any number of times; once it is not,
6171
+ * this reverts with the same error the consuming claim would raise, in the
6172
+ * same order: the mode's dedup slot first (`AddressAlreadyClaimed` /
6173
+ * `DedupIdAlreadyClaimed`), the EIP-712 digest second (`SignatureAlreadyUsed`).
6174
+ * A rejected preview performs no FHE op, grants no ACL and emits nothing.
6175
+ *
6176
+ * So this is not a probe for "has this been claimed" - use
6177
+ * {@link isSignatureValid}, which never reverts and answers the same
6178
+ * question for free. Reach for this when you want the AMOUNT.
6179
+ *
5925
6180
  * An encrypted view: the contract calls `FHE.allow(amount, msg.sender)`, so
5926
6181
  * the result is recovered from the receipt's ACL `Allowed` event, never
5927
6182
  * from a simulation. See {@link AirdropBaseClient}'s class TSDoc.
5928
6183
  *
5929
6184
  * @returns `{ handle, hash }` — pass `handle` to the Zama relayer's `userDecrypt`.
6185
+ * @throws {@link AlreadyClaimedError} when this recipient's dedup slot is consumed.
6186
+ * @throws {@link DedupIdConsumedError} when this `dedupId`'s slot is consumed.
5930
6187
  */
5931
6188
  async getClaimAmount(args) {
5932
6189
  return this.encryptedView({
@@ -6126,7 +6383,8 @@ function toContractCommonParams(common) {
6126
6383
  endTime: common.endTime,
6127
6384
  canExtendClaimWindow: common.canExtendClaimWindow,
6128
6385
  unwrappable: common.unwrappable,
6129
- complianceAdmin: common.complianceAdmin
6386
+ complianceAdmin: common.complianceAdmin,
6387
+ maxAcceptedGasFee: common.maxAcceptedGasFee
6130
6388
  };
6131
6389
  }
6132
6390
  function toContractEcdsaParams(params) {
@@ -6483,11 +6741,28 @@ var ConfidentialAirdropFactoryClient = class {
6483
6741
  async airdrops(offset, limit) {
6484
6742
  return this.#read("airdrops", [offset, limit]);
6485
6743
  }
6744
+ /**
6745
+ * Whether THIS factory created `candidate` - the genuineness check (audit-10).
6746
+ *
6747
+ * Nothing observable at an instance proves which factory, if any, deployed
6748
+ * it: an attacker can deploy a contract with the same ABI, the same events
6749
+ * and a pool it controls. The only trustworthy question is whether the
6750
+ * canonical factory's own registry contains the address, which is why this
6751
+ * read has to be addressed to a factory taken from
6752
+ * `src/core/addresses.ts` rather than one the instance names.
6753
+ *
6754
+ * @param candidate The address to check.
6755
+ * @returns True when this factory's registry contains `candidate`.
6756
+ */
6757
+ async isAirdrop(candidate) {
6758
+ return this.#read("isAirdrop", [candidate]);
6759
+ }
6486
6760
  /**
6487
6761
  * The compliance-manager clone bound to an instance.
6488
6762
  *
6489
- * Doubles as a provenance check: the factory records this mapping only for
6490
- * instances it deployed, so a zero address means the instance is not ours.
6763
+ * Doubles as a provenance check, though a weaker one than {@link isAirdrop}:
6764
+ * the factory records this mapping only for instances it deployed, so a zero
6765
+ * address means the instance is not ours.
6491
6766
  *
6492
6767
  * @param airdrop Instance address.
6493
6768
  * @returns The clone address, or the zero address when unknown to this factory.
@@ -6541,6 +6816,47 @@ var ConfidentialAirdropFactoryClient = class {
6541
6816
  async defaultGasFee() {
6542
6817
  return this.#read("defaultGasFee");
6543
6818
  }
6819
+ /** The factory's own ceiling on every configurable fee and every create-time resolved fee. */
6820
+ async maxGasFee() {
6821
+ return this.#read("maxGasFee");
6822
+ }
6823
+ /**
6824
+ * Set the factory's ceiling on every fee `setDefaultGasFee`/`setCustomFee`
6825
+ * may configure, and on the fee resolved at create.
6826
+ *
6827
+ * Requires `DEFAULT_ADMIN_ROLE`, deliberately not `FEE_MANAGER_ROLE`: the fee
6828
+ * manager moves fees only within a bound the admin controls. `0n` admits a
6829
+ * zero fee and nothing else.
6830
+ *
6831
+ * Lowering it below an already-configured fee does not rewrite that fee - the
6832
+ * stale value stays in storage and reverts `GasFeeExceedsMaximum` at the next
6833
+ * create until it is lowered too.
6834
+ *
6835
+ * @throws {@link InvalidArgumentError} when `maxGasFee` is below a currently configured fee (`GasFeeExceedsMaximum`).
6836
+ */
6837
+ async setMaxGasFee(maxGasFee, account) {
6838
+ return this.#write("setMaxGasFee", [maxGasFee], account, "setMaxGasFee");
6839
+ }
6840
+ /**
6841
+ * The per-claim fee a `create*` from `creator` would freeze into the new
6842
+ * instance right now: their {@link getCustomFee} override when enabled, else
6843
+ * {@link defaultGasFee}.
6844
+ *
6845
+ * This is the number `CommonAirdropParams.maxAcceptedGasFee` is checked
6846
+ * against, so it is also what to show a creator before they choose a bound.
6847
+ * It is a snapshot, not a quote: `FEE_MANAGER_ROLE` can move it between this
6848
+ * read and the create, which is exactly what the bound exists to catch.
6849
+ *
6850
+ * @param creator The account that will send `create*`.
6851
+ * @returns The resolved fee in wei.
6852
+ */
6853
+ async resolveGasFee(creator) {
6854
+ const [custom, fallback] = await Promise.all([
6855
+ this.getCustomFee(creator),
6856
+ this.defaultGasFee()
6857
+ ]);
6858
+ return custom.enabled ? custom.gasFee : fallback;
6859
+ }
6544
6860
  // ----------------------- implementation admin -----------------------
6545
6861
  /**
6546
6862
  * Point future `createEcdsaAirdrop*` calls at a new ECDSA implementation.
@@ -6805,17 +7121,15 @@ var ConfidentialAirdropFactoryClient = class {
6805
7121
  /**
6806
7122
  * Revoke `role` from `holder`. Requires the role's admin role.
6807
7123
  *
6808
- * Unlike an airdrop instance, the factory declares no "never empty" floor:
6809
- * revoking the last `DEFAULT_ADMIN_ROLE` member succeeds, and what it
6810
- * freezes is **role administration**, permanently. `DEFAULT_ADMIN_ROLE`
6811
- * administers all four operational roles and itself, so with the set empty
6812
- * no role can ever be granted or revoked again - including putting an admin
6813
- * back. The four operational roles keep working for whoever already holds
6814
- * them: a `FEE_MANAGER_ROLE` holder can still call {@link setDefaultGasFee},
6815
- * an `IMPL_MANAGER_ROLE` holder can still rotate an implementation. The
6816
- * factory therefore keeps running with exactly the role holders it had at
6817
- * that moment, with no way to rotate or remove them. Grant the successor
6818
- * first.
7124
+ * **The factory floors `DEFAULT_ADMIN_ROLE` at one live member** (audit-14),
7125
+ * matching the instances. Renouncing or revoking the sole holder reverts
7126
+ * `LastAdmin`, and granting the role to the zero address reverts
7127
+ * `ZeroAdminGrant`, so the set can neither be emptied nor satisfied by a
7128
+ * member nobody controls. Before audit-14 this succeeded and froze role
7129
+ * administration permanently; it no longer does.
7130
+ *
7131
+ * A handover is still available and is the supported way out: grant the
7132
+ * successor first, then renounce.
6819
7133
  *
6820
7134
  * @returns The transaction hash.
6821
7135
  */
@@ -6887,11 +7201,15 @@ var ConfidentialAirdropFactoryClient = class {
6887
7201
  /**
6888
7202
  * The create-time guardrails that need a read, run before anything is sent.
6889
7203
  *
6890
- * Two checks, in the order a failure is cheapest to discover:
7204
+ * Three checks, in the order a failure is cheapest to discover:
6891
7205
  *
6892
- * 1. **Stock wrapper.** Only when `unwrappable` is requested; one
7206
+ * 1. **Accepted gas fee.** The fee is frozen into the instance at
7207
+ * initialization and immutable after, so a bound that no longer holds must
7208
+ * stop the transaction before anything else is spent on it (see
7209
+ * {@link GasFeeNotAcceptedError}).
7210
+ * 2. **Stock wrapper.** Only when `unwrappable` is requested; one
6893
7211
  * `underlying()` probe (see {@link NonStockWrapperError}).
6894
- * 2. **Salt collision.** A predicted address commits to `(implementation,
7212
+ * 3. **Salt collision.** A predicted address commits to `(implementation,
6895
7213
  * mode, deployer, userSalt)` and ignores the params struct entirely, so
6896
7214
  * two campaigns differing only in token, window, signer or root still
6897
7215
  * land on one address. The prediction plus one `eth_getCode` turns that
@@ -6902,6 +7220,12 @@ var ConfidentialAirdropFactoryClient = class {
6902
7220
  */
6903
7221
  async #guardCreate(input) {
6904
7222
  const { variant, args, deployer, method } = input;
7223
+ await assertGasFeeAccepted({
7224
+ factory: this,
7225
+ creator: deployer,
7226
+ maxAcceptedGasFee: args.params.common.maxAcceptedGasFee,
7227
+ method
7228
+ });
6905
7229
  await assertStockWrapper({
6906
7230
  publicClient: this.publicClient,
6907
7231
  token: args.params.common.token,
@@ -7433,6 +7757,11 @@ var merkleConfidentialAirdropAbi = [
7433
7757
  name: "ZeroToken",
7434
7758
  type: "error"
7435
7759
  },
7760
+ {
7761
+ inputs: [],
7762
+ name: "ZeroUnwrapRequestId",
7763
+ type: "error"
7764
+ },
7436
7765
  {
7437
7766
  anonymous: false,
7438
7767
  inputs: [
@@ -7465,6 +7794,12 @@ var merkleConfidentialAirdropAbi = [
7465
7794
  internalType: "uint256",
7466
7795
  name: "deploymentBlockNumber",
7467
7796
  type: "uint256"
7797
+ },
7798
+ {
7799
+ indexed: false,
7800
+ internalType: "uint256",
7801
+ name: "gasFee",
7802
+ type: "uint256"
7468
7803
  }
7469
7804
  ],
7470
7805
  name: "AirdropInitialized",
@@ -8492,6 +8827,19 @@ var merkleConfidentialAirdropAbi = [
8492
8827
  stateMutability: "view",
8493
8828
  type: "function"
8494
8829
  },
8830
+ {
8831
+ inputs: [],
8832
+ name: "refreshComplianceBalance",
8833
+ outputs: [
8834
+ {
8835
+ internalType: "euint64",
8836
+ name: "balance",
8837
+ type: "bytes32"
8838
+ }
8839
+ ],
8840
+ stateMutability: "nonpayable",
8841
+ type: "function"
8842
+ },
8495
8843
  {
8496
8844
  inputs: [
8497
8845
  {
@@ -1,5 +1,5 @@
1
- import { resolveEncryptor, encryptUint64Batch, encryptUint64 } from './chunk-X7WBPCEU.js';
2
- import { assertPredictionFresh, FeeCollectorSelfAdministeredError } from './chunk-VW356KR3.js';
1
+ import { resolveEncryptor, encryptUint64Batch, encryptUint64 } from './chunk-BXX5TETM.js';
2
+ import { assertPredictionFresh, FeeCollectorSelfAdministeredError } from './chunk-LEYYG4RF.js';
3
3
  import { normaliseAddress } from './chunk-ZA673I3O.js';
4
4
  import { InvalidArgumentError, MissingWalletClientError, MissingAccountError, ContractRevertError, MissingEncryptorError, isTokenOpsSdkError, UnknownWriteFailureError } from './chunk-QBJ7O2B4.js';
5
5
  import { StandardMerkleTree } from '@openzeppelin/merkle-tree';