@tokenops/sdk 1.6.0 → 2.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/CHANGELOG.md +48 -8
  2. package/CONTRIBUTING.md +4 -2
  3. package/README.md +146 -90
  4. package/SUPPORT.md +47 -0
  5. package/dist/{chunk-HETNKZEE.js → chunk-335Z2W67.js} +1 -1
  6. package/dist/{chunk-BD4LZBVF.cjs → chunk-3QHNYEQD.cjs} +18 -17
  7. package/dist/chunk-456VDDA3.js +370 -0
  8. package/dist/{chunk-6WSNS3UV.js → chunk-4RAAATVY.js} +2 -4
  9. package/dist/{chunk-4KJ66YRH.js → chunk-4TSDNZQ3.js} +2 -2
  10. package/dist/{chunk-WUXUWTFW.cjs → chunk-5576FRT3.cjs} +31 -7
  11. package/dist/chunk-66IHPTOK.cjs +20 -0
  12. package/dist/{chunk-2RNW4MIJ.cjs → chunk-67OV5CX2.cjs} +0 -18
  13. package/dist/{chunk-PD7ME2BT.js → chunk-6GNR22OV.js} +2 -1
  14. package/dist/{chunk-VHSNYUYV.js → chunk-6NAVMWZQ.js} +5 -5
  15. package/dist/{chunk-EUKPOXWR.cjs → chunk-6PXXGACR.cjs} +17 -15
  16. package/dist/{chunk-WTK6JDSI.js → chunk-74QFZ5MK.js} +6 -4
  17. package/dist/{chunk-WOEETTH7.cjs → chunk-7AFPOE7N.cjs} +6 -6
  18. package/dist/{chunk-U57COLUE.js → chunk-AXIPOR3C.js} +2 -2
  19. package/dist/chunk-CTED3MTR.cjs +380 -0
  20. package/dist/{chunk-QKKBBH7I.js → chunk-DZHYSUGY.js} +28 -7
  21. package/dist/{chunk-V5D7BHW3.js → chunk-EAJ7SYHE.js} +6 -4
  22. package/dist/{chunk-SYHNZSZZ.cjs → chunk-FAXIIH5R.cjs} +3 -3
  23. package/dist/{chunk-7G7UOQV4.cjs → chunk-FGEB7RMY.cjs} +4 -4
  24. package/dist/chunk-GKKDAW44.js +8823 -0
  25. package/dist/{chunk-QET3Q4JP.js → chunk-H5POPGOZ.js} +8 -6
  26. package/dist/{chunk-VR3FREBX.cjs → chunk-JK4XMMKM.cjs} +3 -3
  27. package/dist/{chunk-CBRL2PJA.cjs → chunk-JQYC66TO.cjs} +12 -12
  28. package/dist/{chunk-YFIWCYHC.cjs → chunk-JZLGCTGK.cjs} +56 -54
  29. package/dist/{chunk-4ZCXK4VI.cjs → chunk-KFRDLKMA.cjs} +14 -14
  30. package/dist/chunk-KWFFIJYX.js +11 -0
  31. package/dist/chunk-M4IT6DNJ.cjs +608 -0
  32. package/dist/{chunk-43RFBQ73.cjs → chunk-MVDQMV25.cjs} +29 -32
  33. package/dist/chunk-NCVX3K2N.cjs +161 -0
  34. package/dist/chunk-NWFMBLSQ.js +4 -0
  35. package/dist/chunk-O5676ZWY.js +585 -0
  36. package/dist/chunk-PUX5VXDB.cjs +8845 -0
  37. package/dist/{chunk-DRSPMIZ7.js → chunk-QBJ7O2B4.js} +1 -11
  38. package/dist/{chunk-UJS4N2XM.cjs → chunk-TEBM66WA.cjs} +12 -12
  39. package/dist/{chunk-TN65XNTI.js → chunk-TWT3STIX.js} +8 -6
  40. package/dist/chunk-UG5RKLU2.cjs +6 -0
  41. package/dist/chunk-VP2B4WM2.js +154 -0
  42. package/dist/{chunk-BK7YIVLK.cjs → chunk-WJLECC22.cjs} +75 -73
  43. package/dist/{chunk-NFW7AUEX.js → chunk-WMACINXO.js} +1 -1
  44. package/dist/{chunk-AYGRYDBX.cjs → chunk-XAYGD4E4.cjs} +37 -35
  45. package/dist/{chunk-46T67CE2.js → chunk-ZA673I3O.js} +1 -1
  46. package/dist/{chunk-YPYCWLYP.js → chunk-ZWXJTBZO.js} +1 -1
  47. package/dist/core/addresses.d.ts +14 -2
  48. package/dist/core/brands.d.ts +8 -2
  49. package/dist/core/errors.d.ts +71 -10
  50. package/dist/core/preflight.d.ts +1 -0
  51. package/dist/fhe/erc7984-abi.d.ts +1 -0
  52. package/dist/fhe/index.cjs +64 -63
  53. package/dist/fhe/index.js +7 -6
  54. package/dist/fhe/operators.d.ts +22 -5
  55. package/dist/fhe/react/index.cjs +13 -12
  56. package/dist/fhe/react/index.js +6 -5
  57. package/dist/fhe/types.d.ts +6 -0
  58. package/dist/fhe-airdrop/abis/{cloneable.d.ts → airdrop-base.d.ts} +254 -396
  59. package/dist/fhe-airdrop/abis/compliance.d.ts +422 -0
  60. package/dist/fhe-airdrop/abis/ecdsa.d.ts +1316 -0
  61. package/dist/fhe-airdrop/abis/factory.d.ts +1319 -190
  62. package/dist/fhe-airdrop/abis/index.d.ts +5 -2
  63. package/dist/fhe-airdrop/abis/merkle.d.ts +1238 -0
  64. package/dist/fhe-airdrop/advanced/index.cjs +11 -12
  65. package/dist/fhe-airdrop/advanced/index.d.cts +34 -11
  66. package/dist/fhe-airdrop/advanced/index.d.ts +34 -11
  67. package/dist/fhe-airdrop/advanced/index.js +3 -8
  68. package/dist/fhe-airdrop/advanced/react/index.cjs +37 -50
  69. package/dist/fhe-airdrop/advanced/react/index.d.cts +9 -3
  70. package/dist/fhe-airdrop/advanced/react/index.d.ts +9 -3
  71. package/dist/fhe-airdrop/advanced/react/index.js +36 -50
  72. package/dist/fhe-airdrop/advanced/react/usePredictEcdsaAirdropAddress.d.ts +33 -0
  73. package/dist/fhe-airdrop/advanced/react/usePredictMerkleAirdropAddress.d.ts +27 -0
  74. package/dist/fhe-airdrop/airdrop-base.d.ts +600 -0
  75. package/dist/fhe-airdrop/campaign.d.ts +297 -0
  76. package/dist/fhe-airdrop/compliance.d.ts +302 -0
  77. package/dist/fhe-airdrop/constants.d.ts +33 -0
  78. package/dist/fhe-airdrop/ecdsa.d.ts +263 -0
  79. package/dist/fhe-airdrop/encryption.d.ts +92 -14
  80. package/dist/fhe-airdrop/errors.d.ts +245 -15
  81. package/dist/fhe-airdrop/factory.d.ts +533 -274
  82. package/dist/fhe-airdrop/guards.d.ts +273 -0
  83. package/dist/fhe-airdrop/index.cjs +1131 -74
  84. package/dist/fhe-airdrop/index.d.cts +46 -8
  85. package/dist/fhe-airdrop/index.d.ts +46 -8
  86. package/dist/fhe-airdrop/index.js +931 -8
  87. package/dist/fhe-airdrop/merkle-tree.d.ts +103 -0
  88. package/dist/fhe-airdrop/merkle.d.ts +180 -0
  89. package/dist/fhe-airdrop/react/_shared.d.ts +144 -71
  90. package/dist/fhe-airdrop/react/index.cjs +399 -459
  91. package/dist/fhe-airdrop/react/index.d.cts +53 -74
  92. package/dist/fhe-airdrop/react/index.d.ts +53 -74
  93. package/dist/fhe-airdrop/react/index.js +261 -374
  94. package/dist/fhe-airdrop/react/useAirdropGasFee.d.ts +10 -5
  95. package/dist/fhe-airdrop/react/useAirdropHasRole.d.ts +15 -6
  96. package/dist/fhe-airdrop/react/useAirdropPause.d.ts +30 -0
  97. package/dist/fhe-airdrop/react/useAirdropPaused.d.ts +17 -0
  98. package/dist/fhe-airdrop/react/useAirdropToken.d.ts +11 -4
  99. package/dist/fhe-airdrop/react/useAirdropWindow.d.ts +37 -0
  100. package/dist/fhe-airdrop/react/useClaimedAmount.d.ts +29 -0
  101. package/dist/fhe-airdrop/react/useComplianceManager.d.ts +16 -0
  102. package/dist/fhe-airdrop/react/useCreateEcdsaAirdrop.d.ts +28 -0
  103. package/dist/fhe-airdrop/react/useCreateMerkleAirdrop.d.ts +25 -0
  104. package/dist/fhe-airdrop/react/useEcdsaClaim.d.ts +23 -0
  105. package/dist/fhe-airdrop/react/useEffectiveUpgradeable.d.ts +20 -0
  106. package/dist/fhe-airdrop/react/useExtendClaimWindow.d.ts +17 -12
  107. package/dist/fhe-airdrop/react/useFactoryFees.d.ts +28 -0
  108. package/dist/fhe-airdrop/react/useFactoryRegistry.d.ts +35 -0
  109. package/dist/fhe-airdrop/react/useFundAirdrop.d.ts +35 -0
  110. package/dist/fhe-airdrop/react/useGrantInstanceRoles.d.ts +35 -0
  111. package/dist/fhe-airdrop/react/useMerkleClaim.d.ts +34 -0
  112. package/dist/fhe-airdrop/react/useMerkleRoot.d.ts +15 -0
  113. package/dist/fhe-airdrop/react/useSetMerkleRoot.d.ts +22 -0
  114. package/dist/fhe-airdrop/react/useWithdrawConfidential.d.ts +23 -0
  115. package/dist/fhe-airdrop/roles.d.ts +147 -0
  116. package/dist/fhe-airdrop/types.d.ts +67 -65
  117. package/dist/fhe-disperse/index.cjs +70 -68
  118. package/dist/fhe-disperse/index.js +10 -8
  119. package/dist/fhe-disperse/react/index.cjs +94 -92
  120. package/dist/fhe-disperse/react/index.js +13 -11
  121. package/dist/fhe-vesting/advanced/index.cjs +10 -8
  122. package/dist/fhe-vesting/advanced/index.js +8 -6
  123. package/dist/fhe-vesting/advanced/react/index.cjs +16 -14
  124. package/dist/fhe-vesting/advanced/react/index.js +13 -11
  125. package/dist/fhe-vesting/index.cjs +74 -72
  126. package/dist/fhe-vesting/index.js +11 -9
  127. package/dist/fhe-vesting/react/index.cjs +228 -226
  128. package/dist/fhe-vesting/react/index.js +15 -13
  129. package/dist/index.cjs +100 -87
  130. package/dist/index.js +3 -2
  131. package/dist/testnet-faucet/index.cjs +57 -55
  132. package/dist/testnet-faucet/index.js +7 -5
  133. package/dist/testnet-faucet/react/index.cjs +55 -53
  134. package/dist/testnet-faucet/react/index.js +9 -7
  135. package/package.json +6 -2
  136. package/dist/chunk-CNP4L3GF.js +0 -105
  137. package/dist/chunk-KSDSXJ34.js +0 -41
  138. package/dist/chunk-LBWRFZR3.cjs +0 -1681
  139. package/dist/chunk-OL6SHN3D.cjs +0 -44
  140. package/dist/chunk-S2XD75JM.js +0 -1637
  141. package/dist/chunk-SPGSO5SO.cjs +0 -1644
  142. package/dist/chunk-UE5XK2SY.js +0 -1673
  143. package/dist/chunk-WO72UBQD.cjs +0 -109
  144. package/dist/fhe-airdrop/advanced/factory-advanced.d.ts +0 -53
  145. package/dist/fhe-airdrop/advanced/react/usePredictAirdropAddress.d.ts +0 -49
  146. package/dist/fhe-airdrop/airdrop.d.ts +0 -317
  147. package/dist/fhe-airdrop/react/useAccessClaimAmount.d.ts +0 -37
  148. package/dist/fhe-airdrop/react/useAirdropCanExtendClaimWindow.d.ts +0 -7
  149. package/dist/fhe-airdrop/react/useAirdropClaimTypehash.d.ts +0 -10
  150. package/dist/fhe-airdrop/react/useAirdropClaimedSignatures.d.ts +0 -16
  151. package/dist/fhe-airdrop/react/useAirdropDeploymentBlockNumber.d.ts +0 -6
  152. package/dist/fhe-airdrop/react/useAirdropDomainSeparator.d.ts +0 -8
  153. package/dist/fhe-airdrop/react/useAirdropEndTime.d.ts +0 -10
  154. package/dist/fhe-airdrop/react/useAirdropFactoryCustomFee.d.ts +0 -17
  155. package/dist/fhe-airdrop/react/useAirdropFactoryDefaultGasFee.d.ts +0 -10
  156. package/dist/fhe-airdrop/react/useAirdropFactoryDisableCustomFee.d.ts +0 -15
  157. package/dist/fhe-airdrop/react/useAirdropFactoryFeeCollector.d.ts +0 -11
  158. package/dist/fhe-airdrop/react/useAirdropFactoryInitCodeHash.d.ts +0 -17
  159. package/dist/fhe-airdrop/react/useAirdropFactorySetCustomFee.d.ts +0 -17
  160. package/dist/fhe-airdrop/react/useAirdropFactorySetDefaultGasFee.d.ts +0 -16
  161. package/dist/fhe-airdrop/react/useAirdropFactorySetFeeCollector.d.ts +0 -15
  162. package/dist/fhe-airdrop/react/useAirdropGrantRole.d.ts +0 -16
  163. package/dist/fhe-airdrop/react/useAirdropHasClaimEnded.d.ts +0 -7
  164. package/dist/fhe-airdrop/react/useAirdropHasClaimStarted.d.ts +0 -7
  165. package/dist/fhe-airdrop/react/useAirdropIsClaimWindowActive.d.ts +0 -9
  166. package/dist/fhe-airdrop/react/useAirdropIsPaused.d.ts +0 -8
  167. package/dist/fhe-airdrop/react/useAirdropIsSignatureClaimed.d.ts +0 -22
  168. package/dist/fhe-airdrop/react/useAirdropIsSignatureValid.d.ts +0 -51
  169. package/dist/fhe-airdrop/react/useAirdropRevokeRole.d.ts +0 -15
  170. package/dist/fhe-airdrop/react/useAirdropStartTime.d.ts +0 -10
  171. package/dist/fhe-airdrop/react/useAirdropWithdrawGasFee.d.ts +0 -15
  172. package/dist/fhe-airdrop/react/useAirdropWithdrawOtherConfidentialToken.d.ts +0 -14
  173. package/dist/fhe-airdrop/react/useAirdropWithdrawOtherToken.d.ts +0 -14
  174. package/dist/fhe-airdrop/react/useClaim.d.ts +0 -39
  175. package/dist/fhe-airdrop/react/useConfidentialAirdropFactoryImplementation.d.ts +0 -11
  176. package/dist/fhe-airdrop/react/useCreateAndFundConfidentialAirdrop.d.ts +0 -41
  177. package/dist/fhe-airdrop/react/useCreateAndFundConfidentialAirdropAndGetAddress.d.ts +0 -48
  178. package/dist/fhe-airdrop/react/useCreateConfidentialAirdrop.d.ts +0 -29
  179. package/dist/fhe-airdrop/react/useCreateConfidentialAirdropAndGetAddress.d.ts +0 -31
  180. package/dist/fhe-airdrop/react/useDisableCustomFee.d.ts +0 -14
  181. package/dist/fhe-airdrop/react/useFactoryCustomFee.d.ts +0 -17
  182. package/dist/fhe-airdrop/react/useFactoryDefaultGasFee.d.ts +0 -10
  183. package/dist/fhe-airdrop/react/useFactoryFeeCollector.d.ts +0 -11
  184. package/dist/fhe-airdrop/react/useFactoryInitCodeHash.d.ts +0 -17
  185. package/dist/fhe-airdrop/react/useFundConfidentialAirdrop.d.ts +0 -33
  186. package/dist/fhe-airdrop/react/usePreflightCreateAirdrop.d.ts +0 -51
  187. package/dist/fhe-airdrop/react/useSetCustomFee.d.ts +0 -16
  188. package/dist/fhe-airdrop/react/useSetDefaultGasFee.d.ts +0 -15
  189. package/dist/fhe-airdrop/react/useSetFeeCollector.d.ts +0 -14
  190. package/dist/fhe-airdrop/react/useSetPaused.d.ts +0 -14
  191. package/dist/fhe-airdrop/react/useSignClaimAuthorization.d.ts +0 -31
  192. package/dist/fhe-airdrop/react/useWithdraw.d.ts +0 -12
  193. package/dist/fhe-airdrop/react/useWithdrawOtherConfidentialToken.d.ts +0 -13
  194. package/dist/fhe-airdrop/react/useWithdrawOtherToken.d.ts +0 -13
