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

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 (145) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +5 -5
  3. package/dist/{chunk-JZLGCTGK.cjs → chunk-3YHBO2DL.cjs} +2 -2
  4. package/dist/{chunk-H5POPGOZ.js → chunk-44YJPMQC.js} +1 -1
  5. package/dist/{chunk-DZHYSUGY.js → chunk-A4DCEE33.js} +11 -5
  6. package/dist/{chunk-M4IT6DNJ.cjs → chunk-AREQJHKA.cjs} +108 -3
  7. package/dist/chunk-EBLBPUPI.cjs +255 -0
  8. package/dist/chunk-EYDA6Q6C.js +245 -0
  9. package/dist/{chunk-XAYGD4E4.cjs → chunk-FEDX7B6T.cjs} +3 -3
  10. package/dist/{chunk-JQYC66TO.cjs → chunk-FHWSBGWE.cjs} +5 -5
  11. package/dist/{chunk-5576FRT3.cjs → chunk-FT5H2Q7Y.cjs} +11 -5
  12. package/dist/{chunk-456VDDA3.js → chunk-GADGBQJO.js} +78 -25
  13. package/dist/{chunk-6NAVMWZQ.js → chunk-IGO5XSPS.js} +2 -2
  14. package/dist/{chunk-CTED3MTR.cjs → chunk-IUKKNJ2R.cjs} +82 -29
  15. package/dist/{chunk-FGEB7RMY.cjs → chunk-MM5BV5CS.cjs} +4 -4
  16. package/dist/{chunk-335Z2W67.js → chunk-PYYSB5ZN.js} +1 -1
  17. package/dist/{chunk-PUX5VXDB.cjs → chunk-PZZK3O3S.cjs} +1040 -42
  18. package/dist/{chunk-74QFZ5MK.js → chunk-SPLNGUFF.js} +1 -1
  19. package/dist/{chunk-6PXXGACR.cjs → chunk-UHHMVBLU.cjs} +2 -2
  20. package/dist/{chunk-O5676ZWY.js → chunk-VW356KR3.js} +108 -5
  21. package/dist/{chunk-EAJ7SYHE.js → chunk-WJMEBBU7.js} +1 -1
  22. package/dist/{chunk-GKKDAW44.js → chunk-X7WBPCEU.js} +1026 -32
  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/merkle.d.ts +24 -12
  27. package/dist/fhe-airdrop/advanced/index.cjs +4 -4
  28. package/dist/fhe-airdrop/advanced/index.js +1 -1
  29. package/dist/fhe-airdrop/advanced/react/index.cjs +590 -9
  30. package/dist/fhe-airdrop/advanced/react/index.d.cts +34 -0
  31. package/dist/fhe-airdrop/advanced/react/index.d.ts +34 -0
  32. package/dist/fhe-airdrop/advanced/react/index.js +561 -7
  33. package/dist/fhe-airdrop/advanced/react/useClearCompliancePolicy.d.ts +28 -0
  34. package/dist/fhe-airdrop/advanced/react/useClearUpgradeabilityPolicy.d.ts +26 -0
  35. package/dist/fhe-airdrop/advanced/react/useDisableCustomFee.d.ts +25 -0
  36. package/dist/fhe-airdrop/advanced/react/useEcdsaInitCodeHash.d.ts +30 -0
  37. package/dist/fhe-airdrop/advanced/react/useFactoryComplianceDelegate.d.ts +25 -0
  38. package/dist/fhe-airdrop/advanced/react/useFactoryCompliancePolicy.d.ts +38 -0
  39. package/dist/fhe-airdrop/advanced/react/useFactoryCustomFee.d.ts +24 -0
  40. package/dist/fhe-airdrop/advanced/react/useFactoryGrantRole.d.ts +32 -0
  41. package/dist/fhe-airdrop/advanced/react/useFactoryHasRole.d.ts +27 -0
  42. package/dist/fhe-airdrop/advanced/react/useFactoryImplementations.d.ts +33 -0
  43. package/dist/fhe-airdrop/advanced/react/useFactoryRenounceRole.d.ts +36 -0
  44. package/dist/fhe-airdrop/advanced/react/useFactoryRevokeRole.d.ts +35 -0
  45. package/dist/fhe-airdrop/advanced/react/useFactoryRoleConstants.d.ts +46 -0
  46. package/dist/fhe-airdrop/advanced/react/useFactoryRoleMembers.d.ts +47 -0
  47. package/dist/fhe-airdrop/advanced/react/useFactoryUpgradeabilityPolicy.d.ts +39 -0
  48. package/dist/fhe-airdrop/advanced/react/useMerkleInitCodeHash.d.ts +24 -0
  49. package/dist/fhe-airdrop/advanced/react/useSetComplianceDelegate.d.ts +33 -0
  50. package/dist/fhe-airdrop/advanced/react/useSetComplianceManagerImpl.d.ts +27 -0
  51. package/dist/fhe-airdrop/advanced/react/useSetCompliancePolicy.d.ts +28 -0
  52. package/dist/fhe-airdrop/advanced/react/useSetCustomFee.d.ts +28 -0
  53. package/dist/fhe-airdrop/advanced/react/useSetDefaultDelegateToCompliance.d.ts +31 -0
  54. package/dist/fhe-airdrop/advanced/react/useSetDefaultGasFee.d.ts +28 -0
  55. package/dist/fhe-airdrop/advanced/react/useSetDefaultUpgradeable.d.ts +27 -0
  56. package/dist/fhe-airdrop/advanced/react/useSetEcdsaImplementation.d.ts +34 -0
  57. package/dist/fhe-airdrop/advanced/react/useSetFeeCollector.d.ts +27 -0
  58. package/dist/fhe-airdrop/advanced/react/useSetMerkleImplementation.d.ts +30 -0
  59. package/dist/fhe-airdrop/advanced/react/useSetUpgradeabilityPolicy.d.ts +31 -0
  60. package/dist/fhe-airdrop/airdrop-base.d.ts +8 -0
  61. package/dist/fhe-airdrop/campaign.d.ts +61 -20
  62. package/dist/fhe-airdrop/constants.d.ts +1 -1
  63. package/dist/fhe-airdrop/errors.d.ts +28 -0
  64. package/dist/fhe-airdrop/guards.d.ts +46 -2
  65. package/dist/fhe-airdrop/index.cjs +74 -971
  66. package/dist/fhe-airdrop/index.d.cts +2 -2
  67. package/dist/fhe-airdrop/index.d.ts +2 -2
  68. package/dist/fhe-airdrop/index.js +8 -927
  69. package/dist/fhe-airdrop/merkle-tree.d.ts +32 -38
  70. package/dist/fhe-airdrop/merkle.d.ts +52 -31
  71. package/dist/fhe-airdrop/react/_shared.d.ts +13 -0
  72. package/dist/fhe-airdrop/react/index.cjs +934 -84
  73. package/dist/fhe-airdrop/react/index.d.cts +49 -3
  74. package/dist/fhe-airdrop/react/index.d.ts +49 -3
  75. package/dist/fhe-airdrop/react/index.js +825 -22
  76. package/dist/fhe-airdrop/react/keys.d.ts +90 -0
  77. package/dist/fhe-airdrop/react/useAccessEcdsaClaimAmount.d.ts +26 -0
  78. package/dist/fhe-airdrop/react/useAccessMerkleClaimAmount.d.ts +27 -0
  79. package/dist/fhe-airdrop/react/useAddComplianceDelegate.d.ts +37 -0
  80. package/dist/fhe-airdrop/react/useAdminBatchDiscloseBalanceToParties.d.ts +36 -0
  81. package/dist/fhe-airdrop/react/useAdminDiscloseBalanceToParty.d.ts +31 -0
  82. package/dist/fhe-airdrop/react/useAdminGetCurrentBalance.d.ts +27 -0
  83. package/dist/fhe-airdrop/react/useAirdropConfig.d.ts +49 -0
  84. package/dist/fhe-airdrop/react/useAirdropDeploymentMode.d.ts +28 -0
  85. package/dist/fhe-airdrop/react/useAirdropGrantRole.d.ts +35 -0
  86. package/dist/fhe-airdrop/react/useAirdropRenounceRole.d.ts +36 -0
  87. package/dist/fhe-airdrop/react/useAirdropRevokeRole.d.ts +33 -0
  88. package/dist/fhe-airdrop/react/useAirdropRoleAdmin.d.ts +28 -0
  89. package/dist/fhe-airdrop/react/useAirdropRoleConstants.d.ts +67 -0
  90. package/dist/fhe-airdrop/react/useAirdropRoleMembers.d.ts +49 -0
  91. package/dist/fhe-airdrop/react/useAirdropUpgradeToAndCall.d.ts +45 -0
  92. package/dist/fhe-airdrop/react/useBatchDiscloseHandlesToParty.d.ts +32 -0
  93. package/dist/fhe-airdrop/react/useBuildMerkleCampaign.d.ts +68 -0
  94. package/dist/fhe-airdrop/react/useComplianceGrantRole.d.ts +32 -0
  95. package/dist/fhe-airdrop/react/useComplianceHasRole.d.ts +37 -0
  96. package/dist/fhe-airdrop/react/useComplianceInfo.d.ts +50 -0
  97. package/dist/fhe-airdrop/react/useComplianceManagerOf.d.ts +32 -0
  98. package/dist/fhe-airdrop/react/useComplianceRenounceRole.d.ts +38 -0
  99. package/dist/fhe-airdrop/react/useComplianceRevokeRole.d.ts +36 -0
  100. package/dist/fhe-airdrop/react/useComplianceRoleConstants.d.ts +41 -0
  101. package/dist/fhe-airdrop/react/useComplianceRoleMembers.d.ts +45 -0
  102. package/dist/fhe-airdrop/react/useCreateAndFundEcdsaAirdrop.d.ts +55 -0
  103. package/dist/fhe-airdrop/react/useCreateAndFundMerkleAirdrop.d.ts +52 -0
  104. package/dist/fhe-airdrop/react/useDiscloseHandleToParty.d.ts +35 -0
  105. package/dist/fhe-airdrop/react/useEcdsaClaim.d.ts +4 -3
  106. package/dist/fhe-airdrop/react/useEcdsaClaimAndUnwrap.d.ts +27 -0
  107. package/dist/fhe-airdrop/react/useEcdsaDomain.d.ts +41 -0
  108. package/dist/fhe-airdrop/react/useEffectiveDelegateToCompliance.d.ts +26 -0
  109. package/dist/fhe-airdrop/react/useEncryptCampaignAmounts.d.ts +59 -0
  110. package/dist/fhe-airdrop/react/useIsActiveDelegate.d.ts +29 -0
  111. package/dist/fhe-airdrop/react/useIsMerkleRootMutable.d.ts +21 -0
  112. package/dist/fhe-airdrop/react/useIsSignatureValid.d.ts +46 -0
  113. package/dist/fhe-airdrop/react/useMerkleClaim.d.ts +7 -19
  114. package/dist/fhe-airdrop/react/useMerkleClaimAndUnwrap.d.ts +29 -0
  115. package/dist/fhe-airdrop/react/usePlanMerkleCampaign.d.ts +53 -0
  116. package/dist/fhe-airdrop/react/usePreflightClaim.d.ts +46 -0
  117. package/dist/fhe-airdrop/react/usePreflightCreateAirdrop.d.ts +67 -0
  118. package/dist/fhe-airdrop/react/useRescueERC20.d.ts +30 -0
  119. package/dist/fhe-airdrop/react/useRescueOtherConfidentialToken.d.ts +34 -0
  120. package/dist/fhe-airdrop/react/useRevokeComplianceDelegate.d.ts +37 -0
  121. package/dist/fhe-airdrop/react/useRotateMerkleRoot.d.ts +52 -0
  122. package/dist/fhe-airdrop/react/useSignClaimAuthorization.d.ts +42 -0
  123. package/dist/fhe-airdrop/react/useWithdrawGasFee.d.ts +37 -0
  124. package/dist/fhe-airdrop/types.d.ts +14 -1
  125. package/dist/fhe-disperse/index.cjs +21 -21
  126. package/dist/fhe-disperse/index.js +2 -2
  127. package/dist/fhe-disperse/react/index.cjs +22 -22
  128. package/dist/fhe-disperse/react/index.js +3 -3
  129. package/dist/fhe-vesting/advanced/index.cjs +5 -5
  130. package/dist/fhe-vesting/advanced/index.js +3 -3
  131. package/dist/fhe-vesting/advanced/react/index.cjs +7 -7
  132. package/dist/fhe-vesting/advanced/react/index.js +4 -4
  133. package/dist/fhe-vesting/index.cjs +8 -8
  134. package/dist/fhe-vesting/index.js +2 -2
  135. package/dist/fhe-vesting/react/index.cjs +114 -114
  136. package/dist/fhe-vesting/react/index.js +3 -3
  137. package/dist/index.cjs +18 -18
  138. package/dist/index.js +1 -1
  139. package/dist/testnet-faucet/index.cjs +14 -14
  140. package/dist/testnet-faucet/index.js +2 -2
  141. package/dist/testnet-faucet/react/index.cjs +8 -8
  142. package/dist/testnet-faucet/react/index.js +3 -3
  143. package/package.json +1 -1
  144. package/dist/chunk-NCVX3K2N.cjs +0 -161
  145. package/dist/chunk-VP2B4WM2.js +0 -154
