@tokenops/sdk 1.1.1 → 1.6.0

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 (163) hide show
  1. package/CHANGELOG.md +158 -2
  2. package/README.md +18 -8
  3. package/SECURITY.md +7 -1
  4. package/dist/{chunk-56UI7LUR.cjs → chunk-2RNW4MIJ.cjs} +37 -0
  5. package/dist/{chunk-VDXVNZCO.cjs → chunk-43RFBQ73.cjs} +85 -29
  6. package/dist/{chunk-BE2AIZ3K.js → chunk-46T67CE2.js} +1 -1
  7. package/dist/{chunk-WRCUDSUJ.js → chunk-4KJ66YRH.js} +61 -3
  8. package/dist/{chunk-ITQ7WKVC.cjs → chunk-4ZCXK4VI.cjs} +68 -8
  9. package/dist/{chunk-JFLEEXKP.js → chunk-6WSNS3UV.js} +58 -2
  10. package/dist/{chunk-W7JHOK7G.cjs → chunk-7G7UOQV4.cjs} +4 -4
  11. package/dist/{chunk-5KHIQG7Y.cjs → chunk-AYGRYDBX.cjs} +35 -36
  12. package/dist/{chunk-5SGMJADP.cjs → chunk-BD4LZBVF.cjs} +85 -9
  13. package/dist/{chunk-OYLZEEHF.cjs → chunk-BK7YIVLK.cjs} +304 -179
  14. package/dist/{chunk-SEKC7H5Y.cjs → chunk-CBRL2PJA.cjs} +12 -11
  15. package/dist/{chunk-XWDVPV42.js → chunk-CNP4L3GF.js} +4 -4
  16. package/dist/{chunk-IVE3QEGD.js → chunk-DRSPMIZ7.js} +28 -1
  17. package/dist/{chunk-SAGJIEQK.cjs → chunk-EUKPOXWR.cjs} +15 -16
  18. package/dist/chunk-FT4LNBOS.js +11 -0
  19. package/dist/{chunk-ITQBDRWX.js → chunk-HETNKZEE.js} +1 -1
  20. package/dist/{chunk-JJ4R5QXF.js → chunk-KSDSXJ34.js} +1 -1
  21. package/dist/{chunk-SYHXDHWX.cjs → chunk-LBWRFZR3.cjs} +218 -31
  22. package/dist/{chunk-ZXCOJY2Z.js → chunk-NFW7AUEX.js} +1 -1
  23. package/dist/{chunk-FPQBFIUW.cjs → chunk-OL6SHN3D.cjs} +3 -3
  24. package/dist/{chunk-XSNLAS5M.js → chunk-PD7ME2BT.js} +75 -2
  25. package/dist/{chunk-FXCW7LVB.js → chunk-QET3Q4JP.js} +94 -9
  26. package/dist/{chunk-M7V2EDPB.js → chunk-QKKBBH7I.js} +2 -2
  27. package/dist/{chunk-XXXDQSHE.js → chunk-S2XD75JM.js} +12 -3
  28. package/dist/{chunk-5SA2HF2W.cjs → chunk-SPGSO5SO.cjs} +31 -22
  29. package/dist/{chunk-Q7ARQSUH.cjs → chunk-SYHNZSZZ.cjs} +3 -3
  30. package/dist/{chunk-X56UVEXS.js → chunk-TN65XNTI.js} +248 -120
  31. package/dist/chunk-U57COLUE.js +56 -0
  32. package/dist/{chunk-OQZAZIAS.js → chunk-UE5XK2SY.js} +193 -6
  33. package/dist/{chunk-NS44KBV5.cjs → chunk-UJS4N2XM.cjs} +12 -12
  34. package/dist/{chunk-IR5AK5U5.js → chunk-V5D7BHW3.js} +4 -5
  35. package/dist/{chunk-3PQ2RFPC.js → chunk-VHSNYUYV.js} +5 -4
  36. package/dist/{chunk-CQIPRNS7.cjs → chunk-VR3FREBX.cjs} +3 -3
  37. package/dist/{chunk-G7G75C46.cjs → chunk-WO72UBQD.cjs} +11 -11
  38. package/dist/chunk-WOEETTH7.cjs +59 -0
  39. package/dist/{chunk-QE7ZONJ2.js → chunk-WTK6JDSI.js} +4 -5
  40. package/dist/{chunk-3ZRHDTEX.cjs → chunk-WUXUWTFW.cjs} +3 -3
  41. package/dist/{chunk-23F7JIK5.cjs → chunk-YFIWCYHC.cjs} +141 -54
  42. package/dist/{chunk-FYQ2UW4T.js → chunk-YPYCWLYP.js} +1 -1
  43. package/dist/chunk-ZQUE2B3Q.cjs +33 -0
  44. package/dist/core/addresses.d.ts +1 -1
  45. package/dist/core/errors.d.ts +41 -1
  46. package/dist/core/revert-mapper.d.ts +77 -0
  47. package/dist/core/wagmi-compat.d.ts +40 -0
  48. package/dist/fhe/index.cjs +134 -68
  49. package/dist/fhe/index.d.cts +2 -1
  50. package/dist/fhe/index.d.ts +2 -1
  51. package/dist/fhe/index.js +64 -10
  52. package/dist/fhe/mock-erc7984.d.ts +4 -4
  53. package/dist/fhe/operators.d.ts +142 -2
  54. package/dist/fhe/react/index.cjs +21 -8
  55. package/dist/fhe/react/index.d.cts +2 -0
  56. package/dist/fhe/react/index.d.ts +2 -0
  57. package/dist/fhe/react/index.js +8 -3
  58. package/dist/fhe/react/useEnsureOperator.d.ts +56 -0
  59. package/dist/fhe/react/useIsOperator.d.ts +54 -0
  60. package/dist/fhe/sepolia-encryptor-web.d.ts +45 -4
  61. package/dist/fhe/sepolia-encryptor.d.ts +38 -0
  62. package/dist/fhe-airdrop/advanced/index.cjs +9 -9
  63. package/dist/fhe-airdrop/advanced/index.js +7 -7
  64. package/dist/fhe-airdrop/advanced/react/index.cjs +14 -14
  65. package/dist/fhe-airdrop/advanced/react/index.js +10 -10
  66. package/dist/fhe-airdrop/airdrop.d.ts +9 -0
  67. package/dist/fhe-airdrop/encryption.d.ts +8 -0
  68. package/dist/fhe-airdrop/factory.d.ts +86 -1
  69. package/dist/fhe-airdrop/index.cjs +69 -66
  70. package/dist/fhe-airdrop/index.d.cts +3 -3
  71. package/dist/fhe-airdrop/index.d.ts +3 -3
  72. package/dist/fhe-airdrop/index.js +7 -8
  73. package/dist/fhe-airdrop/react/index.cjs +176 -135
  74. package/dist/fhe-airdrop/react/index.d.cts +7 -4
  75. package/dist/fhe-airdrop/react/index.d.ts +7 -4
  76. package/dist/fhe-airdrop/react/index.js +43 -16
  77. package/dist/fhe-airdrop/react/useAccessClaimAmount.d.ts +17 -11
  78. package/dist/fhe-airdrop/react/useAirdropIsSignatureValid.d.ts +3 -2
  79. package/dist/fhe-airdrop/react/useClaim.d.ts +10 -0
  80. package/dist/fhe-airdrop/react/useCreateAndFundConfidentialAirdrop.d.ts +8 -0
  81. package/dist/fhe-airdrop/react/useCreateAndFundConfidentialAirdropAndGetAddress.d.ts +8 -0
  82. package/dist/fhe-airdrop/react/useFundConfidentialAirdrop.d.ts +8 -0
  83. package/dist/fhe-airdrop/react/usePreflightCreateAirdrop.d.ts +51 -0
  84. package/dist/fhe-airdrop/react/useSignClaimAuthorization.d.ts +1 -1
  85. package/dist/fhe-airdrop/types.d.ts +56 -0
  86. package/dist/fhe-disperse/encryption.d.ts +8 -0
  87. package/dist/fhe-disperse/errors.d.ts +55 -0
  88. package/dist/fhe-disperse/index.cjs +77 -66
  89. package/dist/fhe-disperse/index.d.cts +2 -2
  90. package/dist/fhe-disperse/index.d.ts +2 -2
  91. package/dist/fhe-disperse/index.js +8 -9
  92. package/dist/fhe-disperse/react/index.cjs +108 -87
  93. package/dist/fhe-disperse/react/index.d.cts +4 -2
  94. package/dist/fhe-disperse/react/index.d.ts +4 -2
  95. package/dist/fhe-disperse/react/index.js +12 -11
  96. package/dist/fhe-disperse/react/useCalculateFee.d.ts +7 -0
  97. package/dist/fhe-disperse/react/useDisperse.d.ts +9 -0
  98. package/dist/fhe-disperse/react/usePreflightDisperse.d.ts +7 -0
  99. package/dist/fhe-disperse/react/useSingletonCalculateFee.d.ts +7 -0
  100. package/dist/fhe-disperse/react/useSingletonWithdrawTokenFee.d.ts +6 -0
  101. package/dist/fhe-disperse/react/useWithdrawTokenFee.d.ts +6 -0
  102. package/dist/fhe-disperse/singleton.d.ts +29 -0
  103. package/dist/fhe-disperse/subtotals.d.ts +6 -0
  104. package/dist/fhe-vesting/advanced/index.cjs +8 -9
  105. package/dist/fhe-vesting/advanced/index.js +6 -7
  106. package/dist/fhe-vesting/advanced/react/index.cjs +15 -15
  107. package/dist/fhe-vesting/advanced/react/index.js +12 -12
  108. package/dist/fhe-vesting/encryption.d.ts +8 -0
  109. package/dist/fhe-vesting/index.cjs +82 -79
  110. package/dist/fhe-vesting/index.d.cts +2 -2
  111. package/dist/fhe-vesting/index.d.ts +2 -2
  112. package/dist/fhe-vesting/index.js +9 -10
  113. package/dist/fhe-vesting/manager.d.ts +119 -1
  114. package/dist/fhe-vesting/react/index.cjs +264 -224
  115. package/dist/fhe-vesting/react/index.d.cts +9 -6
  116. package/dist/fhe-vesting/react/index.d.ts +9 -6
  117. package/dist/fhe-vesting/react/index.js +44 -21
  118. package/dist/fhe-vesting/react/useAccessClaimableAmount.d.ts +11 -3
  119. package/dist/fhe-vesting/react/useAccessSettledAmount.d.ts +11 -3
  120. package/dist/fhe-vesting/react/useAccessTotalAllocation.d.ts +11 -3
  121. package/dist/fhe-vesting/react/useAccessVestedAmount.d.ts +11 -3
  122. package/dist/fhe-vesting/react/useAdminClaim.d.ts +2 -0
  123. package/dist/fhe-vesting/react/useAdminGetClaimableAmount.d.ts +1 -1
  124. package/dist/fhe-vesting/react/useAdminGetSettledAmount.d.ts +1 -1
  125. package/dist/fhe-vesting/react/useAdminGetTotalAllocation.d.ts +1 -1
  126. package/dist/fhe-vesting/react/useAdminGetVestedAmount.d.ts +1 -1
  127. package/dist/fhe-vesting/react/useAdminPartialClaim.d.ts +10 -0
  128. package/dist/fhe-vesting/react/useBatchCreateVesting.d.ts +8 -0
  129. package/dist/fhe-vesting/react/useClaim.d.ts +3 -1
  130. package/dist/fhe-vesting/react/useCreateVesting.d.ts +8 -0
  131. package/dist/fhe-vesting/react/useDiscloseHandleToParty.d.ts +1 -1
  132. package/dist/fhe-vesting/react/useManagerDiscloseHandleToParty.d.ts +1 -1
  133. package/dist/fhe-vesting/react/useManagerWithdrawTokenFee.d.ts +6 -0
  134. package/dist/fhe-vesting/react/usePartialClaim.d.ts +9 -1
  135. package/dist/fhe-vesting/react/usePreflightCreateVesting.d.ts +37 -0
  136. package/dist/fhe-vesting/react/useVestingClaim.d.ts +2 -0
  137. package/dist/fhe-vesting/react/useVestingInfo.d.ts +1 -1
  138. package/dist/fhe-vesting/react/useWithdrawAdmin.d.ts +6 -0
  139. package/dist/fhe-vesting/react/useWithdrawTokenFee.d.ts +6 -0
  140. package/dist/fhe-vesting/types.d.ts +45 -0
  141. package/dist/index.cjs +93 -86
  142. package/dist/index.d.cts +1 -1
  143. package/dist/index.d.ts +1 -1
  144. package/dist/index.js +2 -3
  145. package/dist/testnet-faucet/index.cjs +58 -55
  146. package/dist/testnet-faucet/index.d.cts +1 -1
  147. package/dist/testnet-faucet/index.d.ts +1 -1
  148. package/dist/testnet-faucet/index.js +5 -6
  149. package/dist/testnet-faucet/react/index.cjs +60 -56
  150. package/dist/testnet-faucet/react/index.d.cts +3 -2
  151. package/dist/testnet-faucet/react/index.d.ts +3 -2
  152. package/dist/testnet-faucet/react/index.js +11 -11
  153. package/dist/testnet-faucet/react/useConfidentialBalance.d.ts +3 -2
  154. package/dist/testnet-faucet/react/useUnderlyingBalance.d.ts +2 -2
  155. package/package.json +14 -8
  156. package/dist/chunk-66IHPTOK.cjs +0 -20
  157. package/dist/chunk-KWFFIJYX.js +0 -11
  158. package/dist/fhe-airdrop/react/useAirdropClaim.d.ts +0 -25
  159. package/dist/fhe-airdrop/react/useGetClaimAmount.d.ts +0 -30
  160. package/dist/fhe-vesting/react/useGetClaimableAmount.d.ts +0 -13
  161. package/dist/fhe-vesting/react/useGetSettledAmount.d.ts +0 -14
  162. package/dist/fhe-vesting/react/useGetTotalAllocation.d.ts +0 -13
  163. package/dist/fhe-vesting/react/useGetVestedAmount.d.ts +0 -25
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var chunkSYHXDHWX_cjs = require('./chunk-SYHXDHWX.cjs');
3
+ var chunkLBWRFZR3_cjs = require('./chunk-LBWRFZR3.cjs');
4
4
 