@@ -0,0 +1,103 @@
1
+ import type { Address, Hex } from "viem";
2
+ /**
3
+ * Inputs for {@link leafOf}.
4
+ *
5
+ * @alpha
6
+ */
7
+ export interface LeafOfArgs {
8
+ /** The `MerkleConfidentialAirdrop` instance the leaf is scoped to — `address(this)` on-chain. */
9
+ instance: Address;
10
+ /** The claiming account — always `msg.sender` on-chain, never the claim's payout destination. */
11
+ recipient: Address;
12
+ /** The encrypted handle committing the recipient's cumulative total allocation. */
13
+ handle: Hex;
14
+ }
15
+ /**
16
+ * Compute a Merkle leaf byte-for-byte identical to the contract's
17
+ * `_leafOf(recipient, inputAmount)` — see the module comment above for the
18
+ * verified derivation. Mirrors what the campaign builder (`buildMerkleCampaign`,
19
+ * `campaign.ts`) needs to construct the same tree `StandardMerkleTree` would,
20
+ * and is useful to any caller who wants to recompute a leaf independently of
21
+ * the campaign orchestrator.
22
+ *
23
+ * @alpha
24
+ */
25
+ export declare function leafOf(args: LeafOfArgs): Hex;
26
+ /**
27
+ * The minimum a leaf must carry. `buildMerkleTree` is generic over anything
28
+ * wider, so a caller's own fields ride along onto the entry.
29
+ *
30
+ * @alpha
31
+ */
32
+ export interface MerkleLeafInput {
33
+ /** The account that will SEND the claim. The contract recomputes the leaf as `_leafOf(msg.sender, inputAmount)`. */
34
+ recipient: Address;
35
+ /** The encrypted handle committing this recipient's cumulative total. */
36
+ handle: Hex;
37
+ }
38
+ /**
39
+ * Inputs for {@link buildMerkleTree}.
40
+ *
41
+ * @alpha
42
+ */
43
+ export interface BuildMerkleTreeArgs<L extends MerkleLeafInput> {
44
+ /** The `MerkleConfidentialAirdrop` instance the leaves are scoped to. Not the factory, not the implementation. */
45
+ instance: Address;
46
+ leaves: readonly L[];
47
+ }
48
+ /**
49
+ * A built tree: the root to publish, and every input leaf with its proof attached.
50
+ *
51
+ * @alpha
52
+ */
53
+ export interface BuiltMerkleTree<L extends MerkleLeafInput> {
54
+ root: Hex;
55
+ entries: readonly (L & {
56
+ merkleProof: readonly Hex[];
57
+ })[];
58
+ }
59
+ /**
60
+ * Build the Merkle tree a `MerkleConfidentialAirdrop` verifies against, from
61
+ * handles produced anywhere.
62
+ *
63
+ * **Pure.** No relayer, no chain access, no encryptor. Given the same leaves
64
+ * it returns the same root, so it can run offline, in a test, or on a machine
65
+ * that has never seen a private key.
66
+ *
67
+ * **The tree commits to the handle, not the amount.** `_leafOf` hashes
68
+ * `(address(this), recipient, encHandle)`, so whoever encrypted must have bound
69
+ * each input to `(instance, that recipient)` — `FHE.fromExternal` reverts on any
70
+ * mismatch. This function cannot check that; it will happily build a tree over
71
+ * wrongly-bound handles, and the failure surfaces at claim time.
72
+ *
73
+ * **Extra fields ride along.** Whatever the leaf carries beyond
74
+ * `recipient` and `handle` — an `inputProof`, your own row id — comes back on
75
+ * the entry, still aligned with its proof. Passing
76
+ * `{ recipient, handle, inputProof }` therefore yields a value structurally
77
+ * assignable to `CampaignEntry`, which is what `MerkleAirdropClient.claim`
78
+ * consumes.
79
+ *
80
+ * @param args The instance the leaves are scoped to, and the leaves.
81
+ * @returns The root to publish, and one proof-bearing entry per input leaf, in input order.
82
+ * @throws {@link InvalidArgumentError} on a zero or malformed instance, an empty leaf set, a malformed or zero recipient, a duplicate recipient, or a handle that is not 32 bytes.
83
+ *
84
+ * @example
85
+ * const { root, entries } = buildMerkleTree({
86
+ * instance: airdrop,
87
+ * leaves: [{ recipient: alice, handle, inputProof }],
88
+ * });
89
+ * await merkle.setMerkleRoot({ newRoot: root });
90
+ *
91
+ * @alpha
92
+ */
93
+ export declare function buildMerkleTree<L extends MerkleLeafInput>(args: BuildMerkleTreeArgs<L>): BuiltMerkleTree<L>;
94
+ /**
95
+ * Real implementation behind {@link buildMerkleTree}, parameterised on the
96
+ * function name a thrown {@link InvalidArgumentError} blames.
97
+ *
98
+ * Not part of the public surface — exported from this module only so
99
+ * `buildMerkleCampaign` (`campaign.ts`) can call it directly with its own
100
+ * name, attributing a malformed-handle failure to itself rather than to
101
+ * `buildMerkleTree`. Neither barrel (`index.ts`) re-exports it.
102
+ */
103
+ export declare function buildMerkleTreeInternal<L extends MerkleLeafInput>({ instance, leaves }: BuildMerkleTreeArgs<L>, method: string): BuiltMerkleTree<L>;
@@ -0,0 +1,180 @@
1
+ import type { Address, Hex } from "viem";
2
+ import { type EncryptedHandle } from "../core/brands.js";
3
+ import type { EncryptedViewResult } from "../fhe/types.js";
4
+ import { AirdropBaseClient, type AirdropBaseClientConfig, type WriteAccountOverride } from "./airdrop-base.js";
5
+ import type { CampaignEntry } from "./types.js";
6
+ /**
7
+ * Inputs shared by {@link MerkleAirdropClient.claim} and {@link MerkleAirdropClient.claimAndUnwrap}.
8
+ *
9
+ * @alpha
10
+ */
11
+ export interface MerkleClaimArgs extends WriteAccountOverride {
12
+ /**
13
+ * Payout destination. Omit (or pass the zero address) to default to the
14
+ * sending account — mirrors the contract's own `to == address(0)` redirect
15
+ * rule. The leaf's recipient field, the outstanding-amount accounting and
16
+ * the FHE input proof all stay bound to the sending account regardless of
17
+ * `to`; this field only redirects where the tokens (and the recipient ACL)
18
+ * land.
19
+ */
20
+ to?: Address;
21
+ /**
22
+ * The recipient's proof-bearing claim entry, built by the campaign
23
+ * orchestrator (`campaign.ts`, Task 11). `entry.recipient` must equal the
24
+ * account this call sends from (`args.account`, or the wallet client's
25
+ * default account): the contract recomputes the leaf as
26
+ * `_leafOf(msg.sender, inputAmount)`, so submitting `entry.merkleProof`
27
+ * from any account other than `entry.recipient` recomputes a different
28
+ * leaf and reverts `InvalidMerkleProof` even though the proof bytes
29
+ * themselves are untouched.
30
+ */
31
+ entry: CampaignEntry;
32
+ }
33
+ /**
34
+ * Inputs for {@link MerkleAirdropClient.getClaimAmount}.
35
+ *
36
+ * @alpha
37
+ */
38
+ export interface GetClaimAmountArgs extends WriteAccountOverride {
39
+ /**
40
+ * Same binding rule as {@link MerkleClaimArgs.entry}: `entry.recipient`
41
+ * must equal the calling account, since the contract's preview also
42
+ * recomputes the leaf against `msg.sender`.
43
+ */
44
+ entry: CampaignEntry;
45
+ }
46
+ /**
47
+ * Client for one `MerkleConfidentialAirdrop` instance — the variant whose
48
+ * claims are authorised by inclusion in a published Merkle tree rather than
49
+ * an off-chain signature. Each leaf commits `(instance, recipient, handle)`,
50
+ * where `handle` is the recipient's CUMULATIVE total allocation, not a
51
+ * per-drop tranche — see the `@remarks` on {@link getClaimedAmount}.
52
+ *
53
+ * Adds the claim surface on top of {@link AirdropBaseClient}'s shared
54
+ * lifecycle/treasury/rescue/role/disclosure methods: `claim` /
55
+ * `claimAndUnwrap` submit a proof-bearing allocation, `getClaimAmount`
56
+ * previews the outstanding amount as a decryptable handle, and
57
+ * `getClaimedAmount` reads an account's running delivered total.
58
+ *
59
+ * Every claim entrypoint here takes the exact-equality gas fee
60
+ * ({@link AirdropBaseClient.gasFee}) automatically — read fresh on every
61
+ * `claim`/`claimAndUnwrap` call and attached as the transaction's `value`, so
62
+ * a caller never has to source it themselves or risk sending the wrong
63
+ * amount against the contract's `msg.value != gasFee()` revert.
64
+ *
65
+ * @example
66
+ * const airdrop = new MerkleAirdropClient({ publicClient, walletClient, address });
67
+ * const hash = await airdrop.claim({ entry });
68
+ *
69
+ * @alpha
70
+ */
71
+ export declare class MerkleAirdropClient extends AirdropBaseClient {
72
+ constructor(config: AirdropBaseClientConfig);
73
+ /**
74
+ * Claim the outstanding amount for a proof-bearing entry, delivering the
75
+ * tokens to `to` (defaults to the sending account).
76
+ *
77
+ * Requires `msg.value == gasFee()` exactly — handled for you; see the
78
+ * class TSDoc.
79
+ *
80
+ * @remarks
81
+ * There is no per-leaf consumption on this variant — replay safety is the
82
+ * accounting itself, not a spent-flag. Re-presenting an already-settled
83
+ * entry computes an encrypted-zero outstanding amount and pays nothing,
84
+ * but the gas fee is still charged (the amounts are encrypted, so a
85
+ * zero-outstanding claim cannot be detected or rejected on-chain).
86
+ * Presenting two different entries for the SAME recipient under one root
87
+ * pays whichever entry's cumulative total is higher net of what the other
88
+ * already delivered — effectively `max`, not `sum`, of the two totals.
89
+ *
90
+ * @throws {@link ClaimNotStartedError} before `startTime`.
91
+ * @throws {@link ClaimWindowClosedError} after `endTime`.
92
+ * @throws {@link InvalidArgumentError} (`argument: "merkleProof"`) when the proof does not verify against
93
+ * the current root — including when `entry.recipient` does not match the sending account.
94
+ * @returns The transaction hash.
95
+ */
96
+ claim(args: MerkleClaimArgs): Promise<Hex>;
97
+ /**
98
+ * Claim then route the allocation straight into the wrapper's unwrap
99
+ * (`to` becomes the underlying ERC-20 beneficiary). Reverts
100
+ * `TokenNotUnwrappable` (surfaced as `FeatureDisabledError`) on a
101
+ * non-unwrappable campaign.
102
+ *
103
+ * Same replay/accounting semantics and `msg.value == gasFee()` requirement
104
+ * as {@link claim} — see its `@remarks`.
105
+ *
106
+ * @returns The transaction hash. The underlying ERC-20 is released later by
107
+ * a separate, permissionless `finalizeUnwrap` — this hash is only the
108
+ * unwrap request.
109
+ */
110
+ claimAndUnwrap(args: MerkleClaimArgs): Promise<Hex>;
111
+ /**
112
+ * Preview the outstanding amount for a proof-bearing entry as a handle the
113
+ * caller can decrypt. Consumes no accounting and no per-leaf state — the
114
+ * same entry still pays the same amount after a preview. No fee.
115
+ *
116
+ * An encrypted view: the contract calls `FHE.allow(outstanding, msg.sender)`,
117
+ * so the result is recovered from the receipt's ACL `Allowed` event, never
118
+ * from a simulation. See {@link AirdropBaseClient}'s class TSDoc.
119
+ *
120
+ * @returns `{ handle, hash }` — pass `handle` to the Zama relayer's `userDecrypt`.
121
+ */
122
+ getClaimAmount(args: GetClaimAmountArgs): Promise<EncryptedViewResult>;
123
+ /**
124
+ * Read `account`'s running delivered total as an encrypted handle.
125
+ *
126
+ * @remarks
127
+ * Since round 8 a Merkle leaf commits the recipient's CUMULATIVE total
128
+ * allocation, not a per-drop tranche, and this getter mirrors that: it
129
+ * returns the cumulative amount actually DELIVERED so far, not a per-claim
130
+ * amount. A claim pays `total - min(total, alreadyDelivered)`, where
131
+ * `alreadyDelivered` is exactly this value.
132
+ *
133
+ * Two consequences worth calling out explicitly:
134
+ * - **A root rotation is a top-up, not a second payout.** Rotating the
135
+ * root republishes updated cumulative totals; this value is keyed by
136
+ * `account` alone (not by root), so a claim against the new root pays
137
+ * only the increase over what this getter already reports.
138
+ * - **One leaf per recipient per root.** If a tree mistakenly commits two
139
+ * leaves for the same recipient, claiming both pays the higher of the
140
+ * two totals net of this running value — `max`, not `sum`.
141
+ *
142
+ * The zero handle (uninitialized ciphertext) before an account's first
143
+ * settled claim decrypts as zero.
144
+ *
145
+ * @returns The account's cumulative delivered total, as an encrypted handle.
146
+ */
147
+ getClaimedAmount(account: Address): Promise<EncryptedHandle>;
148
+ /** The currently published root. Proofs must verify against this exact value. */
149
+ merkleRoot(): Promise<Hex>;
150
+ /** Whether {@link setMerkleRoot} can succeed at all — fixed at create time, never toggled after. */
151
+ isMerkleRootMutable(): Promise<boolean>;
152
+ /**
153
+ * Rotate the published root. Requires `MERKLE_ADMIN_ROLE`.
154
+ *
155
+ * A rotation republishes UPDATED cumulative totals — it tops accounts up,
156
+ * it never claws back: {@link getClaimedAmount}'s running total survives
157
+ * the rotation and every future claim still nets it out. See that
158
+ * getter's `@remarks`.
159
+ *
160
+ * @throws {@link FeatureDisabledError} (`feature: "merkleRootRotation"`) when the campaign was created
161
+ * with `isMerkleRootMutable: false`.
162
+ * @throws {@link InvalidArgumentError} (`argument: "merkleRoot"`) when `newRoot` is zero — a zero root
163
+ * would silently brick every claim with no way to fix it; pause instead.
164
+ * @returns The transaction hash.
165
+ */
166
+ setMerkleRoot(args: {
167
+ newRoot: Hex;
168
+ } & WriteAccountOverride): Promise<Hex>;
169
+ /** Gates {@link setMerkleRoot}. */
170
+ MERKLE_ADMIN_ROLE(): Promise<Hex>;
171
+ }
172
+ /**
173
+ * Create a {@link MerkleAirdropClient}. Mirrors viem's `create*` convention.
174
+ *
175
+ * @example
176
+ * const airdrop = createMerkleAirdropClient({ publicClient, walletClient, address });
177
+ *
178
+ * @alpha
179
+ */
180
+ export declare function createMerkleAirdropClient(config: AirdropBaseClientConfig): MerkleAirdropClient;
@@ -1,64 +1,134 @@
1
+ import type { UseQueryOptions } from "@tanstack/react-query";
1
2
  import type { Address, PublicClient, WalletClient } from "viem";