@@ -0,0 +1,41 @@
1
+ import { type UseQueryResult } from "@tanstack/react-query";
2
+ import type { Hex } from "viem";
3
+ import type { Eip712Domain } from "../ecdsa.js";
4
+ import { type EcdsaAirdropInstanceHookOptions } from "./_shared.js";
5
+ /**
6
+ * One `ECDSAConfidentialAirdrop` instance's live EIP-712 identity, read
7
+ * straight off the deployment.
8
+ *
9
+ * @alpha
10
+ */
11
+ export interface EcdsaDomain {
12
+ /** The on-chain `CLAIM_TYPEHASH`. Compare against the module `CLAIM_TYPEHASH` constant. */
13
+ claimTypehash: Hex;
14
+ /** `_domainSeparatorV4()`, bound to `(chainId, address(this))`. */
15
+ domainSeparator: Hex;
16
+ /** The ERC-5267 domain, field by field - what {@link EcdsaDomain.domainSeparator} hashes. */
17
+ domain: Eip712Domain;
18
+ }
19
+ /** @alpha */
20
+ export type UseEcdsaDomainArgs = EcdsaAirdropInstanceHookOptions<EcdsaDomain>;
21
+ /**
22
+ * Read an ECDSA instance's `CLAIM_TYPEHASH`, domain separator and ERC-5267
23
+ * domain in one round trip - the three deployment-verification reads nobody
24
+ * wants one at a time (same call as {@link useAirdropWindow}).
25
+ *
26
+ * **This is the round-trip confirmation, not the common path.** For building
27
+ * a signature, use the module-level `CLAIM_TYPEHASH` / `EIP712_DOMAIN_NAME` /
28
+ * `EIP712_DOMAIN_VERSION` constants and skip the RPC. Use this hook to
29
+ * confirm a deployed instance really was initialized with the domain you
30
+ * expect, on the chain you think it is on, before a signing service starts
31
+ * issuing signatures against it.
32
+ *
33
+ * All three are bytecode/deploy constants, so `staleTime: Infinity`.
34
+ *
35
+ * @example
36
+ * const { data } = useEcdsaDomain({ address: airdropAddress, dedupMode: "perAddress" });
37
+ * const built = data?.claimTypehash === CLAIM_TYPEHASH;
38
+ *
39
+ * @alpha
40
+ */
41
+ export declare function useEcdsaDomain(args: UseEcdsaDomainArgs): UseQueryResult<EcdsaDomain, Error>;
@@ -0,0 +1,26 @@
1
+ import { type UseQueryResult } from "@tanstack/react-query";
2
+ import type { Address } from "viem";
3
+ import { type AirdropHookOptions } from "./_shared.js";
4
+ /** @alpha */
5
+ export interface UseEffectiveDelegateToComplianceArgs extends AirdropHookOptions<boolean> {
6
+ /** The creator whose effective delegate-to-compliance policy to read. */
7
+ creator?: Address;
8
+ }
9
+ /**
10
+ * Whether `creator`'s NEXT `create*` will wire the platform compliance
11
+ * delegate into the instance's compliance-manager clone - their
12
+ * `setCompliancePolicy` override when they have one, else the factory
13
+ * default. Read it to tell a creator up front that a platform delegate will
14
+ * hold delegated rights on the campaign they are about to deploy.
15
+ *
16
+ * The creator-facing mirror of {@link useEffectiveUpgradeable}: same args
17
+ * shape, same gating, same subpath - even though the setters that move it
18
+ * (`setCompliancePolicy` / `clearCompliancePolicy` /
19
+ * `setDefaultDelegateToCompliance`) are factory-admin surface.
20
+ *
21
+ * @example
22
+ * const { data: willDelegate } = useEffectiveDelegateToCompliance({ creator: deployerAddress });
23
+ *
24
+ * @alpha
25
+ */
26
+ export declare function useEffectiveDelegateToCompliance(args?: UseEffectiveDelegateToComplianceArgs): UseQueryResult<boolean, Error>;
@@ -0,0 +1,59 @@
1
+ import { type UseMutationResult } from "@tanstack/react-query";
2
+ import type { Address } from "viem";
3
+ import { type CampaignSubmitterOption, type EncryptedCampaignLeaf } from "../campaign.js";
4
+ import { type EncryptorSource } from "../encryption.js";
5
+ import type { CampaignRecipient } from "../types.js";
6
+ /**
7
+ * Hook-level config for {@link useEncryptCampaignAmounts}. No chain client is
8
+ * involved — encryption is relayer work — so only the encryptor is needed.
9
+ *
10
+ * @alpha
11
+ */
12
+ export interface UseEncryptCampaignAmountsOptions {
13
+ /**
14
+ * Eager or lazy encryptor. Wire it lazily so the live React context is read
15
+ * at submit time rather than captured at mount (CLAUDE.md Pitfall #3):
16
+ * `const sdk = useZamaSDK()` once, then `encryptor: () => sdk.relayer`.
17
+ */
18
+ encryptor?: EncryptorSource;
19
+ }
20
+ /**
21
+ * Variables for {@link useEncryptCampaignAmounts}.
22
+ *
23
+ * @alpha
24
+ */
25
+ export interface UseEncryptCampaignAmountsArgs extends CampaignSubmitterOption {
26
+ /** The LIVE `MerkleConfidentialAirdrop` instance every input is bound to. Not the factory, not the implementation. */
27
+ instance: Address;
28
+ /** CUMULATIVE totals per account, never per-drop tranches. */
29
+ recipients: readonly CampaignRecipient[];
30
+ }
31
+ /**
32
+ * Encrypt a plaintext roster into per-recipient handles, without building a
33
+ * tree. Use it to persist the ciphertexts before committing to a root; if you
34
+ * just want a campaign, {@link useBuildMerkleCampaign} does both stages.
35
+ *
36
+ * A mutation rather than a query on purpose: encryption is randomised, so the
37
+ * same roster yields different handles every call and there is no legitimate
38
+ * cache identity to key. **Persist what resolves** — nothing here is
39
+ * recoverable or reproducible.
40
+ *
41
+ * `submitter` decides the shape and the relayer cost. Omitted: one request per
42
+ * recipient, issued concurrently, each input bound to that recipient, so only
43
+ * they can claim — chunk the roster yourself if your relayer rate-limits. Set:
44
+ * a single batched request bound to that one address, one shared `inputProof`
45
+ * for the whole roster, and only that address can submit.
46
+ *
47
+ * **Invalidates:** nothing. Pure off-chain relayer work — no contract state
48
+ * moves, so no cached read goes stale.
49
+ *
50
+ * @throws {@link InvalidArgumentError} on a duplicate, zero-address or out-of-`uint64`-range roster entry, or a zero `instance`.
51
+ * @throws {@link MissingEncryptorError} when `encryptor` resolves to `undefined`.
52
+ *
53
+ * @example
54
+ * const encrypt = useEncryptCampaignAmounts({ encryptor: () => sdk.relayer });
55
+ * const leaves = await encrypt.mutateAsync({ instance: airdrop, recipients });
56
+ *
57
+ * @alpha
58
+ */
59
+ export declare function useEncryptCampaignAmounts(options?: UseEncryptCampaignAmountsOptions): UseMutationResult<readonly EncryptedCampaignLeaf[], Error, UseEncryptCampaignAmountsArgs>;
@@ -0,0 +1,29 @@
1
+ import { type UseQueryResult } from "@tanstack/react-query";
2
+ import type { Address } from "viem";
3
+ import { type AirdropInstanceHookOptions } from "./_shared.js";
4
+ /** @alpha */
5
+ export interface UseIsActiveDelegateArgs extends AirdropInstanceHookOptions<boolean> {
6
+ /** The address to check. Stays disabled until it is defined. */
7
+ delegate?: Address;
8
+ }
9
+ /**
10
+ * Whether `delegate` currently holds user-decryption delegation over this
11
+ * compliance-manager clone's airdrop. `address` is the CLONE.
12
+ *
13
+ * Authoritative: it reads the ACL expiration directly rather than the
14
+ * contract's `EnumerableSet` mirror, so unlike
15
+ * {@link useComplianceInfo}'s `clientDelegates` it also answers `true` for
16
+ * the irrevocable platform compliance delegate.
17
+ *
18
+ * **On-chain truth only.** A `true` here does not mean the Zama gateway will
19
+ * serve a delegated decrypt yet - it observes ACL changes out of band, with a
20
+ * lag the SDK's own guidance puts at 1-2 minutes. A UI that renders
21
+ * "delegated" off this value must still treat `isAclPropagationError` as a
22
+ * retry-with-backoff signal rather than a failure.
23
+ *
24
+ * @example
25
+ * const { data: canDecrypt } = useIsActiveDelegate({ address: managerAddress, delegate: officer });
26
+ *
27
+ * @alpha
28
+ */
29
+ export declare function useIsActiveDelegate(args: UseIsActiveDelegateArgs): UseQueryResult<boolean, Error>;
@@ -0,0 +1,21 @@
1
+ import { type UseQueryResult } from "@tanstack/react-query";
2
+ import { type AirdropInstanceHookOptions } from "./_shared.js";
3
+ /** @alpha */
4
+ export type UseIsMerkleRootMutableArgs = AirdropInstanceHookOptions<boolean>;
5
+ /**
6
+ * Whether this `MerkleConfidentialAirdrop` instance permits root rotation at
7
+ * all. This is the read that decides whether a UI offers `useSetMerkleRoot` -
8
+ * on a `false` instance the rotation reverts with `FeatureDisabledError`
9
+ * (`feature: "merkleRootRotation"`) rather than failing a role check.
10
+ *
11
+ * **Fixed at create time, never toggled** - hence `staleTime: Infinity` and
12
+ * hence deliberately NOT bundled with {@link useMerkleRoot}, which rotates.
13
+ * Bundling would refetch an immutable value on every rotation and would force
14
+ * `useSetMerkleRoot`'s single-key invalidation to become coarser.
15
+ *
16
+ * @example
17
+ * const { data: canRotate } = useIsMerkleRootMutable({ address: merkleAirdropAddress });
18
+ *
19
+ * @alpha
20
+ */
21
+ export declare function useIsMerkleRootMutable(args: UseIsMerkleRootMutableArgs): UseQueryResult<boolean, Error>;
@@ -0,0 +1,46 @@
1
+ import { type UseQueryResult } from "@tanstack/react-query";
2
+ import type { Address, Hex } from "viem";
3
+ import { type EcdsaAirdropInstanceHookOptions } from "./_shared.js";
4
+ /** @alpha */
5
+ export interface UseIsSignatureValidArgs extends EcdsaAirdropInstanceHookOptions<boolean> {
6
+ /** The address the signature was made out to. The digest binds `msg.sender`, so the read is simulated FROM this address. */
7
+ recipient?: Address;
8
+ /** The external encrypted allocation handle. No input proof: a view never calls `FHE.fromExternal`. */
9
+ encryptedAmountHandle?: Hex;
10
+ /** The off-chain claim id bound into the signature. */
11
+ dedupId?: Hex;
12
+ /** Unix seconds the signature expires at. */
13
+ deadline?: bigint;
14
+ /** The `SIGNER_ROLE` holder that authorized the claim. */
15
+ signer?: Address;
16
+ /** The EIP-712 signature from `signClaimAuthorization`. */
17
+ signature?: Hex;
18
+ }
19
+ /**
20
+ * Whether an ECDSA claim authorization would be accepted right now for `recipient`,
21
+ * without spending an FHE op or a transaction.
22
+ *
23
+ * Never reverts - `false` covers every failure mode (paused, outside the claim window,
24
+ * past `deadline`, `signer` lacking `SIGNER_ROLE`, an invalid signature, a consumed
25
+ * digest, or an already-deduped claim). `recipient` is load-bearing and part of the
26
+ * cache key: the read is an `eth_call` FROM that address, so passing the wrong one
27
+ * returns `false` for a signature that would otherwise succeed.
28
+ *
29
+ * Stays disabled until all six signature fields are defined, so a UI can call it
30
+ * unconditionally while a form fills in.
31
+ *
32
+ * @remarks
33
+ * A successful {@link useEcdsaClaim} / {@link useEcdsaClaimAndUnwrap} flips this to
34
+ * `false` by consuming the digest, but neither claim hook invalidates it - refetch it
35
+ * yourself after a claim rather than trusting a cached `true`.
36
+ *
37
+ * @example
38
+ * const { data: claimable } = useIsSignatureValid({
39
+ * address: airdropAddress,
40
+ * dedupMode: "perAddress",
41
+ * recipient, encryptedAmountHandle, dedupId, deadline, signer, signature,
42
+ * });
43
+ *
44
+ * @alpha
45
+ */
46
+ export declare function useIsSignatureValid(args: UseIsSignatureValidArgs): UseQueryResult<boolean, Error>;
@@ -6,28 +6,16 @@ import { type AirdropInstanceClientOptions } from "./_shared.js";
6
6
  * Claim the outstanding amount for a proof-bearing entry on a
