@tokenops/sdk 2.0.0-alpha.3 → 2.0.0-alpha.4

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 (151) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +71 -35
  3. package/SUPPORT.md +1 -1
  4. package/dist/{chunk-NGU4JYIR.js → chunk-2ND7US2I.js} +1 -1
  5. package/dist/{chunk-U3TBQRT7.js → chunk-3ZSPRHR3.js} +55 -12
  6. package/dist/{chunk-BXX5TETM.js → chunk-67Q6KSVV.js} +4114 -3267
  7. package/dist/{chunk-JVNJSDQ4.cjs → chunk-6AYJRUGP.cjs} +7 -50
  8. package/dist/{chunk-AHU2HMNE.cjs → chunk-6FUHF73F.cjs} +5 -5
  9. package/dist/{chunk-NWFMBLSQ.js → chunk-7KY4K4PH.js} +1 -1
  10. package/dist/{chunk-YABHXJNH.cjs → chunk-ARZ5C3FS.cjs} +7 -7
  11. package/dist/{chunk-4IB4IY5Y.js → chunk-AX6MQAWU.js} +2 -2
  12. package/dist/{chunk-BPIVVCSQ.js → chunk-BSXEX2SH.js} +3 -3
  13. package/dist/{chunk-PK6Q6J5F.js → chunk-CHGY6B7L.js} +34 -81
  14. package/dist/{chunk-GKYZQJGP.cjs → chunk-DFK5GCJP.cjs} +55 -72
  15. package/dist/{chunk-4AWQJQXY.cjs → chunk-E4IV4M4E.cjs} +4126 -3279
  16. package/dist/{chunk-6HCT4QIX.js → chunk-GHGF65LN.js} +16 -13
  17. package/dist/{chunk-TWT3STIX.js → chunk-K3R27WX4.js} +8 -46
  18. package/dist/{chunk-GCJFAY4X.js → chunk-KJUNBOJQ.js} +52 -71
  19. package/dist/{chunk-6XOAYDC6.cjs → chunk-PO3A2AQX.cjs} +4 -4
  20. package/dist/{chunk-TND5NDV7.cjs → chunk-QHDMPT7I.cjs} +64 -19
  21. package/dist/{chunk-IEKTGJ4J.cjs → chunk-S47IBDTA.cjs} +36 -83
  22. package/dist/{chunk-UG5RKLU2.cjs → chunk-SUYBAF27.cjs} +1 -1
  23. package/dist/{chunk-WRWRA4TN.js → chunk-TWU7L5H7.js} +5 -48
  24. package/dist/{chunk-WJLECC22.cjs → chunk-UUSSWOPR.cjs} +9 -47
  25. package/dist/{chunk-YTIYTV4K.cjs → chunk-VHKMWWBA.cjs} +319 -40
  26. package/dist/{chunk-PG3WXT3K.cjs → chunk-YAL6JSAZ.cjs} +16 -13
  27. package/dist/{chunk-LEYYG4RF.js → chunk-YMWMIWBP.js} +315 -42
  28. package/dist/core/addresses.d.ts +4 -4
  29. package/dist/core/errors.d.ts +1 -1
  30. package/dist/core/index.d.ts +1 -0
  31. package/dist/core/pending.d.ts +57 -0
  32. package/dist/core/version.d.ts +1 -1
  33. package/dist/fhe/operators.d.ts +6 -5
  34. package/dist/fhe/types.d.ts +1 -1
  35. package/dist/fhe-airdrop/abis/airdrop-base.d.ts +81 -4
  36. package/dist/fhe-airdrop/abis/ecdsa.d.ts +101 -4
  37. package/dist/fhe-airdrop/abis/factory.d.ts +222 -4
  38. package/dist/fhe-airdrop/abis/merkle.d.ts +100 -4
  39. package/dist/fhe-airdrop/advanced/index.cjs +8 -4
  40. package/dist/fhe-airdrop/advanced/index.d.cts +1 -0
  41. package/dist/fhe-airdrop/advanced/index.d.ts +1 -0
  42. package/dist/fhe-airdrop/advanced/index.js +1 -1
  43. package/dist/fhe-airdrop/advanced/react/index.cjs +121 -143
  44. package/dist/fhe-airdrop/advanced/react/index.js +55 -77
  45. package/dist/fhe-airdrop/advanced/react/useClearCompliancePolicy.d.ts +3 -1
  46. package/dist/fhe-airdrop/advanced/react/useDisableCustomFee.d.ts +3 -1
  47. package/dist/fhe-airdrop/advanced/react/useFactoryComplianceDelegate.d.ts +2 -4
  48. package/dist/fhe-airdrop/advanced/react/useSetComplianceDelegate.d.ts +7 -7
  49. package/dist/fhe-airdrop/advanced/react/useSetComplianceManagerImpl.d.ts +3 -1
  50. package/dist/fhe-airdrop/advanced/react/useSetCompliancePolicy.d.ts +2 -1
  51. package/dist/fhe-airdrop/advanced/react/useSetCustomFee.d.ts +3 -1
  52. package/dist/fhe-airdrop/advanced/react/useSetDefaultDelegateToCompliance.d.ts +5 -4
  53. package/dist/fhe-airdrop/advanced/react/useSetDefaultGasFee.d.ts +3 -1
  54. package/dist/fhe-airdrop/advanced/react/useSetMaxGasFee.d.ts +7 -3
  55. package/dist/fhe-airdrop/airdrop-base.d.ts +95 -10
  56. package/dist/fhe-airdrop/campaign.d.ts +37 -73
  57. package/dist/fhe-airdrop/compliance-clone.d.ts +21 -0
  58. package/dist/fhe-airdrop/constants.d.ts +3 -1
  59. package/dist/fhe-airdrop/ecdsa.d.ts +67 -27
  60. package/dist/fhe-airdrop/encryption.d.ts +19 -6
  61. package/dist/fhe-airdrop/errors.d.ts +77 -2
  62. package/dist/fhe-airdrop/factory-params.d.ts +2361 -0
  63. package/dist/fhe-airdrop/factory.d.ts +142 -68
  64. package/dist/fhe-airdrop/guards.d.ts +110 -31
  65. package/dist/fhe-airdrop/index.cjs +79 -59
  66. package/dist/fhe-airdrop/index.d.cts +11 -9
  67. package/dist/fhe-airdrop/index.d.ts +11 -9
  68. package/dist/fhe-airdrop/index.js +5 -5
  69. package/dist/fhe-airdrop/merkle-tree.d.ts +9 -9
  70. package/dist/fhe-airdrop/merkle.d.ts +32 -11
  71. package/dist/fhe-airdrop/react/_shared.d.ts +12 -6
  72. package/dist/fhe-airdrop/react/index.cjs +294 -258
  73. package/dist/fhe-airdrop/react/index.d.cts +16 -9
  74. package/dist/fhe-airdrop/react/index.d.ts +16 -9
  75. package/dist/fhe-airdrop/react/index.js +114 -110
  76. package/dist/fhe-airdrop/react/keys.d.ts +46 -7
  77. package/dist/fhe-airdrop/react/useAccessEcdsaClaimAmount.d.ts +6 -3
  78. package/dist/fhe-airdrop/react/useAccessMerkleClaimAmount.d.ts +2 -2
  79. package/dist/fhe-airdrop/react/useAirdropConfig.d.ts +8 -3
  80. package/dist/fhe-airdrop/react/useAirdropPause.d.ts +5 -0
  81. package/dist/fhe-airdrop/react/useBuildMerkleCampaign.d.ts +4 -6
  82. package/dist/fhe-airdrop/react/useComplianceManager.d.ts +2 -2
  83. package/dist/fhe-airdrop/react/useComplianceManagerOf.d.ts +1 -2
  84. package/dist/fhe-airdrop/react/useCreateAndFundEcdsaAirdrop.d.ts +16 -11
  85. package/dist/fhe-airdrop/react/useCreateAndFundMerkleAirdrop.d.ts +23 -7
  86. package/dist/fhe-airdrop/react/useCreateEcdsaAirdrop.d.ts +13 -8
  87. package/dist/fhe-airdrop/react/useCreateMerkleAirdrop.d.ts +27 -7
  88. package/dist/fhe-airdrop/react/useDedupMode.d.ts +16 -0
  89. package/dist/fhe-airdrop/react/useDiscloseHandleToParty.d.ts +4 -3
  90. package/dist/fhe-airdrop/react/useEcdsaClaim.d.ts +6 -4
  91. package/dist/fhe-airdrop/react/useEcdsaClaimAndUnwrap.d.ts +15 -8
  92. package/dist/fhe-airdrop/react/useEcdsaDomain.d.ts +1 -1
  93. package/dist/fhe-airdrop/react/useEncryptCampaignAmounts.d.ts +5 -7
  94. package/dist/fhe-airdrop/react/useExtendClaimWindow.d.ts +4 -1
  95. package/dist/fhe-airdrop/react/useFundAirdrop.d.ts +3 -4
  96. package/dist/fhe-airdrop/react/useGrantInstanceRoles.d.ts +2 -1
  97. package/dist/fhe-airdrop/react/useIsSignatureValid.d.ts +5 -4
  98. package/dist/fhe-airdrop/react/useMerkleClaim.d.ts +4 -1
  99. package/dist/fhe-airdrop/react/useMerkleClaimAndUnwrap.d.ts +14 -3
  100. package/dist/fhe-airdrop/react/usePlanMerkleCampaign.d.ts +18 -3
  101. package/dist/fhe-airdrop/react/usePreflightClaim.d.ts +1 -1
  102. package/dist/fhe-airdrop/react/usePreflightCreateAirdrop.d.ts +34 -13
  103. package/dist/fhe-airdrop/react/useRescueERC20.d.ts +3 -3
  104. package/dist/fhe-airdrop/react/useRescueNativeToken.d.ts +23 -0
  105. package/dist/fhe-airdrop/react/useRotateMerkleRoot.d.ts +5 -2
  106. package/dist/fhe-airdrop/react/useSignClaimAuthorization.d.ts +4 -0
  107. package/dist/fhe-airdrop/react/useTokenOf.d.ts +29 -0
  108. package/dist/fhe-airdrop/react/useUnwrapRequest.d.ts +25 -0
  109. package/dist/fhe-airdrop/react/useWithdrawConfidential.d.ts +4 -0
  110. package/dist/fhe-airdrop/roles.d.ts +82 -7
  111. package/dist/fhe-airdrop/types.d.ts +109 -14
  112. package/dist/fhe-disperse/errors.d.ts +3 -3
  113. package/dist/fhe-disperse/index.cjs +22 -22
  114. package/dist/fhe-disperse/index.d.cts +2 -1
  115. package/dist/fhe-disperse/index.d.ts +2 -1
  116. package/dist/fhe-disperse/index.js +3 -3
  117. package/dist/fhe-disperse/react/index.cjs +27 -25
  118. package/dist/fhe-disperse/react/index.d.cts +2 -1
  119. package/dist/fhe-disperse/react/index.d.ts +2 -1
  120. package/dist/fhe-disperse/react/index.js +8 -6
  121. package/dist/fhe-disperse/react/useDisperse.d.ts +6 -2
  122. package/dist/fhe-disperse/react/useRegister.d.ts +9 -3
  123. package/dist/fhe-disperse/react/useSingletonWithdrawTokenFee.d.ts +7 -2
  124. package/dist/fhe-disperse/react/useWithdrawTokenFee.d.ts +7 -2
  125. package/dist/fhe-disperse/singleton.d.ts +33 -19
  126. package/dist/fhe-disperse/types.d.ts +48 -8
  127. package/dist/fhe-vesting/advanced/index.cjs +6 -6
  128. package/dist/fhe-vesting/advanced/index.js +4 -4
  129. package/dist/fhe-vesting/advanced/react/index.cjs +9 -9
  130. package/dist/fhe-vesting/advanced/react/index.js +6 -6
  131. package/dist/fhe-vesting/factory.d.ts +31 -8
  132. package/dist/fhe-vesting/index.cjs +23 -23
  133. package/dist/fhe-vesting/index.d.cts +3 -2
  134. package/dist/fhe-vesting/index.d.ts +3 -2
  135. package/dist/fhe-vesting/index.js +4 -4
  136. package/dist/fhe-vesting/manager.d.ts +27 -2
  137. package/dist/fhe-vesting/react/index.cjs +126 -126
  138. package/dist/fhe-vesting/react/index.d.cts +3 -2
  139. package/dist/fhe-vesting/react/index.d.ts +3 -2
  140. package/dist/fhe-vesting/react/index.js +5 -5
  141. package/dist/fhe-vesting/react/useCreateManager.d.ts +16 -9
  142. package/dist/fhe-vesting/react/useCreateManagerAndGetAddress.d.ts +9 -5
  143. package/dist/fhe-vesting/react/useSplitVesting.d.ts +9 -3
  144. package/dist/index.cjs +18 -18
  145. package/dist/index.js +1 -1
  146. package/dist/testnet-faucet/faucet.d.ts +3 -0
  147. package/dist/testnet-faucet/index.cjs +15 -15
  148. package/dist/testnet-faucet/index.js +3 -3
  149. package/dist/testnet-faucet/react/index.cjs +9 -9
  150. package/dist/testnet-faucet/react/index.js +4 -4
  151. package/package.json +1 -1