2
3
  import { DeploymentAddressUnavailableError } from "../../core/errors.js";
3
- import { type Encryptor, type EncryptorSource } from "../encryption.js";
4
+ import type { SdkTelemetry } from "../../core/telemetry.js";
5
+ import { type AirdropBaseClient } from "../airdrop-base.js";
6
+ import type { DedupMode } from "../constants.js";
7
+ import { type EcdsaAirdropClient } from "../ecdsa.js";
8
+ import { type EncryptorSource } from "../encryption.js";
4
9
  import { type ConfidentialAirdropFactoryClient } from "../factory.js";
5
- import { type ConfidentialAirdropClient } from "../airdrop.js";
6
- /** Common per-hook overrides — every public hook accepts these alongside its own args. */
7
- export interface BaseHookOptions {
8
- /** Override the on-chain contract address. Defaults to {@link getFheAirdropFactoryAddress} keyed by chain id. */
10
+ import { type MerkleAirdropClient } from "../merkle.js";
11
+ /**
12
+ * Stable query-key prefix for every hook in this subpath — matches the
13
+ * sibling subpaths' convention (`FHE_VESTING_KEY`/`FHE_DISPERSE_KEY`/
14
+ * `TESTNET_FAUCET_KEY` all use `"tokenops-sdk"`; see `src/fhe-vesting/react/_shared.ts`,
15
+ * `src/fhe-disperse/react/_shared.ts`, `src/testnet-faucet/react/_shared.ts`).
16
+ *
17
+ * Not `"tokenops"` — an earlier draft of this file used that value; fixed so
18
+ * a consumer calling `queryClient.invalidateQueries({ queryKey: ["tokenops-sdk"] })`
19
+ * to clear every `@tokenops/sdk` cache entry doesn't silently miss this
20
+ * subpath's queries.
21
+ */
22
+ export declare const FHE_AIRDROP_KEY: "tokenops-sdk";
23
+ export declare const FHE_AIRDROP_NAMESPACE: "fhe-airdrop";
24
+ /**
25
+ * Build the TanStack Query key for an `/fhe-airdrop` read.
26
+ *
27
+ * Namespaced by chain id AND instance/factory address so cache entries never
28
+ * bleed across chains or campaigns — two different campaign instances (or
29
+ * the same instance on two chains) never share a cache slot. Caller-specific
30
+ * reads (e.g. `getClaimedAmount(account)`) pass `account` as part of `args`,
31
+ * so switching the connected account changes the key and never serves a
32
+ * stale value cached under the previous account.
33
+ *
34
+ * @returns `["tokenops-sdk", "fhe-airdrop", chainId, address, fn, args]`.
35
+ *
36
+ * @alpha
37
+ */
38
+ export declare function airdropQueryKey(params: {
39
+ chainId: number | undefined;
40
+ address: Address | undefined;
41
+ fn: string;
42
+ args: ReadonlyArray<unknown>;
43
+ }): unknown[];
44
+ /**
45
+ * Build the *prefix* of {@link airdropQueryKey} up to (and including) `fn` —
46
+ * useful for `invalidateQueries({ queryKey: airdropQueryKeyPrefix(...), exact: false })`
47
+ * when a write affects every cached read for one function regardless of args
48
+ * (e.g. every `hasRole` entry for one instance, regardless of which
49
+ * role/holder pair was queried).
50
+ *
51
+ * @alpha
52
+ */
53
+ export declare function airdropQueryKeyPrefix(params: {
54
+ chainId: number | undefined;
55
+ address: Address | undefined;
56
+ fn?: string;
57
+ }): unknown[];
58
+ /**
59
+ * The client-construction subset of every hook's options — deliberately NOT
60
+ * generic over `TData`. Client-memo helpers (`useMemoAirdropBaseClient`,
61
+ * etc.) accept this narrower shape rather than {@link AirdropHookOptions},
62
+ * because a `useQuery<TData, ...>` per-hook `query` option makes the wider
63
+ * type invariant in `TData` (the `enabled` callback's parameter type), which
64
+ * would otherwise force every memo helper to be generic too.
65
+ *
66
+ * @alpha
67
+ */
68
+ export interface AirdropClientOptions {
69
+ /** Instance or factory address override. Factory hooks default this by chain id; instance hooks require it. */
9
70
  address?: Address;
10
71
  /** Override the chain id used for default address resolution. Defaults to `usePublicClient().chain?.id`. */
11
72
  chainId?: number;
12
- }
13
- /** Per-hook overrides for factory hooks that submit encrypted inputs. */
14
- export interface FactoryHookOptions extends BaseHookOptions {
15
73
  /**
16
- * Lazy or eager encryptor source. Optional at hook level; **required at call
17
- * time** for factory methods that submit encrypted inputs
18
- * (`useCreateAndFundConfidentialAirdrop`, `useFundConfidentialAirdrop`).
19
- *
20
- * Recommended in React: capture `useZamaSDK()` once at the top of your
21
- * component and wire `encryptor: () => sdk.relayer` — the SDK
22
- * calls this per-encryption so it picks up the live `ZamaSDK` instance
23
- * rather than a stale capture (CLAUDE.md Pitfall #3).
74
+ * Lazy or eager encryptor source. Only consumed by hooks that submit
75
+ * encrypted inputs (`useFundAirdrop`). Recommended in React: capture
76
+ * `useZamaSDK()` once and wire `encryptor: () => sdk.relayer` so the SDK
77
+ * picks up the live context at submit time (CLAUDE.md Pitfall #3) rather
78
+ * than a stale capture. An eager `Encryptor` instance also type-checks.
24
79
  */
25
80
  encryptor?: EncryptorSource;
81
+ /**
82
+ * Optional telemetry adapter. Forwarded into the headless client so spans
83
+ * and `*.client.init` events flow through whichever sink the consumer
84
+ * wires up (PostHog, OTel, Sentry, custom).
85
+ */
86
+ telemetry?: SdkTelemetry;
26
87
  }
27
- /** Per-hook overrides for FHE-airdrop *clone* hooks — `address` is required (per-airdrop). */
28
- export interface AirdropHookOptions {
29
- /** Deployed airdrop clone address. Required — there is no chain-level default. */
30
- address: Address;
31
- /** Override the FHEVM ACL address (defaults to chain-id lookup). */
32
- aclAddress?: Address;
33
- /** Override the chain id used for ACL/public-client lookup. Defaults to `usePublicClient().chain?.id`. */
34
- chainId?: number;
35
- }
36
- /** Stable query-key prefix for every hook in this subpath. */
37
- export declare const FHE_AIRDROP_KEY: "tokenops-sdk";
38
- export declare const FHE_AIRDROP_NAMESPACE: "fhe-airdrop";
39
88
  /**
40
- * Resolve the FHE-airdrop factory address for `chainId`, mirroring the
41
- * headless client's resolution. Throws the same {@link TokenOpsSdkError} the
42
- * headless client would throw at construction time.
89
+ * Common per-hook overrides — every public read hook accepts these alongside its own args.
90
+ *
91
+ * @alpha
43
92
  */
44
- export declare function resolveFactoryAddress(override: Address | undefined, chainId: number | undefined): Address;
93
+ export interface AirdropHookOptions<TData = unknown> extends AirdropClientOptions {
94
+ /**
95
+ * Escape hatch for TanStack Query's own cache-behavior options
96
+ * (`staleTime`, `gcTime`, `select`, `refetchInterval`, …). Cannot override
97
+ * `queryKey` / `queryFn` — those stay owned by the hook so cache identity
98
+ * is never at risk of drifting from what was actually fetched.
99
+ */
100
+ query?: Omit<UseQueryOptions<TData, Error>, "queryKey" | "queryFn">;
101
+ }
45
102
  /**
46
- * Same as {@link resolveFactoryAddress} but returns `undefined` instead of
47
- * throwing. Used by query-key builders and `enabled` gates.
103
+ * Instance-scoped hook options — `address` is required (a campaign instance, not a chain-wide default).
104
+ *
105
+ * @alpha
48
106
  */
49
- export declare function tryResolveFactoryAddress(override: Address | undefined, chainId: number | undefined): Address | undefined;
107
+ export type AirdropInstanceHookOptions<TData = unknown> = AirdropHookOptions<TData> & {
108
+ address: Address;
109
+ };
50
110
  /**
51
- * Memoize an {@link ConfidentialAirdropFactoryClient} keyed on
52
- * `(publicClient, walletClient, address)`. The encryptor source is passed
53
- * through as a **lazy** function (mirroring Pitfall #3 from CLAUDE.md): the
54
- * SDK calls it per-encryption, picking up the live React context at submit
55
- * time rather than baking in a stale capture.
111
+ * Non-generic instance-scoped client options, for memo helpers.
56
112
  *
57
- * @returns `{ client, publicClient, walletClient }`. `client` is `undefined`
58
- * when no `publicClient` is available (wagmi may briefly return `undefined`
59
- * during reconnects) — gate queries with `enabled: !!client`.
113
+ * @alpha
114
+ */
115
+ export type AirdropInstanceClientOptions = AirdropClientOptions & {
116
+ address: Address;
117
+ };
118
+ /**
119
+ * Resolve the airdrop factory address for `chainId`, mirroring the headless
120
+ * client's resolution. Returns `undefined` instead of throwing — used by
121
+ * query-key builders and `enabled` gates.
60
122
  */
61
- export declare function useMemoFactoryClient(opts?: FactoryHookOptions): {
123
+ export declare function tryResolveAirdropFactoryAddress(override: Address | undefined, chainId: number | undefined): Address | undefined;
124
+ /**
125
+ * Memoize a {@link ConfidentialAirdropFactoryClient} keyed on
126
+ * `(publicClient, walletClient, address, chainId)`. The encryptor source is
127
+ * threaded through as a lazy ref (CLAUDE.md Pitfall #3): the client calls it
128
+ * per-encryption, so it always sees the live React value rather than one
129
+ * baked in at memo time.
130
+ */
131
+ export declare function useMemoAirdropFactoryClient(opts?: AirdropClientOptions): {
62
132
  client: ConfidentialAirdropFactoryClient | undefined;
63
133
  resolutionError: DeploymentAddressUnavailableError | undefined;
64
134
  publicClient: PublicClient | undefined;
@@ -67,41 +137,44 @@ export declare function useMemoFactoryClient(opts?: FactoryHookOptions): {
67
137
  resolvedAddress: Address | undefined;
68
138
  };
69
139
  /**
70
- * Memoize a {@link ConfidentialAirdropClient} keyed on
71
- * `(publicClient, walletClient, address, aclAddress)`. The airdrop clone
72
- * client does not encrypt — the recipient submits an admin-issued
73
- * `{ encryptedInput, signature }` pair as-is — so no encryptor is wired here.
140
+ * Memoize an {@link AirdropBaseClient} for `opts.address` — the surface
141
+ * shared by both variants (lifecycle, treasury, rescue, roles, disclosure).
142
+ * Use this for hooks that don't need a variant-specific method.
74
143
  */
75
- export declare function useMemoAirdropClient(opts: AirdropHookOptions): {
76
- client: ConfidentialAirdropClient | undefined;
144
+ export declare function useMemoAirdropBaseClient(opts: AirdropInstanceClientOptions): {
145
+ client: AirdropBaseClient | undefined;
146
+ publicClient: PublicClient | undefined;
147
+ walletClient: WalletClient | undefined;
148
+ chainId: number | undefined;
149
+ };
150
+ /** Memoize a {@link MerkleAirdropClient} for `opts.address`. */
151
+ export declare function useMemoMerkleAirdropClient(opts: AirdropInstanceClientOptions): {
152
+ client: MerkleAirdropClient | undefined;
77
153
  publicClient: PublicClient | undefined;
78
154
  walletClient: WalletClient | undefined;
79
155
  chainId: number | undefined;
80
156
  };
81
157
  /**
82
- * Resolve the encryptor for a mutation call. Order:
83
- * 1. Explicit `override` (eager `Encryptor` or lazy `() => Encryptor | undefined`).
84
- * 2. The hook-level `encryptor` source from the hook options.
85
- *
86
- * Both are resolved per-call (not cached), mirroring the lazy `EncryptorSource`
87
- * pattern from CLAUDE.md Pitfall #3 — the consumer's React context is the
88
- * source of truth.
158
+ * Per-hook overrides for {@link useMemoEcdsaAirdropClient} — `dedupMode` has no on-chain getter, so it must be supplied.
89
159
  *
90
- * If both are missing, throws an actionable error. The hook layer does NOT
91
- * dynamically import `@zama-fhe/react-sdk` — calling `useZamaSDK()` from
92
- * inside `mutationFn` would violate the rules of hooks. Consumers wire the
93
- * encryptor at hook construction. The safe pattern is two lines:
94
- * `const sdk = useZamaSDK();` then `encryptor: () => sdk.relayer` — never
95
- * `() => useZamaSDK().relayer` inline (that calls a React hook inside a
96
- * mutation body, violating the rules of hooks).
160
+ * @alpha
97
161
  */
98
- export declare function resolveCallTimeEncryptor(override: Encryptor | EncryptorSource | undefined, hookLevelSource: EncryptorSource | undefined): Encryptor;
162
+ export type EcdsaAirdropInstanceHookOptions<TData = unknown> = AirdropInstanceHookOptions<TData> & {
163
+ /** @see EcdsaAirdropClientConfig.dedupMode */
164
+ dedupMode: DedupMode;
165
+ };
99
166
  /**
100
- * Build a stable TanStack Query key for an FHE-airdrop hook.
167
+ * Non-generic version of {@link EcdsaAirdropInstanceHookOptions}, for the memo helper.
101
168
  *
102
- * Conventions:
103
- * - Lowercase the contract address (TanStack uses structural equality; viem
104
- * sometimes returns checksummed addresses).
105
- * - Convert bigints to base-10 strings (TanStack's serializer doesn't handle bigints).
169
+ * @alpha
106
170
  */
107
- export declare function buildQueryKey(method: string, chainId: number | undefined, address: Address | undefined, ...args: ReadonlyArray<unknown>): ReadonlyArray<unknown>;
171
+ export type EcdsaAirdropInstanceClientOptions = AirdropInstanceClientOptions & {
172
+ dedupMode: DedupMode;
173
+ };
174
+ /** Memoize an {@link EcdsaAirdropClient} for `opts.address`. */
175
+ export declare function useMemoEcdsaAirdropClient(opts: EcdsaAirdropInstanceClientOptions): {
176
+ client: EcdsaAirdropClient | undefined;
177
+ publicClient: PublicClient | undefined;
178
+ walletClient: WalletClient | undefined;
179
+ chainId: number | undefined;
180
+ };