7
7
  * `MerkleConfidentialAirdrop` instance.
8
8
  *
9
- * **Invalidates:** the claiming account's `useClaimedAmount` entry for this
10
- * instance — the read whose cumulative-delivered value a successful claim
11
- * changes. The claiming account is `args.account` if given, else the
12
- * connected wallet's own account; other accounts' cached reads, and every
13
- * other instance's cache, are left untouched (a `useMerkleClaim` on one
14
- * campaign must not invalidate another campaign's `useClaimedAmount`).
15
- *
16
- * The claimant is resolved once in `onMutate` — synchronously, before the
17
- * (async) write runs — and threaded into `onSuccess` via TanStack's mutation
18
- * `context`, rather than re-read from `useWalletClient()` after the write
19
- * settles. A mutation can outlive several re-renders of its own component
20
- * (its `isPending` transition alone triggers one), and `useWalletClient()`'s
21
- * data can read back transiently empty across those re-renders even though
22
- * the write itself already resolved and used a real account — re-reading it
23
- * in `onSuccess` risks silently skipping the invalidation this TSDoc
24
- * promises. `onMutate` runs in the same tick `mutate()`/`mutateAsync()` was
25
- * called, so it observes the exact same `walletClient` value the write is
26
- * about to use.
9
+ * **Invalidates:** `useClaimedAmount` for `entry.account` on this instance — the read
10
+ * whose cumulative-delivered value a successful claim changes. The contract advances
11
+ * `claimedAmount[account]`, keyed on the entry's claim identity and NOT on whoever sent
12
+ * the transaction, so a relayed claim must invalidate the recipient's cache entry rather
13
+ * than the relayer's. Other accounts' cached reads, and every other instance's cache,
14
+ * are left untouched.
27
15
  *