5
5
  // src/fhe-airdrop/advanced/factory-advanced.ts
6
- var ConfidentialAirdropFactoryAdvancedClient = class extends chunkSYHXDHWX_cjs.ConfidentialAirdropFactoryClient {
6
+ var ConfidentialAirdropFactoryAdvancedClient = class extends chunkLBWRFZR3_cjs.ConfidentialAirdropFactoryClient {
7
7
  /**
8
8
  * Compute the deterministic CREATE2 address for an airdrop clone without
9
9
  * deploying it.
@@ -21,7 +21,7 @@ var ConfidentialAirdropFactoryAdvancedClient = class extends chunkSYHXDHWX_cjs.C
21
21
  async predictAirdropAddress(args) {
22
22
  return this.publicClient.readContract({
23
23
  address: this.address,
24
- abi: chunkSYHXDHWX_cjs.confidentialAirdropFactoryAbi,
24
+ abi: chunkLBWRFZR3_cjs.confidentialAirdropFactoryAbi,
25
25
  functionName: "predictAirdropAddress",
26
26
  args: [toAbiParams(args.params), args.userSalt, args.deployer, args.gasFee]
27
27
  });
@@ -1,4 +1,5 @@
1
- import { InvalidArgumentError } from './chunk-IVE3QEGD.js';
1
+ import { InvalidArgumentError, asExternalInputProof, asEncryptedHandle } from './chunk-DRSPMIZ7.js';
2
+ import { bytesToHex } from 'viem';
2
3
 
3
4
  // src/fhe/scale-ratio.ts
4
5
  var FHE_SPLIT_DENOMINATOR = 90090000n;
@@ -131,5 +132,77 @@ function toIntegerBigInt(value, method, argument) {
131
132
  }
132
133
  return BigInt(value);
133
134
  }
135
+ function resolveEncryptor(source) {
136
+ if (source === void 0) return void 0;
137
+ return typeof source === "function" ? source() : source;
138
+ }
139
+ var MAX_UINT642 = (1n << 64n) - 1n;
140
+ function assertUint64(value, label) {
141
+ if (value < 0n || value > MAX_UINT642) {
142
+ throw new InvalidArgumentError({
143
+ method: "encryptUint64",
144
+ argument: label,
145
+ reason: `does not fit in uint64 (0..2^64-1)`,
146
+ value
147
+ });
148
+ }
149
+ }
150
+ async function encryptUint64({
151
+ encryptor,
152
+ contractAddress,
153
+ userAddress,
154
+ value
155
+ }) {
156
+ assertUint64(value, "value");
157
+ const { handles, inputProof } = await encryptor.encrypt({
158
+ values: [{ value, type: "euint64" }],
159
+ contractAddress,
160
+ userAddress
161
+ });
162
+ if (handles.length !== 1) {
163
+ throw new InvalidArgumentError({
164
+ method: "encryptUint64",
165
+ argument: "handles",
166
+ reason: `expected 1 handle, got ${handles.length}`,
167
+ value: handles.length
168
+ });
169
+ }
170
+ return {
171
+ handle: asEncryptedHandle(bytesToHex(handles[0])),
172
+ inputProof: asExternalInputProof(bytesToHex(inputProof))
173
+ };
174
+ }
175
+ async function encryptUint64Batch({
176
+ encryptor,
177
+ contractAddress,
178
+ userAddress,
179
+ values
180
+ }) {
181
+ if (values.length === 0) {
182
+ throw new InvalidArgumentError({
183
+ method: "encryptUint64Batch",
184
+ argument: "values",
185
+ reason: "must be non-empty"
186
+ });
187
+ }
188
+ values.forEach((v, i) => assertUint64(v, `values[${i}]`));
189
+ const { handles, inputProof } = await encryptor.encrypt({
190
+ values: values.map((value) => ({ value, type: "euint64" })),
191
+ contractAddress,
192
+ userAddress
193
+ });
194
+ if (handles.length !== values.length) {
195
+ throw new InvalidArgumentError({
196
+ method: "encryptUint64Batch",
197
+ argument: "handles",
198
+ reason: `expected ${values.length} handles, got ${handles.length}`,
199
+ value: handles.length
200
+ });
201
+ }
202
+ return {
203
+ handles: handles.map((h) => asEncryptedHandle(bytesToHex(h))),
204
+ inputProof: asExternalInputProof(bytesToHex(inputProof))
205
+ };
206
+ }
134
207
 
135
- export { FHE_SPLIT_DENOMINATOR, scaleRatio, share };
208
+ export { FHE_SPLIT_DENOMINATOR, encryptUint64, encryptUint64Batch, resolveEncryptor, scaleRatio, share };
@@ -1,11 +1,10 @@
1
- import { mapZamaError } from './chunk-ZXCOJY2Z.js';
2
- import { getFhevmAclAddress, requireFhevmAclAddress, ACL_ALLOWED_EVENT } from './chunk-FYQ2UW4T.js';
3
- import { SDK_VERSION, isContractRevert, mapContractRevert } from './chunk-JFLEEXKP.js';
4
- import { getFheDisperseSingletonAddress } from './chunk-M7V2EDPB.js';
5
- import { normaliseAddress } from './chunk-BE2AIZ3K.js';
1
+ import { mapZamaError } from './chunk-NFW7AUEX.js';
2
+ import { getFhevmAclAddress, requireFhevmAclAddress, ACL_ALLOWED_EVENT } from './chunk-YPYCWLYP.js';
3
+ import { SDK_VERSION, isContractRevert, mapContractRevert } from './chunk-6WSNS3UV.js';
4
+ import { getFheDisperseSingletonAddress } from './chunk-QKKBBH7I.js';
5
+ import { normaliseAddress } from './chunk-46T67CE2.js';
6
+ import { InvalidArgumentError, asExternalInputProof, asEncryptedHandle, TokenOpsSdkError, DeploymentAddressUnavailableError, PausedError, InsufficientFeeError, MissingEncryptorError, ReceiptEventAmbiguousError, MissingWalletClientError, MissingAccountError, BatchTooLargeError } from './chunk-DRSPMIZ7.js';
6
7
  import { withTelemetry } from './chunk-Q2GP5UDC.js';
7
- import { asExternalInputProof, asEncryptedHandle } from './chunk-KWFFIJYX.js';
8
- import { InvalidArgumentError, TokenOpsSdkError, DeploymentAddressUnavailableError, PausedError, InsufficientFeeError, MissingEncryptorError, ReceiptEventAmbiguousError, MissingWalletClientError, MissingAccountError, BatchTooLargeError } from './chunk-IVE3QEGD.js';
9
8
  import { bytesToHex, keccak256, encodePacked, parseEventLogs, isAddress, getCreate2Address } from 'viem';
10
9
 
11
10
  // src/fhe-disperse/abis/singleton.ts
@@ -1771,6 +1770,44 @@ var NotRegisteredError = class extends TokenOpsSdkError {
1771
1770
  );
1772
1771
  }
1773
1772
  };
1773
+ var SubwalletsNotApprovedError = class extends TokenOpsSdkError {
1774
+ name = "SubwalletsNotApprovedError";
1775
+ constructor(args) {
1776
+ super(
1777
+ `${args.method}: sub-wallets are not fully approved for token ${args.token} \u2014 wallet0: ${args.wallet0Approved}, wallet1: ${args.wallet1Approved}. Call \`approveUserWalletsForToken\` first.`,
1778
+ {
1779
+ code: "TOKENOPS_SUBWALLETS_NOT_APPROVED",
1780
+ cause: args.cause,
1781
+ context: {
1782
+ method: args.method,
1783
+ contractAddress: args.contractAddress,
1784
+ user: args.user,
1785
+ token: args.token,
1786
+ wallet0Approved: args.wallet0Approved,
1787
+ wallet1Approved: args.wallet1Approved
1788
+ }
1789
+ }
1790
+ );
1791
+ }
1792
+ };
1793
+ var SingletonNotApprovedError = class extends TokenOpsSdkError {
1794
+ name = "SingletonNotApprovedError";
1795
+ constructor(args) {
1796
+ super(
1797
+ `${args.method}: ${args.user} has not approved the singleton ${args.contractAddress} as an operator on token ${args.token}. Call setOperator() (see @tokenops/sdk/fhe) before this transaction.`,
1798
+ {
1799
+ code: "TOKENOPS_SINGLETON_NOT_APPROVED",
1800
+ cause: args.cause,
1801
+ context: {
1802
+ method: args.method,
1803
+ contractAddress: args.contractAddress,
1804
+ user: args.user,
1805
+ token: args.token
1806
+ }
1807
+ }
1808
+ );
1809
+ }
1810
+ };
1774
1811
  var AlreadyRegisteredError = class extends TokenOpsSdkError {
1775
1812
  name = "AlreadyRegisteredError";
1776
1813
  constructor(args) {
@@ -2166,6 +2203,13 @@ var ConfidentialDisperseClient = class {
2166
2203
  * subtotal1` for the result to match the on-chain computation. Both this
2167
2204
  * SDK and the contract round the BPS multiplication down (floor division).
2168
2205
  *
2206
+ * **Amount units:** TokenOps confidential (ERC-7984) tokens use a 6-decimals
2207
+ * convention (1 token = 1_000_000 base units), not the 18 decimals typical of
2208
+ * ERC-20. Amount parameters are base units of the token's actual decimals:
2209
+ * for the CTTT test token (6 decimals) `1_000_000n` = 1 CTTT, while the
2210
+ * transparent TTT test token uses 18 decimals. `totalTokens` follows this
2211
+ * convention.
2212
+ *
2169
2213
  * @throws {TokenOpsSdkError} if mode is `"wallet-token-fee"` and `totalTokens` is not provided.
2170
2214
  */
2171
2215
  async calculateFee(args) {
@@ -2229,6 +2273,13 @@ var ConfidentialDisperseClient = class {
2229
2273
  * - `hasApprovedSubwallets` (wallet modes) or `isOperator(sender, singleton)` (direct mode)
2230
2274
  * - `calculateFee` / `getBatchLimits`
2231
2275
  * - Structural recipient + amount validation
2276
+ *
2277
+ * **Amount units:** TokenOps confidential (ERC-7984) tokens use a 6-decimals
2278
+ * convention (1 token = 1_000_000 base units), not the 18 decimals typical of
2279
+ * ERC-20. Amount parameters are base units of the token's actual decimals:
2280
+ * for the CTTT test token (6 decimals) `1_000_000n` = 1 CTTT, while the
2281
+ * transparent TTT test token uses 18 decimals. Pass `amounts[]` in the same
2282
+ * units you will pass to `disperse` so the report reflects the real call.
2232
2283
  */
2233
2284
  async preflightDisperse(args) {
2234
2285
  const { user, token, recipients, amounts, mode } = args;
@@ -2321,13 +2372,32 @@ var ConfidentialDisperseClient = class {
2321
2372
  })
2322
2373
  );
2323
2374
  } else if (mode === "wallet" || mode === "wallet-token-fee") {
2324
- if (!hasApprovedSubwallets.both)
2375
+ if (!hasApprovedSubwallets.both) {
2325
2376
  blockers.push(
2326
2377
  `Wallets not fully approved for token \u2014 wallet0: ${hasApprovedSubwallets.wallet0}, wallet1: ${hasApprovedSubwallets.wallet1}`
2327
2378
  );
2379
+ blockerErrors.push(
2380
+ new SubwalletsNotApprovedError({
2381
+ method: "preflightDisperse",
2382
+ contractAddress: this.address,
2383
+ user: args.user,
2384
+ token: args.token,
2385
+ wallet0Approved: hasApprovedSubwallets.wallet0,
2386
+ wallet1Approved: hasApprovedSubwallets.wallet1
2387
+ })
2388
+ );
2389
+ }
2328
2390
  }
2329
2391
  if (mode === "direct" && hasApprovedSingleton === false) {
2330
2392
  blockers.push("Sender has not approved the singleton as operator on the token");
2393
+ blockerErrors.push(
2394
+ new SingletonNotApprovedError({
2395
+ method: "preflightDisperse",
2396
+ contractAddress: this.address,
2397
+ user: args.user,
2398
+ token: args.token
2399
+ })
2400
+ );
2331
2401
  }
2332
2402
  if (isPaused) {
2333
2403
  blockers.push("Singleton is paused");
@@ -2474,6 +2544,15 @@ var ConfidentialDisperseClient = class {
2474
2544
  * 4. Computes `msg.value` for gas-fee modes; `0` for token-fee mode.
2475
2545
  * 5. Dispatches to the correct contract function based on `mode`.
2476
2546
  *
2547
+ * **Silent-zero transfers.** ERC-7984 transfers do not revert when the sender's encrypted balance is insufficient — the transfer succeeds and moves an encrypted zero instead. This is by design: reverting would leak balance information. The transaction receipt alone cannot tell you whether value actually moved.
2548
+ *
2549
+ * **Amount units:** TokenOps confidential (ERC-7984) tokens use a 6-decimals
2550
+ * convention (1 token = 1_000_000 base units), not the 18 decimals typical of
2551
+ * ERC-20. Amount parameters are base units of the token's actual decimals:
2552
+ * for the CTTT test token (6 decimals) `1_000_000n` = 1 CTTT, while the
2553
+ * transparent TTT test token uses 18 decimals. Every entry of `amounts[]`
2554
+ * follows this convention.
2555
+ *
2477
2556
  * @throws {TokenOpsSdkError} on input validation failure (first deterministic error).
2478
2557
  * @throws {TokenOpsSdkError} if no encryptor is available at call time.
2479
2558
  */
@@ -2789,6 +2868,12 @@ var ConfidentialDisperseClient = class {
2789
2868
  * encryptor, or pass `encryptedInput` directly. The contract caps the
2790
2869
  * withdrawal at the available reserve via `FHE.min`.
2791
2870
  *
2871
+ * **Amount units:** TokenOps confidential (ERC-7984) tokens use a 6-decimals
2872
+ * convention (1 token = 1_000_000 base units), not the 18 decimals typical of
2873
+ * ERC-20. Amount parameters are base units of the token's actual decimals:
2874
+ * for the CTTT test token (6 decimals) `1_000_000n` = 1 CTTT, while the
2875
+ * transparent TTT test token uses 18 decimals.
2876
+ *
2792
2877
  * Returns the tx hash plus the **transferred** handle parsed from the
2793
2878
  * `TokenFeeWithdrawn` event. Decrypt the handle via Zama's `userDecrypt`
2794
2879
  * to view the actual amount moved (which can be less than requested when
@@ -3385,4 +3470,4 @@ var PAUSER_ROLE = "0x65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440
3385
3470
  var WITHDRAWER_ROLE = "0x10dac8c06a04bec0b551627dad28bc00d6516b0caacd1c7b345fcdb5211334e4";
3386
3471
  var DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000";
3387
3472
 
3388
- export { AlreadyRegisteredError, ConfidentialDisperseClient, DEFAULT_ADMIN_ROLE, DisperseEncryptedReserveNotGrantedError, DisperseSubwalletNotFoundError, FEE_COLLECTOR_ROLE, FEE_MANAGER_ROLE, NotRegisteredError, PAUSER_ROLE, WITHDRAWER_ROLE, computeSubtotals, createConfidentialDisperseClient, disperseConfidentialAbi, disperseWalletAbi, encryptUint64, encryptUint64Batch, resolveEncryptor };
3473
+ export { AlreadyRegisteredError, ConfidentialDisperseClient, DEFAULT_ADMIN_ROLE, DisperseEncryptedReserveNotGrantedError, DisperseSubwalletNotFoundError, FEE_COLLECTOR_ROLE, FEE_MANAGER_ROLE, NotRegisteredError, PAUSER_ROLE, SingletonNotApprovedError, SubwalletsNotApprovedError, WITHDRAWER_ROLE, computeSubtotals, createConfidentialDisperseClient, disperseConfidentialAbi, disperseWalletAbi, encryptUint64, encryptUint64Batch, resolveEncryptor };
@@ -1,10 +1,10 @@
1
- import { DeploymentAddressUnavailableError } from './chunk-IVE3QEGD.js';
1
+ import { DeploymentAddressUnavailableError } from './chunk-DRSPMIZ7.js';
2
2
  import { sepolia, mainnet } from 'viem/chains';
3
3
 
4
4
  var DEPLOYED_ADDRESSES = {
5
5
  fheVesting: {
6
6
  confidentialVestingFactory: {
7
- [sepolia.id]: "0xA87701CE9A52D43681600583a99c85b50DbE3150"
7
+ [sepolia.id]: "0x059d6Bb8ff9a13E794fe416d4757d7310CdC69ab"
8
8
  // mainnet omitted — not deployed.
9
9
  }
10
10
  },
@@ -1,7 +1,7 @@
1
- import { getFhevmAclAddress, requireFhevmAclAddress, ACL_ALLOWED_EVENT } from './chunk-FYQ2UW4T.js';
2
- import { SDK_VERSION, mapContractRevert, isContractRevert } from './chunk-JFLEEXKP.js';
1
+ import { getFhevmAclAddress, requireFhevmAclAddress, ACL_ALLOWED_EVENT } from './chunk-YPYCWLYP.js';
2
+ import { SDK_VERSION, mapContractRevert, isContractRevert } from './chunk-6WSNS3UV.js';
3
+ import { TokenOpsSdkError, PausedError, InsufficientFeeError, ReceiptEventNotFoundError, ReceiptEventAmbiguousError, InvalidArgumentError, MissingWalletClientError, MissingAccountError, InsufficientBalanceError, InvalidSignatureError } from './chunk-DRSPMIZ7.js';
3
4
  import { withTelemetry } from './chunk-Q2GP5UDC.js';
4
- import { TokenOpsSdkError, PausedError, InsufficientFeeError, ReceiptEventNotFoundError, ReceiptEventAmbiguousError, InvalidArgumentError, MissingWalletClientError, MissingAccountError, InsufficientBalanceError, InvalidSignatureError } from './chunk-IVE3QEGD.js';
5
5
  import { parseEventLogs, isAddress } from 'viem';
6
6
 
7
7
  // src/fhe-airdrop/abis/cloneable.ts
@@ -1358,6 +1358,15 @@ var ConfidentialAirdropClient = class {
1358
1358
  * {@link signClaimAuthorization}. The signature commits to that handle, so the SDK
1359
1359
  * does NOT re-encrypt — submit the admin-issued payload as-is.
1360
1360
  *
1361
+ * **Silent-zero transfers.** ERC-7984 transfers do not revert when the sender's encrypted balance is insufficient — the transfer succeeds and moves an encrypted zero instead. This is by design: reverting would leak balance information. The transaction receipt alone cannot tell you whether value actually moved.
1362
+ *
1363
+ * **An unfunded pool is the opposite case — it reverts loudly.** Do not
1364
+ * generalize the silent-zero rule above to a clone whose pool was never
1365
+ * funded: that claim throws {@link FheHandleNotAllowedError} (the FHEVM ACL
1366
+ * rejects `FHE.allowTransient` on an uninitialized handle), and
1367
+ * {@link preflightClaim} cannot detect it because the pool balance is an
1368
+ * encrypted `euint64` the SDK cannot read in plaintext.
1369
+ *
1361
1370
  * @returns Transaction hash.
1362
1371
  * @example
1363
1372
  * const fee = await airdrop.gasFee();
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var chunkQ7ARQSUH_cjs = require('./chunk-Q7ARQSUH.cjs');
4
- var chunkVDXVNZCO_cjs = require('./chunk-VDXVNZCO.cjs');
3
+ var chunkSYHNZSZZ_cjs = require('./chunk-SYHNZSZZ.cjs');
4
+ var chunk43RFBQ73_cjs = require('./chunk-43RFBQ73.cjs');
5
+ var chunk2RNW4MIJ_cjs = require('./chunk-2RNW4MIJ.cjs');
5
6
  var chunkVJKZWYYJ_cjs = require('./chunk-VJKZWYYJ.cjs');
6
- var chunk56UI7LUR_cjs = require('./chunk-56UI7LUR.cjs');
7
7
  var viem = require('viem');
8
8
 
9
9
  // src/fhe-airdrop/abis/cloneable.ts
@@ -1016,7 +1016,7 @@ var confidentialAirdropCloneableAbi = [
1016
1016
  ];
1017
1017
 
1018
1018
  // src/fhe-airdrop/errors.ts
1019
- var AlreadyClaimedError = class extends chunk56UI7LUR_cjs.TokenOpsSdkError {
1019
+ var AlreadyClaimedError = class extends chunk2RNW4MIJ_cjs.TokenOpsSdkError {
1020
1020
  name = "AlreadyClaimedError";
1021
1021
  constructor(args) {
1022
1022
  const who = args.caller ? `${args.caller}: ` : "";
@@ -1031,7 +1031,7 @@ var AlreadyClaimedError = class extends chunk56UI7LUR_cjs.TokenOpsSdkError {
1031
1031
  });
1032
1032
  }
1033
1033
  };
1034
- var ClaimNotStartedError = class extends chunk56UI7LUR_cjs.TokenOpsSdkError {
1034
+ var ClaimNotStartedError = class extends chunk2RNW4MIJ_cjs.TokenOpsSdkError {
1035
1035
  name = "ClaimNotStartedError";
1036
1036
  constructor(args) {
1037
1037
  const detail = args.startsAt !== void 0 ? ` Opens at unix timestamp ${args.startsAt}.` : "";
@@ -1046,7 +1046,7 @@ var ClaimNotStartedError = class extends chunk56UI7LUR_cjs.TokenOpsSdkError {
1046
1046
  });
1047
1047
  }
1048
1048
  };
1049
- var ClaimWindowClosedError = class extends chunk56UI7LUR_cjs.TokenOpsSdkError {
1049
+ var ClaimWindowClosedError = class extends chunk2RNW4MIJ_cjs.TokenOpsSdkError {
1050
1050
  name = "ClaimWindowClosedError";
1051
1051
  constructor(args) {
1052
1052
  const detail = args.endedAt !== void 0 ? ` Closed at unix timestamp ${args.endedAt}.` : "";
@@ -1081,10 +1081,10 @@ var airdropProductMapper = (name, _args, ctx) => {
1081
1081
  case "ECDSAInvalidSignature":
1082
1082
  case "ECDSAInvalidSignatureS":
1083
1083
  case "ECDSAInvalidSignatureLength":
1084
- return new chunk56UI7LUR_cjs.InvalidSignatureError(ctx);
1084
+ return new chunk2RNW4MIJ_cjs.InvalidSignatureError(ctx);
1085
1085
  case "ZeroBalance":
1086
1086
  case "InsufficientBalance":
1087
- return CONFIDENTIAL_POOL_BALANCE_METHODS.has(ctx.method) ? new chunk56UI7LUR_cjs.InsufficientBalanceError({ ...ctx, balanceKind: "confidential" }) : void 0;
1087
+ return CONFIDENTIAL_POOL_BALANCE_METHODS.has(ctx.method) ? new chunk2RNW4MIJ_cjs.InsufficientBalanceError({ ...ctx, balanceKind: "confidential" }) : void 0;
1088
1088
  default:
1089
1089
  return void 0;
1090
1090
  }
@@ -1107,8 +1107,8 @@ var ConfidentialAirdropClient = class {
1107
1107
  surface: "client",
1108
1108
  chainId: chainIdForInit ?? null,
1109
1109
  hasWallet: !!this.walletClient,
1110
- aclResolved: !!config.aclAddress || chainIdForInit !== void 0 && !!chunkQ7ARQSUH_cjs.getFhevmAclAddress(chainIdForInit),
1111
- sdkVersion: chunkVDXVNZCO_cjs.SDK_VERSION
1110
+ aclResolved: !!config.aclAddress || chainIdForInit !== void 0 && !!chunkSYHNZSZZ_cjs.getFhevmAclAddress(chainIdForInit),
1111
+ sdkVersion: chunk43RFBQ73_cjs.SDK_VERSION
1112
1112
  });
1113
1113
  }
1114
1114
  /**
@@ -1119,7 +1119,7 @@ var ConfidentialAirdropClient = class {
1119
1119
  */
1120
1120
  get aclAddress() {
1121
1121
  if (this.#cachedAclAddress) return this.#cachedAclAddress;
1122
- this.#cachedAclAddress = this.#aclAddressOverride ?? chunkQ7ARQSUH_cjs.requireFhevmAclAddress(this.publicClient.chain?.id, "ConfidentialAirdropClient");
1122
+ this.#cachedAclAddress = this.#aclAddressOverride ?? chunkSYHNZSZZ_cjs.requireFhevmAclAddress(this.publicClient.chain?.id, "ConfidentialAirdropClient");
1123
1123
  return this.#cachedAclAddress;
1124
1124
  }
1125
1125
  // ============================================================
@@ -1254,7 +1254,7 @@ var ConfidentialAirdropClient = class {
1254
1254
  account: args.caller
1255
1255
  });
1256
1256
  } catch (err) {
1257
- throw chunkVDXVNZCO_cjs.mapContractRevert(err, {
1257
+ throw chunk43RFBQ73_cjs.mapContractRevert(err, {
1258
1258
  method: "isSignatureValid",
1259
1259
  contractAddress: this.address,
1260
1260
  abi: confidentialAirdropCloneableAbi,
@@ -1308,7 +1308,7 @@ var ConfidentialAirdropClient = class {
1308
1308
  ]);
1309
1309
  const now = Number(block.timestamp);
1310
1310
  if (isPaused) {
1311
- blockers.push(new chunk56UI7LUR_cjs.PausedError({ method: "claim", contractAddress: this.address }));
1311
+ blockers.push(new chunk2RNW4MIJ_cjs.PausedError({ method: "claim", contractAddress: this.address }));
1312
1312
  }
1313
1313
  if (now < startTime) {
1314
1314
  blockers.push(
@@ -1339,7 +1339,7 @@ var ConfidentialAirdropClient = class {
1339
1339
  }
1340
1340
  if (callerBalance < gasFee) {
1341
1341
  blockers.push(
1342
- new chunk56UI7LUR_cjs.InsufficientFeeError({
1342
+ new chunk2RNW4MIJ_cjs.InsufficientFeeError({
1343
1343
  method: "claim",
1344
1344
  contractAddress: this.address,
1345
1345
  feeKind: "gas",
@@ -1360,6 +1360,15 @@ var ConfidentialAirdropClient = class {
1360
1360
  * {@link signClaimAuthorization}. The signature commits to that handle, so the SDK
1361
1361
  * does NOT re-encrypt — submit the admin-issued payload as-is.
1362
1362
  *
1363
+ * **Silent-zero transfers.** ERC-7984 transfers do not revert when the sender's encrypted balance is insufficient — the transfer succeeds and moves an encrypted zero instead. This is by design: reverting would leak balance information. The transaction receipt alone cannot tell you whether value actually moved.
1364
+ *
1365
+ * **An unfunded pool is the opposite case — it reverts loudly.** Do not
1366
+ * generalize the silent-zero rule above to a clone whose pool was never
1367
+ * funded: that claim throws {@link FheHandleNotAllowedError} (the FHEVM ACL
1368
+ * rejects `FHE.allowTransient` on an uninitialized handle), and
1369
+ * {@link preflightClaim} cannot detect it because the pool balance is an
1370
+ * encrypted `euint64` the SDK cannot read in plaintext.
1371
+ *
1363
1372
  * @returns Transaction hash.
1364
1373
  * @example
1365
1374
  * const fee = await airdrop.gasFee();
@@ -1433,12 +1442,12 @@ var ConfidentialAirdropClient = class {
1433
1442
  const aclLogs = receipt.logs.filter(
1434
1443
  (log) => log.address.toLowerCase() === this.aclAddress.toLowerCase()
1435
1444
  );
1436
- const events = viem.parseEventLogs({ abi: [chunkQ7ARQSUH_cjs.ACL_ALLOWED_EVENT], logs: aclLogs });
1445
+ const events = viem.parseEventLogs({ abi: [chunkSYHNZSZZ_cjs.ACL_ALLOWED_EVENT], logs: aclLogs });
1437
1446
  const granted = events.filter(
1438
1447
  (ev) => ev.args.account.toLowerCase() === callerAddress && ev.args.caller.toLowerCase() === this.address.toLowerCase()
1439
1448
  );
1440
1449
  if (granted.length === 0) {
1441
- throw new chunk56UI7LUR_cjs.ReceiptEventNotFoundError({
1450
+ throw new chunk2RNW4MIJ_cjs.ReceiptEventNotFoundError({
1442
1451
  method: "getClaimAmount",
1443
1452
  eventName: "Allowed",
1444
1453
  contractAddress: this.aclAddress,
@@ -1447,7 +1456,7 @@ var ConfidentialAirdropClient = class {
1447
1456
  });
1448
1457
  }
1449
1458
  if (granted.length > 1) {
1450
- throw new chunk56UI7LUR_cjs.ReceiptEventAmbiguousError({
1459
+ throw new chunk2RNW4MIJ_cjs.ReceiptEventAmbiguousError({
1451
1460
  method: "getClaimAmount",
1452
1461
  eventName: "Allowed",
1453
1462
  contractAddress: this.aclAddress,
@@ -1535,7 +1544,7 @@ var ConfidentialAirdropClient = class {
1535
1544
  // ============================================================
1536
1545
  #requireChecksumAddress(method, argument, value) {
1537
1546
  if (!viem.isAddress(value, { strict: true })) {
1538
- throw new chunk56UI7LUR_cjs.InvalidArgumentError({
1547
+ throw new chunk2RNW4MIJ_cjs.InvalidArgumentError({
1539
1548
  method,
1540
1549
  argument,
1541
1550
  reason: "must be a valid EIP-55 checksummed address",
@@ -1545,14 +1554,14 @@ var ConfidentialAirdropClient = class {
1545
1554
  }
1546
1555
  #requireWallet(method) {
1547
1556
  if (!this.walletClient) {
1548
- throw new chunk56UI7LUR_cjs.MissingWalletClientError(method);
1557
+ throw new chunk2RNW4MIJ_cjs.MissingWalletClientError(method);
1549
1558
  }
1550
1559
  return this.walletClient;
1551
1560
  }
1552
1561
  #resolveAccount(wallet, override, method) {
1553
1562
  const acct = override ?? wallet.account;
1554
1563
  if (!acct) {
1555
- throw new chunk56UI7LUR_cjs.MissingAccountError(method);
1564
+ throw new chunk2RNW4MIJ_cjs.MissingAccountError(method);
1556
1565
  }
1557
1566
  if (typeof acct === "string") {
1558
1567
  this.#requireChecksumAddress(method, "account", acct);
@@ -1560,7 +1569,7 @@ var ConfidentialAirdropClient = class {
1560
1569
  return acct;
1561
1570
  }
1562
1571
  #mapRevert(method, err, account) {
1563
- return chunkVDXVNZCO_cjs.mapContractRevert(err, {
1572
+ return chunk43RFBQ73_cjs.mapContractRevert(err, {
1564
1573
  method,
1565
1574
  contractAddress: this.address,
1566
1575
  abi: confidentialAirdropCloneableAbi,
@@ -1605,7 +1614,7 @@ var ConfidentialAirdropClient = class {
1605
1614
  ...value !== void 0 ? { value } : {}
1606
1615
  });
1607
1616
  } catch (err) {
1608
- if (chunkVDXVNZCO_cjs.isContractRevert(err)) {
1617
+ if (chunk43RFBQ73_cjs.isContractRevert(err)) {
1609
1618
  throw this.#mapRevert(method, err, accountAddress(account));
1610
1619
  }
1611
1620
  }
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk56UI7LUR_cjs = require('./chunk-56UI7LUR.cjs');
3
+ var chunk2RNW4MIJ_cjs = require('./chunk-2RNW4MIJ.cjs');
4
4
  var viem = require('viem');
5
5
 
6
6
  var FHEVM_ACL_ADDRESS_BY_CHAIN = {
@@ -16,7 +16,7 @@ function getFhevmAclAddress(chainId) {
16
16
  }
17
17
  function requireFhevmAclAddress(chainId, clientLabel) {
18
18
  if (chainId === void 0) {
19
- throw new chunk56UI7LUR_cjs.DeploymentAddressUnavailableError({
19
+ throw new chunk2RNW4MIJ_cjs.DeploymentAddressUnavailableError({
20
20
  reason: "chain-id-missing",
21
21
  product: "fhevm",
22
22
  contract: "acl",
@@ -26,7 +26,7 @@ function requireFhevmAclAddress(chainId, clientLabel) {
26
26
  }
27
27
  const addr = FHEVM_ACL_ADDRESS_BY_CHAIN[chainId];
28
28
  if (addr) return addr;
29
- throw new chunk56UI7LUR_cjs.DeploymentAddressUnavailableError({
29
+ throw new chunk2RNW4MIJ_cjs.DeploymentAddressUnavailableError({
30
30
  reason: "registry-unknown-chain",
31
31
  product: "fhevm",
32
32
  contract: "acl",