@tokenops/sdk 2.0.0-alpha.1 → 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 (155) hide show
  1. package/CHANGELOG.md +67 -2
  2. package/README.md +14 -8
  3. package/dist/{chunk-PUX5VXDB.cjs → chunk-4AWQJQXY.cjs} +1415 -69
  4. package/dist/{chunk-74QFZ5MK.js → chunk-4IB4IY5Y.js} +1 -1
  5. package/dist/{chunk-DZHYSUGY.js → chunk-6HCT4QIX.js} +12 -5
  6. package/dist/{chunk-FGEB7RMY.cjs → chunk-6XOAYDC6.cjs} +4 -4
  7. package/dist/{chunk-XAYGD4E4.cjs → chunk-AHU2HMNE.cjs} +3 -3
  8. package/dist/{chunk-6NAVMWZQ.js → chunk-BPIVVCSQ.js} +2 -2
  9. package/dist/{chunk-GKKDAW44.js → chunk-BXX5TETM.js} +1401 -59
  10. package/dist/{chunk-456VDDA3.js → chunk-GCJFAY4X.js} +78 -25
  11. package/dist/{chunk-CTED3MTR.cjs → chunk-GKYZQJGP.cjs} +82 -29
  12. package/dist/{chunk-JZLGCTGK.cjs → chunk-IEKTGJ4J.cjs} +2 -2
  13. package/dist/{chunk-6PXXGACR.cjs → chunk-JVNJSDQ4.cjs} +2 -2
  14. package/dist/{chunk-O5676ZWY.js → chunk-LEYYG4RF.js} +232 -6
  15. package/dist/{chunk-335Z2W67.js → chunk-NGU4JYIR.js} +1 -1
  16. package/dist/{chunk-5576FRT3.cjs → chunk-PG3WXT3K.cjs} +12 -5
  17. package/dist/{chunk-H5POPGOZ.js → chunk-PK6Q6J5F.js} +1 -1
  18. package/dist/chunk-TND5NDV7.cjs +263 -0
  19. package/dist/chunk-U3TBQRT7.js +253 -0
  20. package/dist/{chunk-EAJ7SYHE.js → chunk-WRWRA4TN.js} +1 -1
  21. package/dist/{chunk-JQYC66TO.cjs → chunk-YABHXJNH.cjs} +5 -5
  22. package/dist/{chunk-M4IT6DNJ.cjs → chunk-YTIYTV4K.cjs} +236 -4
  23. package/dist/core/addresses.d.ts +4 -4
  24. package/dist/core/errors.d.ts +1 -1
  25. package/dist/fhe/types.d.ts +2 -2
  26. package/dist/fhe-airdrop/abis/airdrop-base.d.ts +19 -0
  27. package/dist/fhe-airdrop/abis/ecdsa.d.ts +19 -0
  28. package/dist/fhe-airdrop/abis/factory.d.ts +113 -0
  29. package/dist/fhe-airdrop/abis/merkle.d.ts +43 -12
  30. package/dist/fhe-airdrop/advanced/index.cjs +4 -4
  31. package/dist/fhe-airdrop/advanced/index.js +1 -1
  32. package/dist/fhe-airdrop/advanced/react/index.cjs +620 -9
  33. package/dist/fhe-airdrop/advanced/react/index.d.cts +35 -0
  34. package/dist/fhe-airdrop/advanced/react/index.d.ts +35 -0
  35. package/dist/fhe-airdrop/advanced/react/index.js +590 -7
  36. package/dist/fhe-airdrop/advanced/react/useClearCompliancePolicy.d.ts +28 -0
  37. package/dist/fhe-airdrop/advanced/react/useClearUpgradeabilityPolicy.d.ts +26 -0
  38. package/dist/fhe-airdrop/advanced/react/useDisableCustomFee.d.ts +26 -0
  39. package/dist/fhe-airdrop/advanced/react/useEcdsaInitCodeHash.d.ts +30 -0
  40. package/dist/fhe-airdrop/advanced/react/useFactoryComplianceDelegate.d.ts +25 -0
  41. package/dist/fhe-airdrop/advanced/react/useFactoryCompliancePolicy.d.ts +38 -0
  42. package/dist/fhe-airdrop/advanced/react/useFactoryCustomFee.d.ts +24 -0
  43. package/dist/fhe-airdrop/advanced/react/useFactoryGrantRole.d.ts +32 -0
  44. package/dist/fhe-airdrop/advanced/react/useFactoryHasRole.d.ts +27 -0
  45. package/dist/fhe-airdrop/advanced/react/useFactoryImplementations.d.ts +33 -0
  46. package/dist/fhe-airdrop/advanced/react/useFactoryRenounceRole.d.ts +37 -0
  47. package/dist/fhe-airdrop/advanced/react/useFactoryRevokeRole.d.ts +37 -0
  48. package/dist/fhe-airdrop/advanced/react/useFactoryRoleConstants.d.ts +46 -0
  49. package/dist/fhe-airdrop/advanced/react/useFactoryRoleMembers.d.ts +48 -0
  50. package/dist/fhe-airdrop/advanced/react/useFactoryUpgradeabilityPolicy.d.ts +39 -0
  51. package/dist/fhe-airdrop/advanced/react/useMerkleInitCodeHash.d.ts +24 -0
  52. package/dist/fhe-airdrop/advanced/react/useSetComplianceDelegate.d.ts +33 -0
  53. package/dist/fhe-airdrop/advanced/react/useSetComplianceManagerImpl.d.ts +27 -0
  54. package/dist/fhe-airdrop/advanced/react/useSetCompliancePolicy.d.ts +28 -0
  55. package/dist/fhe-airdrop/advanced/react/useSetCustomFee.d.ts +29 -0
  56. package/dist/fhe-airdrop/advanced/react/useSetDefaultDelegateToCompliance.d.ts +31 -0
  57. package/dist/fhe-airdrop/advanced/react/useSetDefaultGasFee.d.ts +30 -0
  58. package/dist/fhe-airdrop/advanced/react/useSetDefaultUpgradeable.d.ts +27 -0
  59. package/dist/fhe-airdrop/advanced/react/useSetEcdsaImplementation.d.ts +34 -0
  60. package/dist/fhe-airdrop/advanced/react/useSetFeeCollector.d.ts +27 -0
  61. package/dist/fhe-airdrop/advanced/react/useSetMaxGasFee.d.ts +33 -0
  62. package/dist/fhe-airdrop/advanced/react/useSetMerkleImplementation.d.ts +30 -0
  63. package/dist/fhe-airdrop/advanced/react/useSetUpgradeabilityPolicy.d.ts +31 -0
  64. package/dist/fhe-airdrop/airdrop-base.d.ts +55 -8
  65. package/dist/fhe-airdrop/campaign.d.ts +61 -20
  66. package/dist/fhe-airdrop/constants.d.ts +9 -1
  67. package/dist/fhe-airdrop/ecdsa.d.ts +13 -0
  68. package/dist/fhe-airdrop/errors.d.ts +87 -0
  69. package/dist/fhe-airdrop/factory.d.ts +62 -22
  70. package/dist/fhe-airdrop/guards.d.ts +133 -4
  71. package/dist/fhe-airdrop/index.cjs +86 -971
  72. package/dist/fhe-airdrop/index.d.cts +4 -4
  73. package/dist/fhe-airdrop/index.d.ts +4 -4
  74. package/dist/fhe-airdrop/index.js +8 -927
  75. package/dist/fhe-airdrop/merkle-tree.d.ts +32 -38
  76. package/dist/fhe-airdrop/merkle.d.ts +52 -31
  77. package/dist/fhe-airdrop/react/_shared.d.ts +13 -0
  78. package/dist/fhe-airdrop/react/index.cjs +997 -87
  79. package/dist/fhe-airdrop/react/index.d.cts +53 -4
  80. package/dist/fhe-airdrop/react/index.d.ts +53 -4
  81. package/dist/fhe-airdrop/react/index.js +887 -27
  82. package/dist/fhe-airdrop/react/keys.d.ts +98 -0
  83. package/dist/fhe-airdrop/react/useAccessEcdsaClaimAmount.d.ts +26 -0
  84. package/dist/fhe-airdrop/react/useAccessMerkleClaimAmount.d.ts +27 -0
  85. package/dist/fhe-airdrop/react/useAddComplianceDelegate.d.ts +37 -0
  86. package/dist/fhe-airdrop/react/useAdminBatchDiscloseBalanceToParties.d.ts +36 -0
  87. package/dist/fhe-airdrop/react/useAdminDiscloseBalanceToParty.d.ts +31 -0
  88. package/dist/fhe-airdrop/react/useAdminGetCurrentBalance.d.ts +27 -0
  89. package/dist/fhe-airdrop/react/useAirdropConfig.d.ts +49 -0
  90. package/dist/fhe-airdrop/react/useAirdropDeploymentMode.d.ts +28 -0
  91. package/dist/fhe-airdrop/react/useAirdropGrantRole.d.ts +35 -0
  92. package/dist/fhe-airdrop/react/useAirdropRenounceRole.d.ts +36 -0
  93. package/dist/fhe-airdrop/react/useAirdropRevokeRole.d.ts +33 -0
  94. package/dist/fhe-airdrop/react/useAirdropRoleAdmin.d.ts +28 -0
  95. package/dist/fhe-airdrop/react/useAirdropRoleConstants.d.ts +67 -0
  96. package/dist/fhe-airdrop/react/useAirdropRoleMembers.d.ts +49 -0
  97. package/dist/fhe-airdrop/react/useAirdropUpgradeToAndCall.d.ts +45 -0
  98. package/dist/fhe-airdrop/react/useBatchDiscloseHandlesToParty.d.ts +32 -0
  99. package/dist/fhe-airdrop/react/useBuildMerkleCampaign.d.ts +68 -0
  100. package/dist/fhe-airdrop/react/useComplianceGrantRole.d.ts +32 -0
  101. package/dist/fhe-airdrop/react/useComplianceHasRole.d.ts +37 -0
  102. package/dist/fhe-airdrop/react/useComplianceInfo.d.ts +50 -0
  103. package/dist/fhe-airdrop/react/useComplianceManagerOf.d.ts +32 -0
  104. package/dist/fhe-airdrop/react/useComplianceRenounceRole.d.ts +38 -0
  105. package/dist/fhe-airdrop/react/useComplianceRevokeRole.d.ts +36 -0
  106. package/dist/fhe-airdrop/react/useComplianceRoleConstants.d.ts +41 -0
  107. package/dist/fhe-airdrop/react/useComplianceRoleMembers.d.ts +45 -0
  108. package/dist/fhe-airdrop/react/useCreateAndFundEcdsaAirdrop.d.ts +55 -0
  109. package/dist/fhe-airdrop/react/useCreateAndFundMerkleAirdrop.d.ts +52 -0
  110. package/dist/fhe-airdrop/react/useDiscloseHandleToParty.d.ts +35 -0
  111. package/dist/fhe-airdrop/react/useEcdsaClaim.d.ts +4 -3
  112. package/dist/fhe-airdrop/react/useEcdsaClaimAndUnwrap.d.ts +27 -0
  113. package/dist/fhe-airdrop/react/useEcdsaDomain.d.ts +41 -0
  114. package/dist/fhe-airdrop/react/useEffectiveDelegateToCompliance.d.ts +26 -0
  115. package/dist/fhe-airdrop/react/useEncryptCampaignAmounts.d.ts +59 -0
  116. package/dist/fhe-airdrop/react/useFactoryFees.d.ts +11 -4
  117. package/dist/fhe-airdrop/react/useIsActiveDelegate.d.ts +29 -0
  118. package/dist/fhe-airdrop/react/useIsAirdrop.d.ts +44 -0
  119. package/dist/fhe-airdrop/react/useIsMerkleRootMutable.d.ts +21 -0
  120. package/dist/fhe-airdrop/react/useIsSignatureValid.d.ts +46 -0
  121. package/dist/fhe-airdrop/react/useMerkleClaim.d.ts +7 -19
  122. package/dist/fhe-airdrop/react/useMerkleClaimAndUnwrap.d.ts +29 -0
  123. package/dist/fhe-airdrop/react/usePlanMerkleCampaign.d.ts +53 -0
  124. package/dist/fhe-airdrop/react/usePreflightClaim.d.ts +46 -0
  125. package/dist/fhe-airdrop/react/usePreflightCreateAirdrop.d.ts +67 -0
  126. package/dist/fhe-airdrop/react/useRefreshComplianceBalance.d.ts +36 -0
  127. package/dist/fhe-airdrop/react/useRescueERC20.d.ts +30 -0
  128. package/dist/fhe-airdrop/react/useRescueOtherConfidentialToken.d.ts +34 -0
  129. package/dist/fhe-airdrop/react/useResolveGasFee.d.ts +30 -0
  130. package/dist/fhe-airdrop/react/useRevokeComplianceDelegate.d.ts +37 -0
  131. package/dist/fhe-airdrop/react/useRotateMerkleRoot.d.ts +52 -0
  132. package/dist/fhe-airdrop/react/useSignClaimAuthorization.d.ts +42 -0
  133. package/dist/fhe-airdrop/react/useWithdrawGasFee.d.ts +37 -0
  134. package/dist/fhe-airdrop/types.d.ts +27 -1
  135. package/dist/fhe-disperse/index.cjs +21 -21
  136. package/dist/fhe-disperse/index.js +2 -2
  137. package/dist/fhe-disperse/react/index.cjs +22 -22
  138. package/dist/fhe-disperse/react/index.js +3 -3
  139. package/dist/fhe-vesting/advanced/index.cjs +5 -5
  140. package/dist/fhe-vesting/advanced/index.js +3 -3
  141. package/dist/fhe-vesting/advanced/react/index.cjs +7 -7
  142. package/dist/fhe-vesting/advanced/react/index.js +4 -4
  143. package/dist/fhe-vesting/index.cjs +8 -8
  144. package/dist/fhe-vesting/index.js +2 -2
  145. package/dist/fhe-vesting/react/index.cjs +114 -114
  146. package/dist/fhe-vesting/react/index.js +3 -3
  147. package/dist/index.cjs +18 -18
  148. package/dist/index.js +1 -1
  149. package/dist/testnet-faucet/index.cjs +14 -14
  150. package/dist/testnet-faucet/index.js +2 -2
  151. package/dist/testnet-faucet/react/index.cjs +8 -8
  152. package/dist/testnet-faucet/react/index.js +3 -3
  153. package/package.json +1 -1
  154. package/dist/chunk-NCVX3K2N.cjs +0 -161
  155. package/dist/chunk-VP2B4WM2.js +0 -154