28
16
  * @example
29
17
  * const claim = useMerkleClaim({ address: airdropAddress });
30
- * await claim.mutateAsync({ entry });
18
+ * await claim.mutateAsync({ entry }); // relayers pass a relayed entry unchanged
31
19
  *
32
20
  * @alpha
33
21
  */
@@ -0,0 +1,29 @@
1
+ import { type UseMutationResult } from "@tanstack/react-query";
2
+ import type { Hex } from "viem";
3
+ import type { MerkleClaimArgs } from "../merkle.js";
4
+ import { type AirdropInstanceClientOptions } from "./_shared.js";
5
+ /**
6
+ * Claim a proof-bearing Merkle entry and route the allocation straight into the
7
+ * wrapper's unwrap, making `to` the underlying ERC-20 beneficiary.
8
+ *
9
+ * **Self-only, unlike {@link useMerkleClaim}.** This entrypoint takes no claim identity:
10
+ * the leaf, the accounting and the input proof are all `msg.sender`, so an entry whose
11
+ * `account` is not the submitter is refused before the write. Gate the button on
12
+ * `submitter === entry.account` and fall back to `useMerkleClaim` for relayed claims.
13
+ * Also requires an unwrappable campaign - see `useAirdropConfig().unwrappable`.
14
+ *
15
+ * **Invalidates:** `useClaimedAmount` for the SENDING account on this instance. The
16
+ * contract advances `claimedAmount[msg.sender]` here, so the key is built from the
17
+ * sender resolved in `onMutate` (`variables.account ?? walletClient.account`) and NOT
18
+ * from `entry.account` the way {@link useMerkleClaim} does it. The two identities are
19
+ * equal on this path by construction - the client refuses a mismatch - but the
20
+ * divergence is deliberate: `claim` records the explicit claim identity, this records
21
+ * the caller. Do not unify them.
22
+ *
23
+ * @example
24
+ * const unwrapClaim = useMerkleClaimAndUnwrap({ address: airdropAddress });
25
+ * await unwrapClaim.mutateAsync({ entry, to: erc20Beneficiary });
26
+ *
27
+ * @alpha
28
+ */
29
+ export declare function useMerkleClaimAndUnwrap(options: AirdropInstanceClientOptions): UseMutationResult<Hex, Error, MerkleClaimArgs>;
@@ -0,0 +1,53 @@
1
+ import { type UseMutationResult } from "@tanstack/react-query";
2
+ import { type PlanMerkleCampaignArgs, type PlannedCampaign } from "../campaign.js";
3
+ import { type AirdropClientOptions } from "./_shared.js";
4
+ /**
5
+ * Variables for {@link usePlanMerkleCampaign} — the create arguments the campaign
6
+ * is planned against. The factory client and the encryptor come from the hook
7
+ * options instead.
8
+ *
9
+ * @alpha
10
+ */
11
+ export type UsePlanMerkleCampaignArgs = Omit<PlanMerkleCampaignArgs, "factory" | "encryptor">;
12
+ /**
13
+ * Build a campaign for a Merkle instance that does not exist yet, so its root
14
+ * can be baked in at create time — the **immutable-root** path.
15
+ *
16
+ * That path is otherwise circular: the root must be known before
17
+ * `createMerkleAirdrop`, the root depends on every ciphertext, and every
18
+ * ciphertext binds to an instance address the create has not produced. This
19
+ * hook breaks it with the factory's CREATE2 prediction oracle, then feeds
20
+ * `root` to {@link useCreateMerkleAirdrop} (or
21
+ * {@link useCreateAndFundMerkleAirdrop}) with the SAME `mode`, `creator` and
22
+ * `userSalt`. `initCodeHashAfter` is what `preflightCreateAirdrop`'s
23
+ * `expectedInitCodeHash` wants.
24
+ *
25
+ * **Surface {@link PredictionDriftError}, never swallow it.** It means the
26
+ * factory's Merkle implementation pointer moved mid-build, so every entry is
27
+ * bound to an address the create will not produce. There is no on-chain repair
28
+ * on an immutable-root instance — the only remedy is a fresh plan.
29
+ *
30
+ * **The returned `entries` ARE the campaign — persist them.** The chain keeps
31
+ * only the root, so a recipient without their own
32
+ * `(handle, inputProof, merkleProof)` triple can never claim. Also pick a
33
+ * fresh `userSalt` per campaign: two campaigns sharing
34
+ * `(variant, mode, creator, userSalt)` predict the same address however
35
+ * different their params.
36
+ *
37
+ * **Invalidates:** nothing. Two init-code-hash reads and a prediction — no
38
+ * state moves until the create lands.
39
+ *
40
+ * @throws {@link DeploymentAddressUnavailableError} when no factory is deployed for the connected chain.
41
+ * @throws {@link PredictionDriftError} when the factory's Merkle implementation pointer moved mid-build.
42
+ * @throws {@link InvalidArgumentError} on a duplicate, zero-address or out-of-`uint64`-range roster entry.
43
+ * @throws {@link MissingEncryptorError} when `encryptor` resolves to `undefined`.
44
+ *
45
+ * @example
46
+ * const plan = usePlanMerkleCampaign({ encryptor: () => sdk.relayer });
47
+ * const { root, entries, predictedAddress } = await plan.mutateAsync({
48
+ * params, mode: "clone", creator, userSalt, recipients,
49
+ * });
50
+ *
51
+ * @alpha
52
+ */
53
+ export declare function usePlanMerkleCampaign(options?: AirdropClientOptions): UseMutationResult<PlannedCampaign, Error, UsePlanMerkleCampaignArgs>;
@@ -0,0 +1,46 @@
1
+ import { type UseQueryResult } from "@tanstack/react-query";
2
+ import type { Address } from "viem";
3
+ import type { PreflightResult } from "../../core/preflight.js";
4
+ import type { DedupMode } from "../constants.js";
5
+ import type { AirdropVariant } from "../errors.js";
6
+ import { type EcdsaClaimPreflightSignature } from "../guards.js";
7
+ import { type AirdropInstanceHookOptions } from "./_shared.js";
8
+ /** @alpha */
9
+ export interface UsePreflightClaimArgs extends AirdropInstanceHookOptions<PreflightResult> {
10
+ /** Which variant this instance is - picks the client the preflight reads through. */
11
+ variant: AirdropVariant;
12
+ /** ECDSA campaigns only; ignored on `variant: "merkle"`. Defaults to `"none"`. */
13
+ dedupMode?: DedupMode;
14
+ /** The account that will SEND the claim and therefore pays the exact-equality gas fee. On a relayed Merkle claim this is the relayer. */
15
+ claimant?: Address;
16
+ /** Merkle campaigns only: the claim identity, when it is not the submitter. Defaults to `claimant`. */
17
+ account?: Address;
18
+ /** The payout destination, if one will be passed. */
19
+ to?: Address;
20
+ /** Set for `claimAndUnwrap`, which is always submitted for the caller. */
21
+ entrypoint?: "claim" | "claimAndUnwrap";
22
+ /** ECDSA campaigns only: adds the authorisation check to the report. */
23
+ signature?: EcdsaClaimPreflightSignature;
24
+ }
25
+ /**
26
+ * Report what would stop a claim right now - chain support, the pause flag, both ends of
27
+ * the claim window, whether `claimant` can cover the exact-equality gas fee, the Merkle
28
+ * argument-relation rules when `account`/`entrypoint` are given, and for an ECDSA
29
+ * campaign given `signature`, whether the authorisation is valid and unconsumed.
30
+ *
31
+ * **`ready: true` does not mean the claimant has anything to claim.** The allocation is
32
+ * encrypted, so an SDK-side "nothing to claim" would require decrypting it; this checks
33
+ * only what is decidable without the ciphertext. Use it to disable a button, not to
34
+ * promise a payout.
35
+ *
36
+ * Every field below `variant` feeds the blockers and is therefore part of the cache key.
37
+ * The fee check reads `claimant`'s live ETH balance, so keep `staleTime` short - the
38
+ * default 0 is right for a claim button.
39
+ *
40
+ * @example
41
+ * const { data } = usePreflightClaim({ address: airdropAddress, variant: "merkle", claimant });
42
+ * <button disabled={!data?.ready}>Claim</button>
43
+ *
44
+ * @alpha
45
+ */
46
+ export declare function usePreflightClaim(args: UsePreflightClaimArgs): UseQueryResult<PreflightResult, Error>;
@@ -0,0 +1,67 @@
1
+ import { type UseQueryResult } from "@tanstack/react-query";
2
+ import type { Address, Hex } from "viem";
3
+ import type { PreflightResult } from "../../core/preflight.js";
4
+ import type { DeploymentMode } from "../constants.js";
5
+ import type { EcdsaAirdropParams, MerkleAirdropParams } from "../types.js";
6
+ import { type AirdropHookOptions } from "./_shared.js";
7
+ /** The variant-independent half of {@link UsePreflightCreateAirdropArgs}. */
8
+ /** @alpha */
9
+ export interface PreflightCreateAirdropCommon extends AirdropHookOptions<PreflightResult> {
10
+ mode?: DeploymentMode;
11
+ /** The account that will send `create*`. CREATE2 salts are per-deployer. */
12
+ creator?: Address;
13
+ userSalt?: Hex;
14
+ /**
15
+ * Pass `plan.initCodeHashAfter` to turn the implementation-drift check on.
16
+ * Omitting it skips that one check.
17
+ */
18
+ expectedInitCodeHash?: Hex;
19
+ }
20
+ /**
21
+ * `variant` and `params` are correlated, mirroring the headless
22
+ * `PreflightCreateArgs` discriminated union rather than widening to a
23
+ * cross-product (CLAUDE.md Pitfall #2). The all-undefined member is what lets
24
+ * a component call the hook unconditionally while a create form fills in.
25
+ *
26
+ * @alpha
27
+ */
28
+ export type UsePreflightCreateAirdropArgs = PreflightCreateAirdropCommon & ({
29
+ variant?: undefined;
30
+ params?: undefined;
31
+ } | {
32
+ variant: "ecdsa";
33
+ params?: EcdsaAirdropParams;
34
+ } | {
35
+ variant: "merkle";
36
+ params?: MerkleAirdropParams;
37
+ });
38
+ /**
39
+ * Read-only preflight for `useCreateEcdsaAirdrop` / `useCreateMerkleAirdrop`.
40
+ * Runs every create-time guardrail the write path enforces - chain support,
41
+ * the Merkle/UUPS refusal, the creator's effective upgradeability policy for
42
+ * `mode: "uups"`, the stock-wrapper probe when `params.common.unwrappable` is
43
+ * set, a salt collision on the predicted address, and implementation drift
44
+ * when `expectedInitCodeHash` is supplied.
45
+ *
46
+ * **The point is disabling the submit button, not catching after the fact.**
47
+ * `blockers` carries the same typed errors `create*` would have thrown, so a
48
+ * UI branches on `error.code` here exactly as it does in `onError`.
49
+ *
50
+ * Disabled until `variant`, `params`, `mode`, `creator` and `userSalt` are all
51
+ * set. Refetch after the user changes their target mode or the factory's
52
+ * implementation pointer moves.
53
+ *
54
+ * @remarks
55
+ * Named `…Airdrop` rather than `…Create` so a consumer importing both this and
56
+ * `/fhe-vesting/react`'s `usePreflightCreateVesting` has no collision.
57
+ *
58
+ * @example
59
+ * const { data: report } = usePreflightCreateAirdrop({
60
+ * variant: "merkle", params, mode: "clone", creator, userSalt,
61
+ * expectedInitCodeHash: plan.initCodeHashAfter,
62
+ * });
63
+ * const canSubmit = report?.ready === true;
64
+ *
65
+ * @alpha
66
+ */
67
+ export declare function usePreflightCreateAirdrop(args?: UsePreflightCreateAirdropArgs): UseQueryResult<PreflightResult, Error>;
@@ -0,0 +1,30 @@
1
+ import { type UseMutationResult } from "@tanstack/react-query";
2
+ import type { Address, Hex } from "viem";
3
+ import type { WriteAccountOverride } from "../airdrop-base.js";
4
+ import { type AirdropInstanceClientOptions } from "./_shared.js";
5
+ /** @alpha */
6
+ export interface RescueERC20Args extends WriteAccountOverride {
7
+ /** The stranded plain ERC-20. Never the campaign's own token, which is ERC-7984. */
8
+ token: Address;
9
+ /** Where the swept balance goes. */
10
+ recipient: Address;
11
+ }
12
+ /**
13
+ * Sweep a plain ERC-20 that was sent to an airdrop instance by mistake.
14
+ * Requires `RESCUER_ROLE`.
15
+ *
16
+ * The campaign's own token is ERC-7984, not ERC-20, so the distribution pool
17
+ * cannot be reached through this path at all — use
18
+ * {@link useWithdrawConfidential} (`TREASURY_ROLE`) for the pool, and
19
+ * {@link useRescueOtherConfidentialToken} for a stranded ERC-7984.
20
+ *
21
+ * **Invalidates:** nothing. This subpath has no read hook over arbitrary
22
+ * ERC-20 balances held by the instance.
23
+ *
24
+ * @example
25
+ * const rescue = useRescueERC20({ address: airdropAddress });
26
+ * await rescue.mutateAsync({ token: strandedErc20, recipient: treasuryAddress });
27
+ *
28
+ * @alpha
29
+ */
30
+ export declare function useRescueERC20(options: AirdropInstanceClientOptions): UseMutationResult<Hex, Error, RescueERC20Args>;
@@ -0,0 +1,34 @@
1
+ import { type UseMutationResult } from "@tanstack/react-query";
2
+ import type { Address, Hex } from "viem";
3
+ import type { WriteAccountOverride } from "../airdrop-base.js";
4
+ import { type AirdropInstanceClientOptions } from "./_shared.js";
5
+ /** @alpha */
6
+ export interface RescueOtherConfidentialTokenArgs extends WriteAccountOverride {
7
+ /**
8
+ * The stranded ERC-7984. Passing the campaign's own token reverts
9
+ * `CannotRescueAirdropToken`.
10
+ */
11
+ token: Address;
12
+ /** Where the swept balance goes. */
13
+ recipient: Address;
14
+ }
15
+ /**
16
+ * Sweep a *different* ERC-7984 token that was sent to an airdrop instance by
17
+ * mistake. Requires `RESCUER_ROLE`.
18
+ *
19
+ * Passing the campaign's own token reverts `CannotRescueAirdropToken` — the
20
+ * guard that stops a rescuer draining the distribution pool without
21
+ * `TREASURY_ROLE`. Compare `token` against `useAirdropConfig().data?.token`
22
+ * before submitting so the user is told before paying gas, and route pool
23
+ * sweeps through {@link useWithdrawConfidential} instead.
24
+ *
25
+ * **Invalidates:** nothing. This subpath has no read hook over third-party
26
+ * confidential balances held by the instance.
27
+ *
28
+ * @example
29
+ * const rescue = useRescueOtherConfidentialToken({ address: airdropAddress });
30
+ * await rescue.mutateAsync({ token: strandedErc7984, recipient: treasuryAddress });
31
+ *
32
+ * @alpha
33
+ */
34
+ export declare function useRescueOtherConfidentialToken(options: AirdropInstanceClientOptions): UseMutationResult<Hex, Error, RescueOtherConfidentialTokenArgs>;
@@ -0,0 +1,37 @@
1
+ import { type UseMutationResult } from "@tanstack/react-query";
2
+ import type { Address, Hex } from "viem";
3
+ import type { WriteAccountOverride } from "../airdrop-base.js";
4
+ import { type AirdropInstanceClientOptions } from "./_shared.js";
5
+ /** @alpha */
6
+ export interface RevokeComplianceDelegateArgs extends WriteAccountOverride {
7
+ /** The client delegate to revoke. Must currently be active, and must not be the platform delegate. */
8
+ delegate: Address;
9
+ }
10
+ /**
11
+ * Revoke a client delegate's user-decryption delegation. `options.address` is
12
+ * the CLONE. Requires `DELEGATION_ADMIN_ROLE` on it.
13
+ *
14
+ * **Cannot revoke the platform compliance delegate** - that slot is
15
+ * irrevocable by construction, and targeting it reverts. Only the addresses in
16
+ * {@link useComplianceInfo}'s `clientDelegates` are revocable.
17
+ *
18
+ * The same gateway lag applies on the way out: the revocation is effective
19
+ * on-chain immediately, but a revoked delegate may still complete a delegated
20
+ * decrypt for a short window afterwards.
21
+ *
22
+ * **Invalidates:** this clone's {@link useComplianceInfo} entry and its
23
+ * {@link useIsActiveDelegate} entry for exactly `delegate`, both keyed on the
24
+ * clone address.
25
+ *
26
+ * @remarks
27
+ * Not in the same block as {@link useAddComplianceDelegate} for the same
28
+ * delegate - the FHEVM ACL refuses both writes at one height with an opaque
29
+ * revert.
30
+ *
31
+ * @example
32
+ * const revoke = useRevokeComplianceDelegate({ address: managerAddress });
33
+ * await revoke.mutateAsync({ delegate: formerOfficer });
34
+ *
35
+ * @alpha
36
+ */
37
+ export declare function useRevokeComplianceDelegate(options: AirdropInstanceClientOptions): UseMutationResult<Hex, Error, RevokeComplianceDelegateArgs>;
@@ -0,0 +1,52 @@
1
+ import { type UseMutationResult } from "@tanstack/react-query";
2
+ import type { WriteAccountOverride } from "../airdrop-base.js";
3
+ import { type CampaignSubmitterOption, type RotatedCampaign } from "../campaign.js";
4
+ import type { CampaignRecipient } from "../types.js";
5
+ import { type AirdropInstanceClientOptions } from "./_shared.js";
6
+ /**
7
+ * Variables for {@link useRotateMerkleRoot}.
8
+ *
9
+ * @alpha
10
+ */
11
+ export interface UseRotateMerkleRootArgs extends CampaignSubmitterOption, WriteAccountOverride {
12
+ /** The FULL updated roster, carrying each account's new CUMULATIVE total — never the delta since the last root. */
13
+ recipients: readonly CampaignRecipient[];
14
+ }
15
+ /**
16
+ * Rebuild a campaign against updated totals and publish the new root in one
17
+ * call.
18
+ *
19
+ * **`recipients` must carry CUMULATIVE totals, not deltas.** `claimedAmount`
20
+ * survives a rotation and a claim pays
21
+ * `newTotal - min(newTotal, alreadyDelivered)`, so passing increments pays the
22
+ * increment minus everything already delivered — encrypted zero for most
23
+ * rosters. A total below what an account already received pays nothing; a
24
+ * rotation cannot claw back.
25
+ *
26
+ * The root is published LAST, so a failed rebuild leaves the previous campaign
27
+ * intact and claimable. Once it lands the old proofs stop verifying:
28
+ * **distribute the new entries to every recipient**, including those whose
29
+ * total did not change, or they are stuck.
30
+ *
31
+ * Requires `MERKLE_ADMIN_ROLE` and an instance created with
32
+ * `isMerkleRootMutable: true`. Distinct from {@link useSetMerkleRoot}, which
33
+ * publishes a root you already built.
34
+ *
35
+ * **Invalidates:** this instance's `useMerkleRoot` entry only. Explicitly NOT
36
+ * `useClaimedAmount`: a rotation changes no account's delivered total (it is
37
+ * keyed by account, not by root), so invalidating it would fan out a pointless
38
+ * RPC per mounted recipient row.
39
+ *
40
+ * @throws {@link FeatureDisabledError} when the instance was created with `isMerkleRootMutable: false`.
41
+ * @throws {@link InvalidArgumentError} on a duplicate, zero-address or out-of-`uint64`-range roster entry.
42
+ * @throws {@link MissingEncryptorError} when `encryptor` resolves to `undefined`.
43
+ *
44
+ * @example
45
+ * const rotate = useRotateMerkleRoot({ address: airdrop, encryptor: () => sdk.relayer });
46
+ * const { root, entries, hash } = await rotate.mutateAsync({
47
+ * recipients: [{ recipient: alice, cumulativeTotal: 1_500_000n }], // was 1_000_000n
48
+ * });
49
+ *
50
+ * @alpha
51
+ */
52
+ export declare function useRotateMerkleRoot(options: AirdropInstanceClientOptions): UseMutationResult<RotatedCampaign, Error, UseRotateMerkleRootArgs>;