@@ -12,7 +12,9 @@
12
12
  *
13
13
  * A `fn` label used by exactly one hook stays inline in that hook.
14
14
  */
15
+ import type { QueryClient } from "@tanstack/react-query";
15
16
  import type { Address, Hex } from "viem";
17
+ import type { DeploymentMode } from "../constants.js";
16
18
  /** Chain + contract scope every key below is built against. */
17
19
  interface Scope {
18
20
  chainId: number | undefined;
@@ -22,6 +24,7 @@ interface Scope {
22
24
  export declare const AIRDROP_FN: {
23
25
  readonly claimedAmount: "getClaimedAmount";
24
26
  readonly paused: "paused";
27
+ readonly dedupMode: "dedupMode";
25
28
  readonly window: "window";
26
29
  readonly config: "config";
27
30
  readonly merkleRoot: "merkleRoot";
@@ -37,19 +40,28 @@ export declare const AIRDROP_FN: {
37
40
  readonly resolvedGasFee: "resolvedGasFee";
38
41
  readonly customFee: "customFee";
39
42
  readonly implementations: "implementations";
43
+ readonly tokenOf: "tokenOf";
44
+ readonly complianceManagerOf: "complianceManagerOf";
40
45
  readonly compliancePolicy: "compliancePolicy";
41
46
  readonly upgradeabilityPolicy: "upgradeabilityPolicy";
42
47
  readonly factoryHasRole: "factoryHasRole";
43
48
  readonly factoryRoleMembers: "factoryRoleMembers";
49
+ readonly effectiveDelegateToCompliance: "effectiveDelegateToCompliance";
50
+ readonly effectiveUpgradeable: "effectiveUpgradeable";
51
+ readonly complianceDelegate: "complianceDelegate";
52
+ readonly ecdsaInitCodeHash: "getEcdsaInitCodeHash";
53
+ readonly predictEcdsaAddress: "predictEcdsaAirdropAddress";
54
+ readonly merkleInitCodeHash: "getMerkleInitCodeHash";
55
+ readonly predictMerkleAddress: "predictMerkleAirdropAddress";
44
56
  readonly complianceInfo: "complianceInfo";
45
57
  readonly activeDelegate: "isActiveDelegate";
46
- readonly clientDelegates: "clientDelegates";
47
58
  readonly complianceHasRole: "complianceHasRole";
48
59
  readonly complianceRoleMembers: "complianceRoleMembers";
49
60
  };
50
61
  export declare const airdropKeys: {
51
62
  /** One account's cumulative delivered total. Keyed on the CLAIM IDENTITY, never the sender. */
52
63
  readonly claimedAmount: (s: Scope, account: Address | undefined) => unknown[];
64
+ readonly dedupMode: (s: Scope) => unknown[];
53
65
  readonly paused: (s: Scope) => unknown[];
54
66
  readonly window: (s: Scope) => unknown[];
55
67
  readonly config: (s: Scope) => unknown[];
@@ -67,15 +79,17 @@ export declare const airdropKeys: {
67
79
  readonly isSignatureValidAll: (s: Scope) => unknown[];
68
80
  readonly fees: (s: Scope) => unknown[];
69
81
  readonly customFee: (s: Scope, creator: Address | undefined) => unknown[];
70
- readonly customFeeAll: (s: Scope) => unknown[];
71
82
  readonly resolvedGasFee: (s: Scope, creator: Address | undefined) => unknown[];
72
83
  /** Every creator's resolved fee; the default and any override both move it. */
73
84
  readonly resolvedGasFeeAll: (s: Scope) => unknown[];
85
+ readonly registry: (s: Scope, offset: bigint | undefined, limit: bigint | undefined) => unknown[];
74
86
  /** Every registry page, whatever offset/limit was queried. */
75
87
  readonly registryAll: (s: Scope) => unknown[];
76
88
  readonly isAirdrop: (s: Scope, candidate: Address | undefined) => unknown[];
77
89
  /** Every genuineness answer from this factory; a create adds one address. */
78
90
  readonly isAirdropAll: (s: Scope) => unknown[];
91
+ readonly tokenOf: (s: Scope, airdrop: Address | undefined) => unknown[];
92
+ readonly complianceManagerOf: (s: Scope, airdrop: Address | undefined) => unknown[];
79
93
  readonly implementations: (s: Scope) => unknown[];
80
94
  readonly compliancePolicy: (s: Scope, creator: Address | undefined) => unknown[];
81
95
  readonly compliancePolicyAll: (s: Scope) => unknown[];
@@ -84,15 +98,40 @@ export declare const airdropKeys: {
84
98
  readonly factoryHasRole: (s: Scope, role: Hex | undefined, holder: Address | undefined) => unknown[];
85
99
  readonly factoryHasRoleAll: (s: Scope) => unknown[];
86
100
  readonly factoryRoleMembers: (s: Scope, role: Hex | undefined) => unknown[];
87
- readonly factoryRoleMembersAll: (s: Scope) => unknown[];
101
+ readonly effectiveDelegateToCompliance: (s: Scope, creator: Address | undefined) => unknown[];
102
+ /** Every creator's effective compliance default; the factory-wide default moves them all. */
103
+ readonly effectiveDelegateToComplianceAll: (s: Scope) => unknown[];
104
+ readonly effectiveUpgradeable: (s: Scope, creator: Address | undefined) => unknown[];
105
+ /** Every creator's effective upgradeability; the factory-wide default moves them all. */
106
+ readonly effectiveUpgradeableAll: (s: Scope) => unknown[];
107
+ readonly complianceDelegate: (s: Scope) => unknown[];
108
+ /** Keyed on `mode` only: `params` does not affect the hash (see `useEcdsaInitCodeHash`). */
109
+ readonly ecdsaInitCodeHash: (s: Scope, mode: DeploymentMode) => unknown[];
110
+ readonly ecdsaInitCodeHashAll: (s: Scope) => unknown[];
111
+ readonly predictEcdsaAddress: (s: Scope, mode: DeploymentMode, deployer: Address, userSalt: Hex) => unknown[];
112
+ readonly predictEcdsaAddressAll: (s: Scope) => unknown[];
113
+ readonly merkleInitCodeHash: (s: Scope, mode: DeploymentMode) => unknown[];
114
+ readonly merkleInitCodeHashAll: (s: Scope) => unknown[];
115
+ readonly predictMerkleAddress: (s: Scope, mode: DeploymentMode, deployer: Address, userSalt: Hex) => unknown[];
116
+ readonly predictMerkleAddressAll: (s: Scope) => unknown[];
88
117
  readonly complianceInfo: (s: Scope) => unknown[];
89
118
  readonly activeDelegate: (s: Scope, delegate: Address | undefined) => unknown[];
90
- readonly activeDelegateAll: (s: Scope) => unknown[];
91
- readonly clientDelegates: (s: Scope, index: bigint | undefined) => unknown[];
92
- readonly clientDelegatesAll: (s: Scope) => unknown[];
93
119
  readonly complianceHasRole: (s: Scope, role: Hex | undefined, holder: Address | undefined) => unknown[];
94
120
  readonly complianceHasRoleAll: (s: Scope) => unknown[];
95
121
  readonly complianceRoleMembers: (s: Scope, role: Hex | undefined) => unknown[];
96
- readonly complianceRoleMembersAll: (s: Scope) => unknown[];
97
122
  };
123
+ /**
124
+ * Invalidate everything a create makes stale, for the four factory create hooks.
125
+ *
126
+ * - `registryAll`: the registry gained an instance.
127
+ * - `isAirdropAll`: `isAirdrop(airdrop)` flipped from false to true.
128
+ * - `preflightCreateAll`: the create consumed its `(mode, deployer, userSalt)`, so a cached
129
+ * `ready: true` for it is now a guaranteed `SaltCollisionError`.
130
+ * - `tokenOf` / `complianceManagerOf` for `airdrop`: a read of the predicted address taken
131
+ * before the create cached a zero.
132
+ *
133
+ * A receipt-free create runs this too, before the transaction executes. That is harmless:
134
+ * the refetch reads the pre-create state and the entries are marked stale again later.
135
+ */
136
+ export declare function invalidateAfterCreate(queryClient: QueryClient, scope: Scope, airdrop: Address): void;
98
137
  export {};
@@ -10,15 +10,18 @@ import { type EcdsaAirdropInstanceClientOptions } from "./_shared.js";
10
10
  * with `FHE.allow(amount, msg.sender)`, unlike {@link useAccessMerkleClaimAmount}, whose
11
11
  * grantee is the entry's claim identity rather than the caller.
12
12
  *
13
- * `dedupMode` must be supplied - the contract has no on-chain getter for it; pass the
14
- * same value used at `createEcdsaAirdrop` time.
13
+ * An empty `inputProof` is accepted only for a zero handle or one the sender and the
14
+ * instance already hold ACL on; see `EcdsaClaimArgs.encryptedInput`.
15
+ *
16
+ * `dedupMode` is deprecated - no call branches on it. Read the
17
+ * instance's actual policy with `useDedupMode`.
15
18
  *
16
19
  * **Invalidates:** nothing. The preview consumes neither replay guard nor the EIP-712
17
20
  * digest, so the same input is still claimable for real afterwards and no cached read
18
21
  * changes value.
19
22
  *
20
23
  * @example
21
- * const preview = useAccessEcdsaClaimAmount({ address: airdropAddress, dedupMode: "perAddress" });
24
+ * const preview = useAccessEcdsaClaimAmount({ address: airdropAddress });
22
25
  * const { handle } = await preview.mutateAsync({ encryptedInput, dedupId, deadline, signer, signature });
23
26
  *
24
27
  * @alpha
@@ -6,8 +6,8 @@ import { type AirdropInstanceClientOptions } from "./_shared.js";
6
6
  * **Submits a transaction.** Previews the outstanding amount for a proof-bearing Merkle
7
7
  * entry as an encrypted handle. Pass `data.handle` to the Zama relayer's `userDecrypt`.
8
8
  *
9
- * `entry.boundTo` must be the sending account (the coprocessor verifies the input proof
10
- * against the literal caller); `entry.account` selects the leaf.
9
+ * `entry.account` selects the leaf. A leaf someone else already settled previews as an
10
+ * encrypted zero; see {@link MerkleClaimArgs.entry}.
11
11
  *
12
12
  * **`entry.account` is the only party that can decrypt the result, not the submitter.**
13
13
  * The contract grants the outstanding handle with `_outstandingOf(account, account, …)`,
@@ -3,7 +3,7 @@ import type { Address } from "viem";
3
3
  import type { AirdropVariant } from "../errors.js";
4
4
  import { type AirdropInstanceHookOptions } from "./_shared.js";
5
5
  /**
6
- * Create-time-immutable instance configuration - combines five `AirdropBaseClient`
6
+ * Create-time-immutable instance configuration - combines seven `AirdropBaseClient`
7
7
  * reads into one.
8
8
  *
9
9
  * @alpha
@@ -21,13 +21,18 @@ export interface AirdropConfig {
21
21
  complianceManager: Address;
22
22
  /** Per-claim ETH fee in wei; `0` on a fee-free campaign. */
23
23
  gasFee: bigint;
24
+ /** Whether `extendClaimWindow` is permitted; frozen at create. */
25
+ canExtendClaimWindow: boolean;
26
+ /** The block the instance was initialized in (L2 block on Arbitrum). */
27
+ deploymentBlockNumber: bigint;
24
28
  }
25
29
  /** @alpha */
26
30
  export type UseAirdropConfigArgs = AirdropInstanceHookOptions<AirdropConfig>;
27
31
  /**
28
32
  * Read an airdrop instance's immutable configuration in one round trip.
29
33
  *
30
- * Bundles `token` / `airdropType` / `unwrappable` / `complianceManager` / `gasFee` -
34
+ * Bundles `token` / `airdropType` / `unwrappable` / `complianceManager` / `gasFee` /
35
+ * `canExtendClaimWindow` / `deploymentBlockNumber` -
31
36
  * what a UI needs before it can render anything else about a campaign, and how
32
37
  * `airdropType` and `unwrappable` get covered without shipping two more one-line hooks
33
38
  * nobody would call separately. `variant` is derived from the ordinal so a consumer can
@@ -38,7 +43,7 @@ export type UseAirdropConfigArgs = AirdropInstanceHookOptions<AirdropConfig>;
38
43
  *
39
44
  * The existing {@link useAirdropToken}, {@link useAirdropGasFee} and
40
45
  * {@link useComplianceManager} overlap this bundle and stay: they are one `eth_call`
41
- * rather than five, which is cheaper for a UI that needs exactly one value.
46
+ * rather than seven, which is cheaper for a UI that needs exactly one value.
42
47
  *
43
48
  * @example
44
49
  * const { data: config } = useAirdropConfig({ address: airdropAddress });
@@ -21,6 +21,11 @@ export interface AirdropPauseArgs extends WriteAccountOverride {
21
21
  * `window.isActive`, so a mounted `useAirdropWindow` consumer would otherwise
22
22
  * keep showing a stale `isActive` after a pause/unpause.
23
23
  *
24
+ * Not invalidated: {@link usePreflightClaim} (its `PausedError` blocker) and
25
+ * {@link useIsSignatureValid} (which answers `false` while paused) also move with
26
+ * the flag. Refetch them if the same session renders both the admin toggle and a
27
+ * claim form.
28
+ *
24
29
  * @example
25
30
  * const setPause = useAirdropPause({ address: airdropAddress });
26
31
  * await setPause.mutateAsync({ paused: true });
@@ -1,6 +1,5 @@
1
1
  import { type UseMutationResult } from "@tanstack/react-query";
2
2
  import type { Address } from "viem";
3
- import { type CampaignSubmitterOption } from "../campaign.js";
4
3
  import { type EncryptorSource } from "../encryption.js";
5
4
  import type { BuiltCampaign, CampaignRecipient } from "../types.js";
6
5
  /**
@@ -23,7 +22,7 @@ export interface UseBuildMerkleCampaignOptions {
23
22
  *
24
23
  * @alpha
25
24
  */
26
- export interface UseBuildMerkleCampaignArgs extends CampaignSubmitterOption {
25
+ export interface UseBuildMerkleCampaignArgs {
27
26
  /** The LIVE `MerkleConfidentialAirdrop` instance every input is bound to. Not the factory, not the implementation. */
28
27
  instance: Address;
29
28
  /** CUMULATIVE totals per account, never per-drop tranches. */
@@ -48,10 +47,9 @@ export interface UseBuildMerkleCampaignArgs extends CampaignSubmitterOption {
48
47
  * A mutation rather than a query: encryption is randomised, so the same roster
49
48
  * builds a different root every call and there is no cache identity to key.
50
49
  *
51
- * Each entry is `{ account, boundTo, handle, inputProof, merkleProof }` —
52
- * `account` selects the leaf and the cumulative accounting, `boundTo` is the
53
- * only address the coprocessor accepts as sender. They are equal unless
54
- * `submitter` was set.
50
+ * Each entry is `{ account, handle, inputProof, merkleProof }` - `account`
51
+ * selects the leaf and the cumulative accounting. One relayer request per 32
52
+ * recipients, issued concurrently; every leaf is submittable by any address.
55
53
  *
56
54
  * **Invalidates:** nothing. Off-chain work only; the root is not published here.
57
55
  *
@@ -5,8 +5,8 @@ import { type AirdropInstanceHookOptions } from "./_shared.js";
5
5
  export type UseComplianceManagerArgs = AirdropInstanceHookOptions<Address>;
6
6
  /**
7
7
  * Read an airdrop instance's own compliance-manager clone — the only
8
- * contract, besides the caller, ever granted ACL on that instance's
9
- * confidential handles.
8
+ * contract the instance itself grants persistent ACL on its pool and claim
9
+ * handles.
10
10
  *
11
11
  * @example
12
12
  * const { data: complianceManager } = useComplianceManager({ address: airdropAddress });
@@ -15,8 +15,7 @@ export interface UseComplianceManagerOfArgs extends AirdropHookOptions<Address>
15
15
  * instances it deployed, so a zero address means the instance did not come
16
16
  * from this factory - do not mount the compliance hooks on it.
17
17
  *
18
- * Cached indefinitely (`staleTime: Infinity`, overridable through `query`):
19
- * the mapping is written once, inside `createX`, and never changes.
18
+ * Caching follows the same write-once policy as {@link useTokenOf}.
20
19
  *
21
20
  * @remarks
22
21
  * {@link useComplianceManager} answers the same question from the other side,
@@ -1,7 +1,8 @@
1
1
  import { type UseMutationResult } from "@tanstack/react-query";
2
+ import type { ReceiptMode } from "../../core/pending.js";
2
3
  import type { WriteAccountOverride } from "../airdrop-base.js";
3
4
  import type { FundInput } from "../factory.js";
4
- import type { CreateAirdropArgs, CreateAirdropResult, EcdsaAirdropParams } from "../types.js";
5
+ import type { CreateAirdropArgs, CreateAirdropResult, EcdsaAirdropParams, PendingCreateAirdropResult } from "../types.js";
5
6
  import { type AirdropClientOptions } from "./_shared.js";
6
7
  /**
7
8
  * Variables for {@link useCreateAndFundEcdsaAirdrop} — the create arguments plus
@@ -9,7 +10,7 @@ import { type AirdropClientOptions } from "./_shared.js";
9
10
  *
10
11
  * @alpha
11
12
  */
12
- export type UseCreateAndFundEcdsaAirdropArgs = CreateAirdropArgs<EcdsaAirdropParams> & FundInput & WriteAccountOverride;
13
+ export type UseCreateAndFundEcdsaAirdropArgs = CreateAirdropArgs<EcdsaAirdropParams> & FundInput & WriteAccountOverride & ReceiptMode;
13
14
  /**
14
15
  * Deploy an ECDSA-authorised airdrop instance and seed its pool in one
15
16
  * transaction.
@@ -20,19 +21,23 @@ export type UseCreateAndFundEcdsaAirdropArgs = CreateAirdropArgs<EcdsaAirdropPar
20
21
  * (plaintext, encrypted against the hook-level `encryptor`) or a pre-built
21
22
  * `encryptedInput`, never both.
22
23
  *
23
- * Returns `CreateAirdropResult` unflattened — `{ hash, airdrop,
24
- * complianceManager }`; the caller needs the instance address to do anything
25
- * with the campaign afterwards.
24
+ * Returns `CreateAirdropResult` (or `PendingCreateAirdropResult` with `waitForReceipt: false`; both carry every address) unflattened - `{ hash, airdrop,
25
+ * complianceManager, managerImplementation, complianceDelegate }`; the caller
26
+ * needs the instance address to do anything with the campaign afterwards.
26
27
  *
27
28
  * **A successful receipt does not prove the pool was funded.** An ERC-7984
28
29
  * transfer moves an encrypted zero instead of reverting when the funder is
29
30
  * short, because reverting would leak the balance.
30
31
  *
31
- * **Invalidates:** the factory's registry reads (`useFactoryRegistry`) for
32
- * this factory address, whatever page was cached — a new instance moves
33
- * `airdropCount()` / `airdrops()`. Nothing else: the new instance has no
34
- * cached reads yet, and no read hook here exposes the confidential pool
35
- * balance.
32
+ * **Safe / multisig signers:** pass `waitForReceipt: false`; see
33
+ * {@link ReceiptMode}.
34
+ *
35
+ * **Invalidates:** the factory's registry pages, every cached `isAirdrop` answer, every
36
+ * cached create preflight (the salt is now consumed), and the {@link useTokenOf} /
37
+ * {@link useComplianceManagerOf} entries for the new address, which may hold a zero
38
+ * read before the create.
39
+ * No read hook here caches the confidential pool balance, so the fund leg moves nothing
40
+ * else.
36
41
  *
37
42
  * **Never log `amount`.** It is the one plaintext confidential value this
38
43
  * hook sees — keep it out of telemetry, `onError` context and console.
@@ -52,4 +57,4 @@ export type UseCreateAndFundEcdsaAirdropArgs = CreateAirdropArgs<EcdsaAirdropPar
52
57
  *
53
58
  * @alpha
54
59
  */
55
- export declare function useCreateAndFundEcdsaAirdrop(options?: AirdropClientOptions): UseMutationResult<CreateAirdropResult, Error, UseCreateAndFundEcdsaAirdropArgs>;
60
+ export declare function useCreateAndFundEcdsaAirdrop(options?: AirdropClientOptions): UseMutationResult<CreateAirdropResult | PendingCreateAirdropResult, Error, UseCreateAndFundEcdsaAirdropArgs>;
@@ -1,7 +1,8 @@
1
1
  import { type UseMutationResult } from "@tanstack/react-query";
2
+ import type { ReceiptMode } from "../../core/pending.js";
2
3
  import type { WriteAccountOverride } from "../airdrop-base.js";
3
4
  import type { FundInput } from "../factory.js";
4
- import type { CreateAirdropArgs, CreateAirdropResult, MerkleAirdropParams } from "../types.js";
5
+ import type { CreateAirdropResult, CreateMerkleAirdropArgs, PendingCreateAirdropResult } from "../types.js";
5
6
  import { type AirdropClientOptions } from "./_shared.js";
6
7
  /**
7
8
  * Variables for {@link useCreateAndFundMerkleAirdrop} — the create arguments plus
@@ -9,7 +10,7 @@ import { type AirdropClientOptions } from "./_shared.js";
9
10
  *
10
11
  * @alpha
11
12
  */
12
- export type UseCreateAndFundMerkleAirdropArgs = CreateAirdropArgs<MerkleAirdropParams> & FundInput & WriteAccountOverride;
13
+ export type UseCreateAndFundMerkleAirdropArgs = CreateMerkleAirdropArgs & FundInput & WriteAccountOverride & ReceiptMode;
13
14
  /**
14
15
  * Deploy a Merkle-proof airdrop instance and seed its pool in one transaction.
15
16
  *
@@ -20,23 +21,37 @@ export type UseCreateAndFundMerkleAirdropArgs = CreateAirdropArgs<MerkleAirdropP
20
21
  *
21
22
  * `mode: "uups"` is rejected before the wallet is even looked up, so the
22
23
  * mutation rejects without prompting for a signature. Returns
23
- * `CreateAirdropResult` unflattened — `{ hash, airdrop, complianceManager }`.
24
+ * `CreateAirdropResult` (or `PendingCreateAirdropResult` with `waitForReceipt: false`; both carry every address) unflattened - `{ hash, airdrop, complianceManager,
25
+ * managerImplementation, complianceDelegate }`.
24
26
  *
25
27
  * **A successful receipt does not prove the pool was funded.** An ERC-7984
26
28
  * transfer moves an encrypted zero instead of reverting when the funder is
27
29
  * short, because reverting would leak the balance.
28
30
  *
29
- * **Invalidates:** the factory's registry reads (`useFactoryRegistry`) for
30
- * this factory address, whatever page was cached — a new instance moves
31
- * `airdropCount()` / `airdrops()`. Nothing else.
31
+ * **Safe / multisig signers:** pass `waitForReceipt: false`; see
32
+ * {@link ReceiptMode}.
33
+ *
34
+ * **Invalidates:** the factory's registry pages, every cached `isAirdrop` answer, every
35
+ * cached create preflight (the salt is now consumed), and the {@link useTokenOf} /
36
+ * {@link useComplianceManagerOf} entries for the new address, which may hold a zero
37
+ * read before the create.
32
38
  *
33
39
  * **Never log `amount`.** It is the one plaintext confidential value this
34
40
  * hook sees — keep it out of telemetry, `onError` context and console.
35
41
  *
42
+ * **Creating from a plan.** Pass the {@link PlannedCampaign} as `plan`, with
43
+ * `merkleRoot: plan.root`. The create then pins `plan.predictedAddress`, refuses a root that
44
+ * differs from the plan's, and refuses to send once the factory's Merkle implementation has
45
+ * moved since the plan ({@link PredictionDriftError}). Both are checked before anything is
46
+ * encrypted. `expected: { airdrop: plan.predictedAddress }` is the lower-level equivalent of
47
+ * the pin alone.
48
+ *
36
49
  * @throws {@link MerkleUupsUnsupportedError} when `mode` is `"uups"`.
37
50
  * @throws {@link DeploymentAddressUnavailableError} when no factory is deployed for the connected chain.
38
51
  * @throws {@link MissingEncryptorError} when `amount` is given and no encryptor resolves.
39
52
  * @throws {@link SaltCollisionError} when this `(mode, deployer, userSalt)` tuple already deployed an instance.
53
+ * @throws {@link PredictionDriftError} when `plan` is given and the factory's Merkle implementation moved since it was taken.
54
+ * @throws {@link InvalidArgumentError} when `params.merkleRoot` or `expected.airdrop` disagrees with `plan`.
40
55
  *
41
56
  * @example
42
57
  * const createAndFund = useCreateAndFundMerkleAirdrop({ encryptor: () => sdk.relayer });
@@ -44,9 +59,10 @@ export type UseCreateAndFundMerkleAirdropArgs = CreateAirdropArgs<MerkleAirdropP
44
59
  * params: { common, merkleRoot: plan.root, isMerkleRootMutable: false },
45
60
  * mode: "clone",
46
61
  * userSalt,
62
+ * plan,
47
63
  * amount: 1_000_000n,
48
64
  * });
49
65
  *
50
66
  * @alpha
51
67
  */
52
- export declare function useCreateAndFundMerkleAirdrop(options?: AirdropClientOptions): UseMutationResult<CreateAirdropResult, Error, UseCreateAndFundMerkleAirdropArgs>;
68
+ export declare function useCreateAndFundMerkleAirdrop(options?: AirdropClientOptions): UseMutationResult<CreateAirdropResult | PendingCreateAirdropResult, Error, UseCreateAndFundMerkleAirdropArgs>;
@@ -1,19 +1,24 @@
1
1
  import { type UseMutationResult } from "@tanstack/react-query";
2
- import type { CreateAirdropArgs, CreateAirdropResult, EcdsaAirdropParams } from "../types.js";
2
+ import type { ReceiptMode } from "../../core/pending.js";
3
+ import type { CreateAirdropArgs, CreateAirdropResult, EcdsaAirdropParams, PendingCreateAirdropResult } from "../types.js";
3
4
  import type { WriteAccountOverride } from "../airdrop-base.js";
4
5
  import { type AirdropClientOptions } from "./_shared.js";
5
6
  /**
6
7
  * Deploy an ECDSA-authorised airdrop instance via the factory.
7
8
  *
8
- * Returns the headless client's `CreateAirdropResult` unchanged — `{ hash,
9
- * airdrop, complianceManager }` — never flattened to just a hash: a caller
9
+ * Returns the headless client's `CreateAirdropResult` (or `PendingCreateAirdropResult` with `waitForReceipt: false`; both carry every address) unchanged - `{ hash,
10
+ * airdrop, complianceManager, managerImplementation, complianceDelegate }` -
11
+ * never flattened to just a hash: a caller
10
12
  * needs the deployed instance address to do anything with the campaign
11
13
  * afterwards.
12
14
  *
13
- * **Invalidates:** the factory's registry reads (`useFactoryRegistry`) for
14
- * this factory address, since a new instance changes `airdropCount()` /
15
- * `airdrops()`. Nothing else — the new instance has no cached reads yet, and
16
- * no other factory or instance state changed.
15
+ * **Safe / multisig signers:** pass `waitForReceipt: false`; see
16
+ * {@link ReceiptMode}.
17
+ *
18
+ * **Invalidates:** the factory's registry pages, every cached `isAirdrop` answer, every
19
+ * cached create preflight (the salt is now consumed), and the {@link useTokenOf} /
20
+ * {@link useComplianceManagerOf} entries for the new address, which may hold a zero
21
+ * read before the create.
17
22
  *
18
23
  * @example
19
24
  * const create = useCreateEcdsaAirdrop();
@@ -25,4 +30,4 @@ import { type AirdropClientOptions } from "./_shared.js";
25
30
  *
26
31
  * @alpha
27
32
  */
28
- export declare function useCreateEcdsaAirdrop(options?: AirdropClientOptions): UseMutationResult<CreateAirdropResult, Error, CreateAirdropArgs<EcdsaAirdropParams> & WriteAccountOverride>;
33
+ export declare function useCreateEcdsaAirdrop(options?: AirdropClientOptions): UseMutationResult<CreateAirdropResult | PendingCreateAirdropResult, Error, CreateAirdropArgs<EcdsaAirdropParams> & WriteAccountOverride & ReceiptMode>;
@@ -1,16 +1,27 @@
1
1
  import { type UseMutationResult } from "@tanstack/react-query";
2
+ import type { ReceiptMode } from "../../core/pending.js";
2
3
  import type { WriteAccountOverride } from "../airdrop-base.js";
3
- import type { CreateAirdropArgs, CreateAirdropResult, MerkleAirdropParams } from "../types.js";
4
+ import type { CreateAirdropResult, CreateMerkleAirdropArgs, PendingCreateAirdropResult } from "../types.js";
4
5
  import { type AirdropClientOptions } from "./_shared.js";
5
6
  /**
6
7
  * Deploy a Merkle-proof airdrop instance via the factory.
7
8
  *
8
- * Returns the headless client's `CreateAirdropResult` unchanged — `{ hash,
9
- * airdrop, complianceManager }`.
9
+ * Returns the headless client's `CreateAirdropResult` (or `PendingCreateAirdropResult` with `waitForReceipt: false`; both carry every address) unchanged - `{ hash,
10
+ * airdrop, complianceManager, managerImplementation, complianceDelegate }`.
10
11
  *
11
- * **Invalidates:** the factory's registry reads (`useFactoryRegistry`) for
12
- * this factory address — a new instance changes `airdropCount()` /
13
- * `airdrops()`. Nothing else.
12
+ * **Safe / multisig signers:** pass `waitForReceipt: false`; see
13
+ * {@link ReceiptMode}.
14
+ *
15
+ * **Invalidates:** the factory's registry pages, every cached `isAirdrop` answer, every
16
+ * cached create preflight (the salt is now consumed), and the {@link useTokenOf} /
17
+ * {@link useComplianceManagerOf} entries for the new address, which may hold a zero
18
+ * read before the create.
19
+ *
20
+ * **Creating from a plan.** Pass the {@link PlannedCampaign} as `plan`, with
21
+ * `merkleRoot: plan.root`. The create then pins `plan.predictedAddress`, refuses a root that
22
+ * differs from the plan's, and refuses to send once the factory's Merkle implementation has
23
+ * moved since the plan ({@link PredictionDriftError}). `expected: { airdrop: plan.predictedAddress }`
24
+ * is the lower-level equivalent of the pin alone.
14
25
  *
15
26
  * @example
16
27
  * const create = useCreateMerkleAirdrop();
@@ -20,6 +31,15 @@ import { type AirdropClientOptions } from "./_shared.js";
20
31
  * userSalt,
21
32
  * });
22
33
  *
34
+ * @example
35
+ * // From a plan (immutable root):
36
+ * await create.mutateAsync({
37
+ * params: { ...params, merkleRoot: plan.root, isMerkleRootMutable: false },
38
+ * mode: "clone",
39
+ * userSalt,
40
+ * plan,
41
+ * });
42
+ *
23
43
  * @alpha
24
44
  */
25
- export declare function useCreateMerkleAirdrop(options?: AirdropClientOptions): UseMutationResult<CreateAirdropResult, Error, CreateAirdropArgs<MerkleAirdropParams> & WriteAccountOverride>;
45
+ export declare function useCreateMerkleAirdrop(options?: AirdropClientOptions): UseMutationResult<CreateAirdropResult | PendingCreateAirdropResult, Error, CreateMerkleAirdropArgs & WriteAccountOverride & ReceiptMode>;
@@ -0,0 +1,16 @@
1
+ import { type UseQueryResult } from "@tanstack/react-query";
2
+ import type { DedupMode } from "../constants.js";
3
+ import { type AirdropInstanceHookOptions } from "./_shared.js";
4
+ /** @alpha */
5
+ export type UseDedupModeArgs = AirdropInstanceHookOptions<DedupMode>;
6
+ /**
7
+ * Read an ECDSA airdrop instance's replay-protection policy from the chain.
8
+ *
9
+ * The mode is frozen at creation, so `staleTime: Infinity`.
10
+ *
11
+ * @example
12
+ * const { data: mode } = useDedupMode({ address: airdropAddress });
13
+ *
14
+ * @alpha
15
+ */
16
+ export declare function useDedupMode(args: UseDedupModeArgs): UseQueryResult<DedupMode, Error>;
@@ -18,9 +18,10 @@ export interface UseDiscloseHandleToPartyArgs extends WriteAccountOverride {
18
18
  * returns the transaction hash rather than an `EncryptedViewResult`; there is
19
19
  * no ACL event to parse.
20
20
  *
21
- * Two gates apply on-chain: the caller must itself be allowed on `handle`
22
- * (bypassed by `DISCLOSURE_ADMIN_ROLE`), and the *instance* must be allowed on
23
- * it, so a handle minted by an unrelated contract cannot be laundered through
21
+ * Two gates apply on-chain: the handle must be persistently user-decryptable by
22
+ * the caller in this instance's context (a transient allowance from a fresh FHE op
23
+ * does not count; `DISCLOSURE_ADMIN_ROLE` bypasses this gate), and the *instance*
24
+ * must be allowed on it, so a handle minted by an unrelated contract cannot be laundered through
24
25
  * this campaign. A failure of the first surfaces as `FheHandleNotAllowedError`.
25
26
  *
26
27
  * **Invalidates:** nothing. ACL is append-only and no read hook in this
@@ -6,9 +6,11 @@ import { type EcdsaAirdropInstanceClientOptions } from "./_shared.js";
6
6
  * Claim a signed encrypted allocation on an `ECDSAConfidentialAirdrop`
7
7
  * instance.
8
8
  *
9
- * `dedupMode` must be supplied — the contract has no on-chain getter for it
10
- * (see {@link EcdsaAirdropClientConfig.dedupMode}); pass the same value used
11
- * at `createEcdsaAirdrop` time.
9
+ * An empty `inputProof` is accepted only for a zero handle or one the sender and the
10
+ * instance already hold ACL on; see `EcdsaClaimArgs.encryptedInput`.
11
+ *
12
+ * `dedupMode` is deprecated - no call branches on it. Read the
13
+ * instance's actual policy with `useDedupMode`.
12
14
  *
13
15
  * **Invalidates:** the `fn "isSignatureValid"` PREFIX for this instance. A successful
14
16
  * claim consumes the EIP-712 digest, so every cached signature check on this instance
@@ -16,7 +18,7 @@ import { type EcdsaAirdropInstanceClientOptions } from "./_shared.js";
16
18
  * that can no longer be claimed. Per-claim dedup state itself remains unqueryable.
17
19
  *
18
20
  * @example
19
- * const claim = useEcdsaClaim({ address: airdropAddress, dedupMode: "perAddress" });
21
+ * const claim = useEcdsaClaim({ address: airdropAddress });
20
22
  * await claim.mutateAsync({ encryptedInput, dedupId, deadline, signer, signature });
21
23
  *
22
24
  * @alpha
@@ -8,18 +8,25 @@ import { type EcdsaAirdropInstanceClientOptions } from "./_shared.js";
8
8
  *
9
9
  * Reverts {@link FeatureDisabledError} on a non-unwrappable campaign - gate the button
10
10
  * on `useAirdropConfig().unwrappable`. Consumes the same replay guards and EIP-712
11
- * digest as {@link useEcdsaClaim}.
11
+ * digest as {@link useEcdsaClaim}, and the same empty-proof rule.
12
12
  *
13
- * `dedupMode` must be supplied - the contract has no on-chain getter for it; pass the
14
- * same value used at `createEcdsaAirdrop` time.
13
+ * **The amount is public from the claim transaction.** With the stock wrapper the unwrapped
14
+ * amount is publicly decryptable at once (the emitted `unwrapRequestId` is its handle);
15
+ * `finalizeUnwrap` only releases the ERC-20. Only a plain claim keeps it confidential.
15
16
  *
16
- * **Invalidates:** nothing, mirroring {@link useEcdsaClaim}. Replay consumption is not
17
- * queryable, so no cached read in this subpath tracks the state a successful claim
18
- * changes. `useIsSignatureValid` DOES flip to `false` once the digest is consumed, but
19
- * it is not invalidated from here - refetch it yourself after a claim.
17
+ * `dedupMode` is deprecated - no call branches on it. Read the
18
+ * instance's actual policy with `useDedupMode`.
19
+ *
20
+ * Resolves to the claim's transaction hash; the underlying ERC-20 moves only at the
21
+ * wrapper's later `finalizeUnwrap`. Pass the hash to `useUnwrapRequest` for the
22
+ * `unwrapRequestId` that call takes.
23
+ *
24
+ * **Invalidates:** the `fn "isSignatureValid"` PREFIX for this instance, exactly as
25
+ * {@link useEcdsaClaim} does: the claim consumes the EIP-712 digest, so a cached `true`
26
+ * is now a guaranteed replay. Per-claim dedup state itself remains unqueryable.
20
27
  *
21
28
  * @example
22
- * const unwrapClaim = useEcdsaClaimAndUnwrap({ address: airdropAddress, dedupMode: "perAddress" });
29
+ * const unwrapClaim = useEcdsaClaimAndUnwrap({ address: airdropAddress });
23
30
  * await unwrapClaim.mutateAsync({ encryptedInput, dedupId, deadline, signer, signature, to });
24
31
  *
25
32
  * @alpha
@@ -33,7 +33,7 @@ export type UseEcdsaDomainArgs = EcdsaAirdropInstanceHookOptions<EcdsaDomain>;
33
33
  * All three are bytecode/deploy constants, so `staleTime: Infinity`.
34
34
  *
35
35
  * @example
36
- * const { data } = useEcdsaDomain({ address: airdropAddress, dedupMode: "perAddress" });
36
+ * const { data } = useEcdsaDomain({ address: airdropAddress });
37
37
  * const built = data?.claimTypehash === CLAIM_TYPEHASH;
38
38
  *
39
39
  * @alpha
@@ -1,6 +1,6 @@
1
1
  import { type UseMutationResult } from "@tanstack/react-query";
2
2
  import type { Address } from "viem";
3
- import { type CampaignSubmitterOption, type EncryptedCampaignLeaf } from "../campaign.js";
3
+ import { type EncryptedCampaignLeaf } from "../campaign.js";
4
4
  import { type EncryptorSource } from "../encryption.js";
5
5
  import type { CampaignRecipient } from "../types.js";
6
6
  /**
@@ -22,7 +22,7 @@ export interface UseEncryptCampaignAmountsOptions {
22
22
  *
23
23
  * @alpha
24
24
  */
25
- export interface UseEncryptCampaignAmountsArgs extends CampaignSubmitterOption {
25
+ export interface UseEncryptCampaignAmountsArgs {
26
26
  /** The LIVE `MerkleConfidentialAirdrop` instance every input is bound to. Not the factory, not the implementation. */
27
27
  instance: Address;
28
28
  /** CUMULATIVE totals per account, never per-drop tranches. */
@@ -38,11 +38,9 @@ export interface UseEncryptCampaignAmountsArgs extends CampaignSubmitterOption {
38
38
  * cache identity to key. **Persist what resolves** — nothing here is
39
39
  * recoverable or reproducible.
40
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.
41
+ * One relayer request per 32 recipients, issued concurrently; every leaf is
42
+ * submittable by any address. Split the roster yourself if your relayer
43
+ * rate-limits.
46
44
  *
47
45
  * **Invalidates:** nothing. Pure off-chain relayer work — no contract state
48
46
  * moves, so no cached read goes stale.
@@ -8,7 +8,10 @@ import { type AirdropInstanceClientOptions } from "./_shared.js";
8
8
  * `canExtendClaimWindow: true`.
9
9
  *
10
10
  * **Invalidates:** only this instance's `useAirdropWindow` entry — `endTime`
11
- * is one of the five fields that hook bundles.
11
+ * is one of the five fields that hook bundles. Not invalidated: the window
12
+ * blockers of {@link usePreflightClaim} and a cached `false` from
13
+ * {@link useIsSignatureValid}, both of which a later `endTime` can move; refetch
14
+ * them if the same session renders a claim form.
12
15
  *
13
16
  * @example
14
17
  * const extend = useExtendClaimWindow({ address: airdropAddress });