@@ -1,8 +1,8 @@
1
- import { assertSupportedChain, airdropProductMapper, assertMerkleModeSupported, assertStockWrapper, assertSaltAvailable, DEDUP_MODE, DEPLOYMENT_MODE } from './chunk-O5676ZWY.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-DZHYSUGY.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.
@@ -5807,6 +6051,17 @@ var AirdropBaseClient = class {
5807
6051
  }
5808
6052
  return acct;
5809
6053
  }
6054
+ /**
6055
+ * The address that will actually send the transaction, as a plain `Address`.
6056
+ *
6057
+ * Needed by any method whose arguments must be validated against the sender before
6058
+ * the write — on the Merkle variant the claim identity, the payout destination and
6059
+ * the submitter are three separate addresses with rules between them.
6060
+ */
6061
+ resolveSender(override, method) {
6062
+ const wallet = this.requireWallet(method);
6063
+ return accountAddress(this.resolveAccount(wallet, override, method));
6064
+ }
5810
6065
  };
5811
6066
  function createAirdropBaseClient(config) {
5812
6067
  return new AirdropBaseClient(config);
@@ -5911,11 +6166,24 @@ var EcdsaAirdropClient = class extends AirdropBaseClient {
5911
6166
  * consuming either replay guard — the same input can still be claimed for
5912
6167
  * real afterwards. No fee.
5913
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
+ *
5914
6180
  * An encrypted view: the contract calls `FHE.allow(amount, msg.sender)`, so
5915
6181
  * the result is recovered from the receipt's ACL `Allowed` event, never
5916
6182
  * from a simulation. See {@link AirdropBaseClient}'s class TSDoc.
5917
6183
  *
5918
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.
5919
6187
  */
5920
6188
  async getClaimAmount(args) {
5921
6189
  return this.encryptedView({
@@ -6115,7 +6383,8 @@ function toContractCommonParams(common) {
6115
6383
  endTime: common.endTime,
6116
6384
  canExtendClaimWindow: common.canExtendClaimWindow,
6117
6385
  unwrappable: common.unwrappable,
6118
- complianceAdmin: common.complianceAdmin
6386
+ complianceAdmin: common.complianceAdmin,
6387
+ maxAcceptedGasFee: common.maxAcceptedGasFee
6119
6388
  };
6120
6389
  }
6121
6390
  function toContractEcdsaParams(params) {
@@ -6472,11 +6741,28 @@ var ConfidentialAirdropFactoryClient = class {
6472
6741
  async airdrops(offset, limit) {
6473
6742
  return this.#read("airdrops", [offset, limit]);
6474
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
+ }
6475
6760
  /**
6476
6761
  * The compliance-manager clone bound to an instance.
6477
6762
  *
6478
- * Doubles as a provenance check: the factory records this mapping only for
6479
- * 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.
6480
6766
  *
6481
6767
  * @param airdrop Instance address.
6482
6768
  * @returns The clone address, or the zero address when unknown to this factory.
@@ -6530,6 +6816,47 @@ var ConfidentialAirdropFactoryClient = class {
6530
6816
  async defaultGasFee() {
6531
6817
  return this.#read("defaultGasFee");
6532
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
+ }
6533
6860
  // ----------------------- implementation admin -----------------------
6534
6861
  /**
6535
6862
  * Point future `createEcdsaAirdrop*` calls at a new ECDSA implementation.
@@ -6794,17 +7121,15 @@ var ConfidentialAirdropFactoryClient = class {
6794
7121
  /**
6795
7122
  * Revoke `role` from `holder`. Requires the role's admin role.
6796
7123
  *
6797
- * Unlike an airdrop instance, the factory declares no "never empty" floor:
6798
- * revoking the last `DEFAULT_ADMIN_ROLE` member succeeds, and what it
6799
- * freezes is **role administration**, permanently. `DEFAULT_ADMIN_ROLE`
6800
- * administers all four operational roles and itself, so with the set empty
6801
- * no role can ever be granted or revoked again - including putting an admin
6802
- * back. The four operational roles keep working for whoever already holds
6803
- * them: a `FEE_MANAGER_ROLE` holder can still call {@link setDefaultGasFee},
6804
- * an `IMPL_MANAGER_ROLE` holder can still rotate an implementation. The
6805
- * factory therefore keeps running with exactly the role holders it had at
6806
- * that moment, with no way to rotate or remove them. Grant the successor
6807
- * 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.
6808
7133
  *
6809
7134
  * @returns The transaction hash.
6810
7135
  */
@@ -6876,11 +7201,15 @@ var ConfidentialAirdropFactoryClient = class {
6876
7201
  /**
6877
7202
  * The create-time guardrails that need a read, run before anything is sent.
6878
7203
  *
6879
- * Two checks, in the order a failure is cheapest to discover:
7204
+ * Three checks, in the order a failure is cheapest to discover:
6880
7205
  *
6881
- * 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
6882
7211
  * `underlying()` probe (see {@link NonStockWrapperError}).
6883
- * 2. **Salt collision.** A predicted address commits to `(implementation,
7212
+ * 3. **Salt collision.** A predicted address commits to `(implementation,
6884
7213
  * mode, deployer, userSalt)` and ignores the params struct entirely, so
6885
7214
  * two campaigns differing only in token, window, signer or root still
6886
7215
  * land on one address. The prediction plus one `eth_getCode` turns that
@@ -6891,6 +7220,12 @@ var ConfidentialAirdropFactoryClient = class {
6891
7220
  */
6892
7221
  async #guardCreate(input) {
6893
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
+ });
6894
7229
  await assertStockWrapper({
6895
7230
  publicClient: this.publicClient,
6896
7231
  token: args.params.common.token,
@@ -7330,22 +7665,6 @@ var merkleConfidentialAirdropAbi = [
7330
7665
  name: "SafeERC20FailedOperation",
7331
7666
  type: "error"
7332
7667
  },
7333
- {
7334
- inputs: [
7335
- {
7336
- internalType: "bytes32",
7337
- name: "handle",
7338
- type: "bytes32"
7339
- },
7340
- {
7341
- internalType: "address",
7342
- name: "sender",
7343
- type: "address"
7344
- }
7345
- ],
7346
- name: "SenderNotAllowedToUseHandle",
7347
- type: "error"
7348
- },
7349
7668
  {
7350
7669
  inputs: [],
7351
7670
  name: "TokenNotAWrapper",
@@ -7372,11 +7691,32 @@ var merkleConfidentialAirdropAbi = [
7372
7691
  name: "UUPSUnsupportedProxiableUUID",
7373
7692
  type: "error"
7374
7693
  },
7694
+ {
7695
+ inputs: [
7696
+ {
7697
+ internalType: "address",
7698
+ name: "account",
7699
+ type: "address"
7700
+ },
7701
+ {
7702
+ internalType: "address",
7703
+ name: "to",
7704
+ type: "address"
7705
+ }
7706
+ ],
7707
+ name: "UnauthorizedRedirect",
7708
+ type: "error"
7709
+ },
7375
7710
  {
7376
7711
  inputs: [],
7377
7712
  name: "ZamaProtocolUnsupported",
7378
7713
  type: "error"
7379
7714
  },
7715
+ {
7716
+ inputs: [],
7717
+ name: "ZeroAccount",
7718
+ type: "error"
7719
+ },
7380
7720
  {
7381
7721
  inputs: [],
7382
7722
  name: "ZeroAdminGrant",
@@ -7417,6 +7757,11 @@ var merkleConfidentialAirdropAbi = [
7417
7757
  name: "ZeroToken",
7418
7758
  type: "error"
7419
7759
  },
7760
+ {
7761
+ inputs: [],
7762
+ name: "ZeroUnwrapRequestId",
7763
+ type: "error"
7764
+ },
7420
7765
  {
7421
7766
  anonymous: false,
7422
7767
  inputs: [
@@ -7449,6 +7794,12 @@ var merkleConfidentialAirdropAbi = [
7449
7794
  internalType: "uint256",
7450
7795
  name: "deploymentBlockNumber",
7451
7796
  type: "uint256"
7797
+ },
7798
+ {
7799
+ indexed: false,
7800
+ internalType: "uint256",
7801
+ name: "gasFee",
7802
+ type: "uint256"
7452
7803
  }
7453
7804
  ],
7454
7805
  name: "AirdropInitialized",
@@ -7998,11 +8349,16 @@ var merkleConfidentialAirdropAbi = [
7998
8349
  inputs: [
7999
8350
  {
8000
8351
  internalType: "address",
8001
- name: "to",
8352
+ name: "account",
8002
8353
  type: "address"
8003
8354
  },
8004
8355
  {
8005
- internalType: "externalEuint64",
8356
+ internalType: "address",
8357
+ name: "to",
8358
+ type: "address"
8359
+ },
8360
+ {
8361
+ internalType: "externalEuint64",
8006
8362
  name: "inputAmount",
8007
8363
  type: "bytes32"
8008
8364
  },
@@ -8122,6 +8478,11 @@ var merkleConfidentialAirdropAbi = [
8122
8478
  },
8123
8479
  {
8124
8480
  inputs: [
8481
+ {
8482
+ internalType: "address",
8483
+ name: "account",
8484
+ type: "address"
8485
+ },
8125
8486
  {
8126
8487
  internalType: "externalEuint64",
8127
8488
  name: "inputAmount",
@@ -8466,6 +8827,19 @@ var merkleConfidentialAirdropAbi = [
8466
8827
  stateMutability: "view",
8467
8828
  type: "function"
8468
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
+ },
8469
8843
  {
8470
8844
  inputs: [
8471
8845
  {
@@ -8674,8 +9048,8 @@ var MerkleAirdropClient = class extends AirdropBaseClient {
8674
9048
  // CLAIM
8675
9049
  // ============================================================
8676
9050
  /**
8677
- * Claim the outstanding amount for a proof-bearing entry, delivering the
8678
- * tokens to `to` (defaults to the sending account).
9051
+ * Claim the outstanding amount for a proof-bearing entry, delivering the tokens to
9052
+ * `to` — which defaults to `entry.account`, the CLAIM IDENTITY, not the sender.
8679
9053
  *
8680
9054
  * Requires `msg.value == gasFee()` exactly — handled for you; see the
8681
9055
  * class TSDoc.
@@ -8692,16 +9066,31 @@ var MerkleAirdropClient = class extends AirdropBaseClient {
8692
9066
  *
8693
9067
  * @throws {@link ClaimNotStartedError} before `startTime`.
8694
9068
  * @throws {@link ClaimWindowClosedError} after `endTime`.
8695
- * @throws {@link InvalidArgumentError} (`argument: "merkleProof"`) when the proof does not verify against
8696
- * the current root — including when `entry.recipient` does not match the sending account.
9069
+ * @throws {@link InvalidArgumentError} (`argument: "entry.boundTo"`) when the entry's proof is bound to
9070
+ * another address, or (`argument: "merkleProof"`) when the proof does not verify against the current root.
9071
+ * @throws {@link UnauthorizedRedirectError} when a third-party submitter passes a `to` other than `entry.account`.
8697
9072
  * @returns The transaction hash.
8698
9073
  */
8699
9074
  async claim(args) {
8700
9075
  return withTelemetry(this.telemetry, `${this.spanPrefix}.claim`, async () => {
9076
+ const submitter = this.resolveSender(args.account, "claim");
9077
+ assertMerkleClaimIdentity({
9078
+ method: "claim",
9079
+ account: args.entry.account,
9080
+ boundTo: args.entry.boundTo,
9081
+ submitter,
9082
+ to: args.to
9083
+ });
8701
9084
  const fee = await this.gasFee();
8702
9085
  return this.write(
8703
9086
  "claim",
8704
- [args.to ?? zeroAddress, args.entry.handle, args.entry.inputProof, args.entry.merkleProof],
9087
+ [
9088
+ args.entry.account,
9089
+ args.to ?? zeroAddress,
9090
+ args.entry.handle,
9091
+ args.entry.inputProof,
9092
+ args.entry.merkleProof
9093
+ ],
8705
9094
  args.account,
8706
9095
  "claim",
8707
9096
  fee
@@ -8717,12 +9106,29 @@ var MerkleAirdropClient = class extends AirdropBaseClient {
8717
9106
  * Same replay/accounting semantics and `msg.value == gasFee()` requirement
8718
9107
  * as {@link claim} — see its `@remarks`.
8719
9108
  *
9109
+ * @remarks
9110
+ * **Self-only by design.** This entrypoint takes no claim identity: releasing an
9111
+ * allocation as a public ERC-20 transfer publishes the amount irreversibly, which is
9112
+ * the recipient's own choice to make. A relayed unwrap is therefore unrepresentable
9113
+ * rather than merely rejected, and an entry whose `account` is not the sender is
9114
+ * refused before the write. A third party can still submit a confidential
9115
+ * {@link claim}.
9116
+ *
8720
9117
  * @returns The transaction hash. The underlying ERC-20 is released later by
8721
9118
  * a separate, permissionless `finalizeUnwrap` — this hash is only the
8722
9119
  * unwrap request.
8723
9120
  */
8724
9121
  async claimAndUnwrap(args) {
8725
9122
  return withTelemetry(this.telemetry, `${this.spanPrefix}.claimAndUnwrap`, async () => {
9123
+ const submitter = this.resolveSender(args.account, "claimAndUnwrap");
9124
+ assertMerkleClaimIdentity({
9125
+ method: "claimAndUnwrap",
9126
+ account: args.entry.account,
9127
+ boundTo: args.entry.boundTo,
9128
+ submitter,
9129
+ to: args.to,
9130
+ entrypoint: "claimAndUnwrap"
9131
+ });
8726
9132
  const fee = await this.gasFee();
8727
9133
  return this.write(
8728
9134
  "claimAndUnwrap",
@@ -8738,16 +9144,32 @@ var MerkleAirdropClient = class extends AirdropBaseClient {
8738
9144
  * caller can decrypt. Consumes no accounting and no per-leaf state — the
8739
9145
  * same entry still pays the same amount after a preview. No fee.
8740
9146
  *
8741
- * An encrypted view: the contract calls `FHE.allow(outstanding, msg.sender)`,
8742
- * so the result is recovered from the receipt's ACL `Allowed` event, never
8743
- * from a simulation. See {@link AirdropBaseClient}'s class TSDoc.
9147
+ * **Submits a transaction.** The contract calls `FHE.allow(outstanding, account)`, so
9148
+ * the result is recovered from the receipt's ACL `Allowed` event, never from a
9149
+ * simulation. See {@link AirdropBaseClient}'s class TSDoc.
8744
9150
  *
8745
- * @returns `{ handle, hash }` — pass `handle` to the Zama relayer's `userDecrypt`.
9151
+ * **`entry.account` is the decryptable party, not the caller.** A relayer previewing on
9152
+ * someone's behalf gets a valid handle it cannot read — that is the contract's intent,
9153
+ * and it is what makes a blind relayed submission possible.
9154
+ *
9155
+ * @returns `{ handle, hash }` — pass `handle` to the Zama relayer's `userDecrypt`, as `entry.account`.
8746
9156
  */
8747
9157
  async getClaimAmount(args) {
9158
+ const submitter = this.resolveSender(args.account, "getClaimAmount");
9159
+ assertMerkleClaimIdentity({
9160
+ method: "getClaimAmount",
9161
+ account: args.entry.account,
9162
+ boundTo: args.entry.boundTo,
9163
+ submitter
9164
+ });
8748
9165
  return this.encryptedView({
8749
9166
  functionName: "getClaimAmount",
8750
- args: [args.entry.handle, args.entry.inputProof, args.entry.merkleProof],
9167
+ args: [args.entry.account, args.entry.handle, args.entry.inputProof, args.entry.merkleProof],
9168
+ // The contract grants the outstanding handle to `account`, never to the caller
9169
+ // (`_outstandingOf(account, account, …)`), so the receipt's ACL `Allowed` event
9170
+ // names the account. Defaulting to the sender would fail extraction on any
9171
+ // relayed preview — after the transaction had already been mined.
9172
+ grantee: args.entry.account,
8751
9173
  account: args.account
8752
9174
  });
8753
9175
  }
@@ -8770,10 +9192,15 @@ var MerkleAirdropClient = class extends AirdropBaseClient {
8770
9192
  * leaves for the same recipient, claiming both pays the higher of the
8771
9193
  * two totals net of this running value — `max`, not `sum`.
8772
9194
  *
8773
- * The zero handle (uninitialized ciphertext) before an account's first
8774
- * settled claim decrypts as zero.
9195
+ * **An account that has never claimed returns the ZERO handle, which cannot be
9196
+ * decrypted.** It is an uninitialized ciphertext, so nobody holds an ACL on it and
9197
+ * the relayer rejects it with "not authorized to user decrypt handle 0x0…0" rather
9198
+ * than answering zero. Treat `handle === zeroHash` as "nothing delivered yet" and
9199
+ * skip the decrypt; only call `userDecrypt` on a non-zero handle. (A mock FHEVM
9200
+ * instance does answer zero here, so this only bites against a live relayer.)
8775
9201
  *
8776
- * @returns The account's cumulative delivered total, as an encrypted handle.
9202
+ * @returns The account's cumulative delivered total as an encrypted handle, or the
9203
+ * zero handle if it has never claimed.
8777
9204
  */
8778
9205
  async getClaimedAmount(account) {
8779
9206
  const handle = await this.read("getClaimedAmount", [account]);
@@ -8820,4 +9247,919 @@ function createMerkleAirdropClient(config) {
8820
9247
  return new MerkleAirdropClient(config);
8821
9248
  }
8822
9249
 
8823
- export { AirdropBaseClient, CLAIM_TYPEHASH, CLAIM_TYPES, ConfidentialAirdropFactoryClient, EIP712_DOMAIN_NAME, EIP712_DOMAIN_VERSION, EcdsaAirdropClient, FACTORY_ROLE_CONCENTRATION_NOTE, MerkleAirdropClient, airdropFactoryAbi, confidentialAirdropBaseAbi, createAirdropBaseClient, createConfidentialAirdropFactoryClient, createEcdsaAirdropClient, createMerkleAirdropClient, ecdsaConfidentialAirdropAbi, encryptUint64, encryptUint64Batch, merkleConfidentialAirdropAbi, resolveEncryptor, signClaimAuthorization };
9250
+ // src/fhe-airdrop/abis/compliance.ts
9251
+ var complianceRoleManagerAbi = [
9252
+ {
9253
+ inputs: [],
9254
+ stateMutability: "nonpayable",
9255
+ type: "constructor"
9256
+ },
9257
+ {
9258
+ inputs: [],
9259
+ name: "AccessControlBadConfirmation",
9260
+ type: "error"
9261
+ },
9262
+ {
9263
+ inputs: [
9264
+ {
9265
+ internalType: "address",
9266
+ name: "account",
9267
+ type: "address"
9268
+ },
9269
+ {
9270
+ internalType: "bytes32",
9271
+ name: "neededRole",
9272
+ type: "bytes32"
9273
+ }
9274
+ ],
9275
+ name: "AccessControlUnauthorizedAccount",
9276
+ type: "error"
9277
+ },
9278
+ {
9279
+ inputs: [
9280
+ {
9281
+ internalType: "address",
9282
+ name: "airdrop",
9283
+ type: "address"
9284
+ }
9285
+ ],
9286
+ name: "AirdropAndManagerAreSameAddress",
9287
+ type: "error"
9288
+ },
9289
+ {
9290
+ inputs: [],
9291
+ name: "CannotManageComplianceDelegate",
9292
+ type: "error"
9293
+ },
9294
+ {
9295
+ inputs: [],
9296
+ name: "DelegateAlreadyAdded",
9297
+ type: "error"
9298
+ },
9299
+ {
9300
+ inputs: [
9301
+ {
9302
+ internalType: "address",
9303
+ name: "delegate",
9304
+ type: "address"
9305
+ }
9306
+ ],
9307
+ name: "DelegateAndAirdropAreSameAddress",
9308
+ type: "error"
9309
+ },
9310
+ {
9311
+ inputs: [
9312
+ {
9313
+ internalType: "address",
9314
+ name: "delegate",
9315
+ type: "address"
9316
+ }
9317
+ ],
9318
+ name: "DelegateAndManagerAreSameAddress",
9319
+ type: "error"
9320
+ },
9321
+ {
9322
+ inputs: [],
9323
+ name: "DelegateNotFound",
9324
+ type: "error"
9325
+ },
9326
+ {
9327
+ inputs: [],
9328
+ name: "InvalidInitialization",
9329
+ type: "error"
9330
+ },
9331
+ {
9332
+ inputs: [],
9333
+ name: "NotInitializing",
9334
+ type: "error"
9335
+ },
9336
+ {
9337
+ inputs: [],
9338
+ name: "ZamaProtocolUnsupported",
9339
+ type: "error"
9340
+ },
9341
+ {
9342
+ inputs: [],
9343
+ name: "ZeroAirdrop",
9344
+ type: "error"
9345
+ },
9346
+ {
9347
+ inputs: [],
9348
+ name: "ZeroClientAdmin",
9349
+ type: "error"
9350
+ },
9351
+ {
9352
+ inputs: [],
9353
+ name: "ZeroDelegate",
9354
+ type: "error"
9355
+ },
9356
+ {
9357
+ anonymous: false,
9358
+ inputs: [
9359
+ {
9360
+ indexed: true,
9361
+ internalType: "address",
9362
+ name: "delegate",
9363
+ type: "address"
9364
+ }
9365
+ ],
9366
+ name: "ClientDelegateAdded",
9367
+ type: "event"
9368
+ },
9369
+ {
9370
+ anonymous: false,
9371
+ inputs: [
9372
+ {
9373
+ indexed: true,
9374
+ internalType: "address",
9375
+ name: "delegate",
9376
+ type: "address"
9377
+ }
9378
+ ],
9379
+ name: "ClientDelegateRevoked",
9380
+ type: "event"
9381
+ },
9382
+ {
9383
+ anonymous: false,
9384
+ inputs: [
9385
+ {
9386
+ indexed: true,
9387
+ internalType: "address",
9388
+ name: "delegate",
9389
+ type: "address"
9390
+ }
9391
+ ],
9392
+ name: "ComplianceDelegateSet",
9393
+ type: "event"
9394
+ },
9395
+ {
9396
+ anonymous: false,
9397
+ inputs: [
9398
+ {
9399
+ indexed: false,
9400
+ internalType: "uint64",
9401
+ name: "version",
9402
+ type: "uint64"
9403
+ }
9404
+ ],
9405
+ name: "Initialized",
9406
+ type: "event"
9407
+ },
9408
+ {
9409
+ anonymous: false,
9410
+ inputs: [
9411
+ {
9412
+ indexed: true,
9413
+ internalType: "bytes32",
9414
+ name: "role",
9415
+ type: "bytes32"
9416
+ },
9417
+ {
9418
+ indexed: true,
9419
+ internalType: "bytes32",
9420
+ name: "previousAdminRole",
9421
+ type: "bytes32"
9422
+ },
9423
+ {
9424
+ indexed: true,
9425
+ internalType: "bytes32",
9426
+ name: "newAdminRole",
9427
+ type: "bytes32"
9428
+ }
9429
+ ],
9430
+ name: "RoleAdminChanged",
9431
+ type: "event"
9432
+ },
9433
+ {
9434
+ anonymous: false,
9435
+ inputs: [
9436
+ {
9437
+ indexed: true,
9438
+ internalType: "bytes32",
9439
+ name: "role",
9440
+ type: "bytes32"
9441
+ },
9442
+ {
9443
+ indexed: true,
9444
+ internalType: "address",
9445
+ name: "account",
9446
+ type: "address"
9447
+ },
9448
+ {
9449
+ indexed: true,
9450
+ internalType: "address",
9451
+ name: "sender",
9452
+ type: "address"
9453
+ }
9454
+ ],
9455
+ name: "RoleGranted",
9456
+ type: "event"
9457
+ },
9458
+ {
9459
+ anonymous: false,
9460
+ inputs: [
9461
+ {
9462
+ indexed: true,
9463
+ internalType: "bytes32",
9464
+ name: "role",
9465
+ type: "bytes32"
9466
+ },
9467
+ {
9468
+ indexed: true,
9469
+ internalType: "address",
9470
+ name: "account",
9471
+ type: "address"
9472
+ },
9473
+ {
9474
+ indexed: true,
9475
+ internalType: "address",
9476
+ name: "sender",
9477
+ type: "address"
9478
+ }
9479
+ ],
9480
+ name: "RoleRevoked",
9481
+ type: "event"
9482
+ },
9483
+ {
9484
+ inputs: [],
9485
+ name: "DEFAULT_ADMIN_ROLE",
9486
+ outputs: [
9487
+ {
9488
+ internalType: "bytes32",
9489
+ name: "",
9490
+ type: "bytes32"
9491
+ }
9492
+ ],
9493
+ stateMutability: "view",
9494
+ type: "function"
9495
+ },
9496
+ {
9497
+ inputs: [],
9498
+ name: "DELEGATION_ADMIN_ROLE",
9499
+ outputs: [
9500
+ {
9501
+ internalType: "bytes32",
9502
+ name: "",
9503
+ type: "bytes32"
9504
+ }
9505
+ ],
9506
+ stateMutability: "view",
9507
+ type: "function"
9508
+ },
9509
+ {
9510
+ inputs: [
9511
+ {
9512
+ internalType: "address",
9513
+ name: "delegate",
9514
+ type: "address"
9515
+ }
9516
+ ],
9517
+ name: "addDelegate",
9518
+ outputs: [],
9519
+ stateMutability: "nonpayable",
9520
+ type: "function"
9521
+ },
9522
+ {
9523
+ inputs: [],
9524
+ name: "airdrop",
9525
+ outputs: [
9526
+ {
9527
+ internalType: "address",
9528
+ name: "",
9529
+ type: "address"
9530
+ }
9531
+ ],
9532
+ stateMutability: "view",
9533
+ type: "function"
9534
+ },
9535
+ {
9536
+ inputs: [],
9537
+ name: "clientDelegates",
9538
+ outputs: [
9539
+ {
9540
+ internalType: "address[]",
9541
+ name: "",
9542
+ type: "address[]"
9543
+ }
9544
+ ],
9545
+ stateMutability: "view",
9546
+ type: "function"
9547
+ },
9548
+ {
9549
+ inputs: [],
9550
+ name: "complianceDelegate",
9551
+ outputs: [
9552
+ {
9553
+ internalType: "address",
9554
+ name: "",
9555
+ type: "address"
9556
+ }
9557
+ ],
9558
+ stateMutability: "view",
9559
+ type: "function"
9560
+ },
9561
+ {
9562
+ inputs: [
9563
+ {
9564
+ internalType: "bytes32",
9565
+ name: "role",
9566
+ type: "bytes32"
9567
+ }
9568
+ ],
9569
+ name: "getRoleAdmin",
9570
+ outputs: [
9571
+ {
9572
+ internalType: "bytes32",
9573
+ name: "",
9574
+ type: "bytes32"
9575
+ }
9576
+ ],
9577
+ stateMutability: "view",
9578
+ type: "function"
9579
+ },
9580
+ {
9581
+ inputs: [
9582
+ {
9583
+ internalType: "bytes32",
9584
+ name: "role",
9585
+ type: "bytes32"
9586
+ },
9587
+ {
9588
+ internalType: "uint256",
9589
+ name: "index",
9590
+ type: "uint256"
9591
+ }
9592
+ ],
9593
+ name: "getRoleMember",
9594
+ outputs: [
9595
+ {
9596
+ internalType: "address",
9597
+ name: "",
9598
+ type: "address"
9599
+ }
9600
+ ],
9601
+ stateMutability: "view",
9602
+ type: "function"
9603
+ },
9604
+ {
9605
+ inputs: [
9606
+ {
9607
+ internalType: "bytes32",
9608
+ name: "role",
9609
+ type: "bytes32"
9610
+ }
9611
+ ],
9612
+ name: "getRoleMemberCount",
9613
+ outputs: [
9614
+ {
9615
+ internalType: "uint256",
9616
+ name: "",
9617
+ type: "uint256"
9618
+ }
9619
+ ],
9620
+ stateMutability: "view",
9621
+ type: "function"
9622
+ },
9623
+ {
9624
+ inputs: [
9625
+ {
9626
+ internalType: "bytes32",
9627
+ name: "role",
9628
+ type: "bytes32"
9629
+ }
9630
+ ],
9631
+ name: "getRoleMembers",
9632
+ outputs: [
9633
+ {
9634
+ internalType: "address[]",
9635
+ name: "",
9636
+ type: "address[]"
9637
+ }
9638
+ ],
9639
+ stateMutability: "view",
9640
+ type: "function"
9641
+ },
9642
+ {
9643
+ inputs: [
9644
+ {
9645
+ internalType: "bytes32",
9646
+ name: "role",
9647
+ type: "bytes32"
9648
+ },
9649
+ {
9650
+ internalType: "address",
9651
+ name: "account",
9652
+ type: "address"
9653
+ }
9654
+ ],
9655
+ name: "grantRole",
9656
+ outputs: [],
9657
+ stateMutability: "nonpayable",
9658
+ type: "function"
9659
+ },
9660
+ {
9661
+ inputs: [
9662
+ {
9663
+ internalType: "bytes32",
9664
+ name: "role",
9665
+ type: "bytes32"
9666
+ },
9667
+ {
9668
+ internalType: "address",
9669
+ name: "account",
9670
+ type: "address"
9671
+ }
9672
+ ],
9673
+ name: "hasRole",
9674
+ outputs: [
9675
+ {
9676
+ internalType: "bool",
9677
+ name: "",
9678
+ type: "bool"
9679
+ }
9680
+ ],
9681
+ stateMutability: "view",
9682
+ type: "function"
9683
+ },
9684
+ {
9685
+ inputs: [
9686
+ {
9687
+ internalType: "address",
9688
+ name: "airdrop_",
9689
+ type: "address"
9690
+ },
9691
+ {
9692
+ internalType: "address",
9693
+ name: "clientAdmin",
9694
+ type: "address"
9695
+ },
9696
+ {
9697
+ internalType: "address",
9698
+ name: "clientDelegate",
9699
+ type: "address"
9700
+ },
9701
+ {
9702
+ internalType: "address",
9703
+ name: "complianceDelegate_",
9704
+ type: "address"
9705
+ }
9706
+ ],
9707
+ name: "initialize",
9708
+ outputs: [],
9709
+ stateMutability: "nonpayable",
9710
+ type: "function"
9711
+ },
9712
+ {
9713
+ inputs: [
9714
+ {
9715
+ internalType: "address",
9716
+ name: "delegate",
9717
+ type: "address"
9718
+ }
9719
+ ],
9720
+ name: "isActiveDelegate",
9721
+ outputs: [
9722
+ {
9723
+ internalType: "bool",
9724
+ name: "",
9725
+ type: "bool"
9726
+ }
9727
+ ],
9728
+ stateMutability: "view",
9729
+ type: "function"
9730
+ },
9731
+ {
9732
+ inputs: [
9733
+ {
9734
+ internalType: "bytes32",
9735
+ name: "role",
9736
+ type: "bytes32"
9737
+ },
9738
+ {
9739
+ internalType: "address",
9740
+ name: "callerConfirmation",
9741
+ type: "address"
9742
+ }
9743
+ ],
9744
+ name: "renounceRole",
9745
+ outputs: [],
9746
+ stateMutability: "nonpayable",
9747
+ type: "function"
9748
+ },
9749
+ {
9750
+ inputs: [
9751
+ {
9752
+ internalType: "address",
9753
+ name: "delegate",
9754
+ type: "address"
9755
+ }
9756
+ ],
9757
+ name: "revokeDelegate",
9758
+ outputs: [],
9759
+ stateMutability: "nonpayable",
9760
+ type: "function"
9761
+ },
9762
+ {
9763
+ inputs: [
9764
+ {
9765
+ internalType: "bytes32",
9766
+ name: "role",
9767
+ type: "bytes32"
9768
+ },
9769
+ {
9770
+ internalType: "address",
9771
+ name: "account",
9772
+ type: "address"
9773
+ }
9774
+ ],
9775
+ name: "revokeRole",
9776
+ outputs: [],
9777
+ stateMutability: "nonpayable",
9778
+ type: "function"
9779
+ },
9780
+ {
9781
+ inputs: [
9782
+ {
9783
+ internalType: "bytes4",
9784
+ name: "interfaceId",
9785
+ type: "bytes4"
9786
+ }
9787
+ ],
9788
+ name: "supportsInterface",
9789
+ outputs: [
9790
+ {
9791
+ internalType: "bool",
9792
+ name: "",
9793
+ type: "bool"
9794
+ }
9795
+ ],
9796
+ stateMutability: "view",
9797
+ type: "function"
9798
+ }
9799
+ ];
9800
+
9801
+ // src/fhe-airdrop/compliance.ts
9802
+ var ACL_PROPAGATION_CODE = "DELEGATION_NOT_PROPAGATED";
9803
+ var ACL_PROPAGATION_ERROR_NAME = "DelegationNotPropagatedError";
9804
+ var ACL_PROPAGATION_STATUSES = /* @__PURE__ */ new Set([400, 500]);
9805
+ function matchesPropagationMessage(message) {
9806
+ const lower = message.toLowerCase();
9807
+ if (lower.includes("acl check not propagated")) return true;
9808
+ return lower.includes("propagat") && lower.includes("gateway");
9809
+ }
9810
+ function readRecord(value) {
9811
+ return typeof value === "object" && value !== null ? value : void 0;
9812
+ }
9813
+ function readNumber(obj, key) {
9814
+ const value = obj?.[key];
9815
+ return typeof value === "number" ? value : void 0;
9816
+ }
9817
+ function readString(obj, key) {
9818
+ const value = obj?.[key];
9819
+ return typeof value === "string" ? value : void 0;
9820
+ }
9821
+ function isAclPropagationError(error) {
9822
+ const err = readRecord(error);
9823
+ if (!err) return false;
9824
+ const cause = readRecord(err["cause"]);
9825
+ if (err["code"] === ACL_PROPAGATION_CODE || err["name"] === ACL_PROPAGATION_ERROR_NAME || cause?.["code"] === ACL_PROPAGATION_CODE || cause?.["name"] === ACL_PROPAGATION_ERROR_NAME) {
9826
+ return true;
9827
+ }
9828
+ const status = readNumber(err, "status") ?? readNumber(err, "statusCode") ?? readNumber(cause, "status") ?? readNumber(cause, "statusCode");
9829
+ if (status === void 0 || !ACL_PROPAGATION_STATUSES.has(status)) return false;
9830
+ const errMessage = readString(err, "message");
9831
+ const causeMessage = readString(cause, "message");
9832
+ return errMessage !== void 0 && matchesPropagationMessage(errMessage) || causeMessage !== void 0 && matchesPropagationMessage(causeMessage);
9833
+ }
9834
+ var ComplianceManagerClient = class {
9835
+ publicClient;
9836
+ walletClient;
9837
+ address;
9838
+ chainId;
9839
+ #telemetry;
9840
+ constructor(config) {
9841
+ this.publicClient = config.publicClient;
9842
+ this.walletClient = config.walletClient;
9843
+ const chainId = config.chainId ?? config.publicClient.chain?.id;
9844
+ if (chainId === void 0) {
9845
+ throw new DeploymentAddressUnavailableError({
9846
+ reason: "chain-id-missing",
9847
+ product: "fheAirdrop",
9848
+ contract: "complianceManager",
9849
+ clientLabel: "ComplianceManagerClient"
9850
+ });
9851
+ }
9852
+ assertSupportedChain(chainId);
9853
+ this.chainId = chainId;
9854
+ this.address = normaliseAddress(config.address);
9855
+ this.#telemetry = config.telemetry;
9856
+ this.#telemetry?.event("fhe-airdrop.client.init", {
9857
+ surface: "compliance",
9858
+ chainId,
9859
+ hasWallet: !!this.walletClient,
9860
+ sdkVersion: SDK_VERSION
9861
+ });
9862
+ }
9863
+ // ============================================================
9864
+ // CLIENT DELEGATION MGMT
9865
+ // ============================================================
9866
+ /**
9867
+ * Add a client delegate: grants `delegate` permanent (never-expiring)
9868
+ * user-decryption delegation over this clone's airdrop. Requires
9869
+ * {@link DELEGATION_ADMIN_ROLE}.
9870
+ *
9871
+ * Effective on-chain immediately; see the class TSDoc for the gateway
9872
+ * propagation lag before `delegatedUserDecrypt` catches up.
9873
+ *
9874
+ * @throws {@link InvalidArgumentError} (`argument: "delegate"`) when `delegate` is the zero address
9875
+ * (`ZeroDelegate`), already an active client delegate (`DelegateAlreadyAdded`), or targets the
9876
+ * irrevocable platform compliance delegate (`CannotManageComplianceDelegate`).
9877
+ * @returns The transaction hash.
9878
+ */
9879
+ async addDelegate(args) {
9880
+ return withTelemetry(
9881
+ this.#telemetry,
9882
+ "fhe-airdrop.compliance.addDelegate",
9883
+ () => this.#write("addDelegate", [args.delegate], args.account, "addDelegate")
9884
+ );
9885
+ }
9886
+ /**
9887
+ * Revoke a client delegate. Requires {@link DELEGATION_ADMIN_ROLE}.
9888
+ *
9889
+ * Effective on-chain immediately — but off-chain, gateway-served
9890
+ * `delegatedUserDecrypt` calls stop succeeding only once the gateway
9891
+ * observes the revocation, which is not instantaneous either. Cannot target
9892
+ * the platform compliance delegate, which is irrevocable by construction.
9893
+ *
9894
+ * **Not in the same block as {@link addDelegate} for the same delegate.**
9895
+ * The FHEVM ACL rejects an add and a revoke of one delegate within a single
9896
+ * block (`AlreadyDelegatedOrRevokedInSameBlock`), and because that revert
9897
+ * comes from the ACL rather than from this contract, it surfaces as an
9898
+ * opaque {@link ContractRevertError} with no decodable selector — nothing
9899
+ * names the delegate or the cause. Batching an add and a revoke into one
9900
+ * multicall, or sending both inside one block, is the way to hit it; wait a
9901
+ * block between them. This is the sequencing counterpart to the propagation
9902
+ * gotcha on the class TSDoc: that one is the gateway lagging the chain, this
9903
+ * one is the chain refusing two conflicting writes at the same height.
9904
+ *
9905
+ * @throws {@link InvalidArgumentError} (`argument: "delegate"`) when `delegate` is the zero address
9906
+ * (`ZeroDelegate`), not currently an active client delegate (`DelegateNotFound`), or targets the
9907
+ * irrevocable platform compliance delegate (`CannotManageComplianceDelegate`).
9908
+ * @returns The transaction hash.
9909
+ */
9910
+ async revokeDelegate(args) {
9911
+ return withTelemetry(
9912
+ this.#telemetry,
9913
+ "fhe-airdrop.compliance.revokeDelegate",
9914
+ () => this.#write("revokeDelegate", [args.delegate], args.account, "revokeDelegate")
9915
+ );
9916
+ }
9917
+ // ============================================================
9918
+ // READS
9919
+ // ============================================================
9920
+ /** The one airdrop instance this clone serves — set once, at `initialize`. */
9921
+ async airdrop() {
9922
+ return this.#read("airdrop");
9923
+ }
9924
+ /**
9925
+ * The platform compliance delegate.
9926
+ *
9927
+ * @returns The delegate address, or the zero address when this clone was
9928
+ * created with the platform compliance policy OFF. Because `initialize`
9929
+ * always runs atomically before this client can reach the clone (see the
9930
+ * class TSDoc), a zero return never means "not wired yet" — there is no
9931
+ * such observable state on this contract. It unambiguously means "no
9932
+ * platform delegate for this airdrop."
9933
+ */
9934
+ async complianceDelegate() {
9935
+ return this.#read("complianceDelegate");
9936
+ }
9937
+ /** The current set of active client delegates (excludes the platform compliance delegate, if any). */
9938
+ async clientDelegates() {
9939
+ return this.#read("clientDelegates");
9940
+ }
9941
+ /**
9942
+ * Authoritative active-delegate check for `delegate` — reads the ACL
9943
+ * expiration date directly rather than the contract's `EnumerableSet`
9944
+ * mirror, so it reflects the platform compliance delegate too (which never
9945
+ * appears in {@link clientDelegates}).
9946
+ *
9947
+ * On-chain truth only: a `true` result means the delegation is live in the
9948
+ * ACL, not that the gateway has caught up with it yet — see the class
9949
+ * TSDoc's propagation note.
9950
+ */
9951
+ async isActiveDelegate(delegate) {
9952
+ return this.#read("isActiveDelegate", [delegate]);
9953
+ }
9954
+ // Role-constant getters are named for the contract function they read, the
9955
+ // same convention every other client in this module follows: one spelling
9956
+ // per role, whichever client you happen to be holding.
9957
+ /** Gates {@link addDelegate} / {@link revokeDelegate}. */
9958
+ async DELEGATION_ADMIN_ROLE() {
9959
+ return this.#read("DELEGATION_ADMIN_ROLE");
9960
+ }
9961
+ /**
9962
+ * OpenZeppelin's root role (`bytes32(0)`), read from the clone rather than
9963
+ * hard-coded. It administers {@link DELEGATION_ADMIN_ROLE}.
9964
+ */
9965
+ async DEFAULT_ADMIN_ROLE() {
9966
+ return this.#read("DEFAULT_ADMIN_ROLE");
9967
+ }
9968
+ // ============================================================
9969
+ // ROLE ADMINISTRATION
9970
+ // ============================================================
9971
+ //
9972
+ // The clone is `AccessControlEnumerableUpgradeable`, so membership is
9973
+ // enumerable as well as checkable. This surface is what makes the delegation
9974
+ // verbs above administrable: without it, whoever the factory named at
9975
+ // `initialize` is the only account that can ever add a delegate, and there
9976
+ // is no way to find out who that is.
9977
+ //
9978
+ // Unlike an airdrop instance, this contract adds no "never empty" floor of
9979
+ // its own - emptying `DEFAULT_ADMIN_ROLE` here permanently freezes the
9980
+ // clone's delegate set at whatever it currently holds.
9981
+ /**
9982
+ * Whether `holder` holds `role`.
9983
+ *
9984
+ * The role subject is called `holder`, not `account`: on the writes below
9985
+ * `account` already means "who sends this transaction", and one key cannot
9986
+ * be both.
9987
+ *
9988
+ * @param args.role A `bytes32` from {@link DELEGATION_ADMIN_ROLE} or {@link DEFAULT_ADMIN_ROLE}.
9989
+ */
9990
+ async hasRole(args) {
9991
+ return this.#read("hasRole", [args.role, args.holder]);
9992
+ }
9993
+ /** The role whose holders may {@link grantRole} and {@link revokeRole} `role`. */
9994
+ async getRoleAdmin(role) {
9995
+ return this.#read("getRoleAdmin", [role]);
9996
+ }
9997
+ /** How many accounts hold `role`. */
9998
+ async getRoleMemberCount(role) {
9999
+ return this.#read("getRoleMemberCount", [role]);
10000
+ }
10001
+ /**
10002
+ * The `index`-th holder of `role`, in `EnumerableSet` order - which is not
10003
+ * stable across grants and revokes. Prefer {@link getRoleMembers}.
10004
+ */
10005
+ async getRoleMember(args) {
10006
+ return this.#read("getRoleMember", [args.role, args.index]);
10007
+ }
10008
+ /**
10009
+ * Every account currently holding `role`.
10010
+ *
10011
+ * With {@link DELEGATION_ADMIN_ROLE} this answers "who may add or revoke a
10012
+ * delegate on this clone?" - the administrative counterpart to
10013
+ * {@link clientDelegates}, which answers "who may currently decrypt?".
10014
+ */
10015
+ async getRoleMembers(role) {
10016
+ return this.#read("getRoleMembers", [role]);
10017
+ }
10018
+ /**
10019
+ * Grant `role` to `holder`. Requires the role's admin role
10020
+ * ({@link getRoleAdmin}).
10021
+ *
10022
+ * This is how a second operator is added to {@link DELEGATION_ADMIN_ROLE} -
10023
+ * the delegation verbs themselves are unaffected, the grant only widens who
10024
+ * may call them.
10025
+ *
10026
+ * @returns The transaction hash.
10027
+ */
10028
+ async grantRole(args) {
10029
+ return withTelemetry(
10030
+ this.#telemetry,
10031
+ "fhe-airdrop.compliance.grantRole",
10032
+ () => this.#write("grantRole", [args.role, args.holder], args.account, "grantRole")
10033
+ );
10034
+ }
10035
+ /**
10036
+ * Revoke `role` from `holder`. Requires the role's admin role.
10037
+ *
10038
+ * Revoking a delegation admin does **not** revoke the delegations they
10039
+ * created: an existing delegate keeps decrypting until
10040
+ * {@link revokeDelegate} is called for it explicitly.
10041
+ *
10042
+ * @returns The transaction hash.
10043
+ */
10044
+ async revokeRole(args) {
10045
+ return withTelemetry(
10046
+ this.#telemetry,
10047
+ "fhe-airdrop.compliance.revokeRole",
10048
+ () => this.#write("revokeRole", [args.role, args.holder], args.account, "revokeRole")
10049
+ );
10050
+ }
10051
+ /**
10052
+ * Give up `role` yourself.
10053
+ *
10054
+ * The contract's signature is `renounceRole(role, callerConfirmation)` and
10055
+ * it reverts `AccessControlBadConfirmation` unless `callerConfirmation` is
10056
+ * the sender, so this method takes no holder and fills the confirmation from
10057
+ * the resolved sending account. Renouncing for somebody else is not a call
10058
+ * that can succeed; use {@link revokeRole} to remove another account's role.
10059
+ *
10060
+ * @returns The transaction hash.
10061
+ */
10062
+ async renounceRole(args) {
10063
+ const method = "renounceRole";
10064
+ const wallet = this.#requireWallet(method);
10065
+ const account = this.#resolveAccount(wallet, args.account, method);
10066
+ return withTelemetry(
10067
+ this.#telemetry,
10068
+ "fhe-airdrop.compliance.renounceRole",
10069
+ () => this.#write(method, [args.role, accountAddress3(account)], account, method)
10070
+ );
10071
+ }
10072
+ // ============================================================
10073
+ // INTERNALS (private)
10074
+ // ============================================================
10075
+ async #write(functionName, args, account, method) {
10076
+ const wallet = this.#requireWallet(method);
10077
+ const acct = this.#resolveAccount(wallet, account, method);
10078
+ await this.#preflightWrite(method, functionName, args, acct);
10079
+ try {
10080
+ return await wallet.writeContract({
10081
+ address: this.address,
10082
+ abi: complianceRoleManagerAbi,
10083
+ functionName,
10084
+ args,
10085
+ account: acct,
10086
+ chain: wallet.chain
10087
+ });
10088
+ } catch (err) {
10089
+ throw this.#mapRevert(method, err, acct);
10090
+ }
10091
+ }
10092
+ async #read(functionName, args = []) {
10093
+ const result = await this.publicClient.readContract({
10094
+ address: this.address,
10095
+ abi: complianceRoleManagerAbi,
10096
+ functionName,
10097
+ args
10098
+ });
10099
+ return result;
10100
+ }
10101
+ /**
10102
+ * Simulate a write purely to surface typed reverts.
10103
+ *
10104
+ * The simulate's return value is discarded on principle: this contract
10105
+ * returns nothing from `addDelegate` / `revokeDelegate` anyway, but the
10106
+ * pattern is kept identical to every other airdrop v2 client so a revert is
10107
+ * always decoded before the user pays for it.
10108
+ */
10109
+ async #preflightWrite(method, functionName, args, account) {
10110
+ try {
10111
+ await this.publicClient.simulateContract({
10112
+ address: this.address,
10113
+ abi: complianceRoleManagerAbi,
10114
+ functionName,
10115
+ args,
10116
+ account
10117
+ });
10118
+ } catch (err) {
10119
+ if (isContractRevert(err)) {
10120
+ throw this.#mapRevert(method, err, account);
10121
+ }
10122
+ }
10123
+ }
10124
+ /**
10125
+ * Map a viem error to the SDK's typed palette.
10126
+ *
10127
+ * `productContext` deliberately carries only public identifiers — the
10128
+ * caller, the chain. Never an amount: this contract never handles amounts
10129
+ * at all, but the convention is shared across every airdrop v2 client.
10130
+ */
10131
+ #mapRevert(method, err, account) {
10132
+ return mapContractRevert(err, {
10133
+ method,
10134
+ contractAddress: this.address,
10135
+ abi: complianceRoleManagerAbi,
10136
+ productMapper: airdropProductMapper,
10137
+ account: accountAddress3(account),
10138
+ productContext: {
10139
+ creator: accountAddress3(account),
10140
+ chainId: this.chainId
10141
+ }
10142
+ });
10143
+ }
10144
+ #requireWallet(method) {
10145
+ if (!this.walletClient) {
10146
+ throw new MissingWalletClientError(method);
10147
+ }
10148
+ return this.walletClient;
10149
+ }
10150
+ #resolveAccount(wallet, override, method) {
10151
+ const acct = override ?? wallet.account;
10152
+ if (!acct) {
10153
+ throw new MissingAccountError(method);
10154
+ }
10155
+ return acct;
10156
+ }
10157
+ };
10158
+ function createComplianceManagerClient(config) {
10159
+ return new ComplianceManagerClient(config);
10160
+ }
10161
+ function accountAddress3(account) {
10162
+ return typeof account === "string" ? account : account.address;
10163
+ }
10164
+
10165
+ export { AirdropBaseClient, CLAIM_TYPEHASH, CLAIM_TYPES, ComplianceManagerClient, ConfidentialAirdropFactoryClient, EIP712_DOMAIN_NAME, EIP712_DOMAIN_VERSION, EcdsaAirdropClient, FACTORY_ROLE_CONCENTRATION_NOTE, MerkleAirdropClient, airdropFactoryAbi, complianceRoleManagerAbi, confidentialAirdropBaseAbi, createAirdropBaseClient, createComplianceManagerClient, createConfidentialAirdropFactoryClient, createEcdsaAirdropClient, createMerkleAirdropClient, ecdsaConfidentialAirdropAbi, encryptUint64, encryptUint64Batch, isAclPropagationError, merkleConfidentialAirdropAbi, resolveEncryptor, signClaimAuthorization };