@tokenops/sdk 2.0.0-alpha.1 → 2.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +67 -2
- package/README.md +14 -8
- package/dist/{chunk-PUX5VXDB.cjs → chunk-4AWQJQXY.cjs} +1415 -69
- package/dist/{chunk-74QFZ5MK.js → chunk-4IB4IY5Y.js} +1 -1
- package/dist/{chunk-DZHYSUGY.js → chunk-6HCT4QIX.js} +12 -5
- package/dist/{chunk-FGEB7RMY.cjs → chunk-6XOAYDC6.cjs} +4 -4
- package/dist/{chunk-XAYGD4E4.cjs → chunk-AHU2HMNE.cjs} +3 -3
- package/dist/{chunk-6NAVMWZQ.js → chunk-BPIVVCSQ.js} +2 -2
- package/dist/{chunk-GKKDAW44.js → chunk-BXX5TETM.js} +1401 -59
- package/dist/{chunk-456VDDA3.js → chunk-GCJFAY4X.js} +78 -25
- package/dist/{chunk-CTED3MTR.cjs → chunk-GKYZQJGP.cjs} +82 -29
- package/dist/{chunk-JZLGCTGK.cjs → chunk-IEKTGJ4J.cjs} +2 -2
- package/dist/{chunk-6PXXGACR.cjs → chunk-JVNJSDQ4.cjs} +2 -2
- package/dist/{chunk-O5676ZWY.js → chunk-LEYYG4RF.js} +232 -6
- package/dist/{chunk-335Z2W67.js → chunk-NGU4JYIR.js} +1 -1
- package/dist/{chunk-5576FRT3.cjs → chunk-PG3WXT3K.cjs} +12 -5
- package/dist/{chunk-H5POPGOZ.js → chunk-PK6Q6J5F.js} +1 -1
- package/dist/chunk-TND5NDV7.cjs +263 -0
- package/dist/chunk-U3TBQRT7.js +253 -0
- package/dist/{chunk-EAJ7SYHE.js → chunk-WRWRA4TN.js} +1 -1
- package/dist/{chunk-JQYC66TO.cjs → chunk-YABHXJNH.cjs} +5 -5
- package/dist/{chunk-M4IT6DNJ.cjs → chunk-YTIYTV4K.cjs} +236 -4
- package/dist/core/addresses.d.ts +4 -4
- package/dist/core/errors.d.ts +1 -1
- package/dist/fhe/types.d.ts +2 -2
- package/dist/fhe-airdrop/abis/airdrop-base.d.ts +19 -0
- package/dist/fhe-airdrop/abis/ecdsa.d.ts +19 -0
- package/dist/fhe-airdrop/abis/factory.d.ts +113 -0
- package/dist/fhe-airdrop/abis/merkle.d.ts +43 -12
- package/dist/fhe-airdrop/advanced/index.cjs +4 -4
- package/dist/fhe-airdrop/advanced/index.js +1 -1
- package/dist/fhe-airdrop/advanced/react/index.cjs +620 -9
- package/dist/fhe-airdrop/advanced/react/index.d.cts +35 -0
- package/dist/fhe-airdrop/advanced/react/index.d.ts +35 -0
- package/dist/fhe-airdrop/advanced/react/index.js +590 -7
- package/dist/fhe-airdrop/advanced/react/useClearCompliancePolicy.d.ts +28 -0
- package/dist/fhe-airdrop/advanced/react/useClearUpgradeabilityPolicy.d.ts +26 -0
- package/dist/fhe-airdrop/advanced/react/useDisableCustomFee.d.ts +26 -0
- package/dist/fhe-airdrop/advanced/react/useEcdsaInitCodeHash.d.ts +30 -0
- package/dist/fhe-airdrop/advanced/react/useFactoryComplianceDelegate.d.ts +25 -0
- package/dist/fhe-airdrop/advanced/react/useFactoryCompliancePolicy.d.ts +38 -0
- package/dist/fhe-airdrop/advanced/react/useFactoryCustomFee.d.ts +24 -0
- package/dist/fhe-airdrop/advanced/react/useFactoryGrantRole.d.ts +32 -0
- package/dist/fhe-airdrop/advanced/react/useFactoryHasRole.d.ts +27 -0
- package/dist/fhe-airdrop/advanced/react/useFactoryImplementations.d.ts +33 -0
- package/dist/fhe-airdrop/advanced/react/useFactoryRenounceRole.d.ts +37 -0
- package/dist/fhe-airdrop/advanced/react/useFactoryRevokeRole.d.ts +37 -0
- package/dist/fhe-airdrop/advanced/react/useFactoryRoleConstants.d.ts +46 -0
- package/dist/fhe-airdrop/advanced/react/useFactoryRoleMembers.d.ts +48 -0
- package/dist/fhe-airdrop/advanced/react/useFactoryUpgradeabilityPolicy.d.ts +39 -0
- package/dist/fhe-airdrop/advanced/react/useMerkleInitCodeHash.d.ts +24 -0
- package/dist/fhe-airdrop/advanced/react/useSetComplianceDelegate.d.ts +33 -0
- package/dist/fhe-airdrop/advanced/react/useSetComplianceManagerImpl.d.ts +27 -0
- package/dist/fhe-airdrop/advanced/react/useSetCompliancePolicy.d.ts +28 -0
- package/dist/fhe-airdrop/advanced/react/useSetCustomFee.d.ts +29 -0
- package/dist/fhe-airdrop/advanced/react/useSetDefaultDelegateToCompliance.d.ts +31 -0
- package/dist/fhe-airdrop/advanced/react/useSetDefaultGasFee.d.ts +30 -0
- package/dist/fhe-airdrop/advanced/react/useSetDefaultUpgradeable.d.ts +27 -0
- package/dist/fhe-airdrop/advanced/react/useSetEcdsaImplementation.d.ts +34 -0
- package/dist/fhe-airdrop/advanced/react/useSetFeeCollector.d.ts +27 -0
- package/dist/fhe-airdrop/advanced/react/useSetMaxGasFee.d.ts +33 -0
- package/dist/fhe-airdrop/advanced/react/useSetMerkleImplementation.d.ts +30 -0
- package/dist/fhe-airdrop/advanced/react/useSetUpgradeabilityPolicy.d.ts +31 -0
- package/dist/fhe-airdrop/airdrop-base.d.ts +55 -8
- package/dist/fhe-airdrop/campaign.d.ts +61 -20
- package/dist/fhe-airdrop/constants.d.ts +9 -1
- package/dist/fhe-airdrop/ecdsa.d.ts +13 -0
- package/dist/fhe-airdrop/errors.d.ts +87 -0
- package/dist/fhe-airdrop/factory.d.ts +62 -22
- package/dist/fhe-airdrop/guards.d.ts +133 -4
- package/dist/fhe-airdrop/index.cjs +86 -971
- package/dist/fhe-airdrop/index.d.cts +4 -4
- package/dist/fhe-airdrop/index.d.ts +4 -4
- package/dist/fhe-airdrop/index.js +8 -927
- package/dist/fhe-airdrop/merkle-tree.d.ts +32 -38
- package/dist/fhe-airdrop/merkle.d.ts +52 -31
- package/dist/fhe-airdrop/react/_shared.d.ts +13 -0
- package/dist/fhe-airdrop/react/index.cjs +997 -87
- package/dist/fhe-airdrop/react/index.d.cts +53 -4
- package/dist/fhe-airdrop/react/index.d.ts +53 -4
- package/dist/fhe-airdrop/react/index.js +887 -27
- package/dist/fhe-airdrop/react/keys.d.ts +98 -0
- package/dist/fhe-airdrop/react/useAccessEcdsaClaimAmount.d.ts +26 -0
- package/dist/fhe-airdrop/react/useAccessMerkleClaimAmount.d.ts +27 -0
- package/dist/fhe-airdrop/react/useAddComplianceDelegate.d.ts +37 -0
- package/dist/fhe-airdrop/react/useAdminBatchDiscloseBalanceToParties.d.ts +36 -0
- package/dist/fhe-airdrop/react/useAdminDiscloseBalanceToParty.d.ts +31 -0
- package/dist/fhe-airdrop/react/useAdminGetCurrentBalance.d.ts +27 -0
- package/dist/fhe-airdrop/react/useAirdropConfig.d.ts +49 -0
- package/dist/fhe-airdrop/react/useAirdropDeploymentMode.d.ts +28 -0
- package/dist/fhe-airdrop/react/useAirdropGrantRole.d.ts +35 -0
- package/dist/fhe-airdrop/react/useAirdropRenounceRole.d.ts +36 -0
- package/dist/fhe-airdrop/react/useAirdropRevokeRole.d.ts +33 -0
- package/dist/fhe-airdrop/react/useAirdropRoleAdmin.d.ts +28 -0
- package/dist/fhe-airdrop/react/useAirdropRoleConstants.d.ts +67 -0
- package/dist/fhe-airdrop/react/useAirdropRoleMembers.d.ts +49 -0
- package/dist/fhe-airdrop/react/useAirdropUpgradeToAndCall.d.ts +45 -0
- package/dist/fhe-airdrop/react/useBatchDiscloseHandlesToParty.d.ts +32 -0
- package/dist/fhe-airdrop/react/useBuildMerkleCampaign.d.ts +68 -0
- package/dist/fhe-airdrop/react/useComplianceGrantRole.d.ts +32 -0
- package/dist/fhe-airdrop/react/useComplianceHasRole.d.ts +37 -0
- package/dist/fhe-airdrop/react/useComplianceInfo.d.ts +50 -0
- package/dist/fhe-airdrop/react/useComplianceManagerOf.d.ts +32 -0
- package/dist/fhe-airdrop/react/useComplianceRenounceRole.d.ts +38 -0
- package/dist/fhe-airdrop/react/useComplianceRevokeRole.d.ts +36 -0
- package/dist/fhe-airdrop/react/useComplianceRoleConstants.d.ts +41 -0
- package/dist/fhe-airdrop/react/useComplianceRoleMembers.d.ts +45 -0
- package/dist/fhe-airdrop/react/useCreateAndFundEcdsaAirdrop.d.ts +55 -0
- package/dist/fhe-airdrop/react/useCreateAndFundMerkleAirdrop.d.ts +52 -0
- package/dist/fhe-airdrop/react/useDiscloseHandleToParty.d.ts +35 -0
- package/dist/fhe-airdrop/react/useEcdsaClaim.d.ts +4 -3
- package/dist/fhe-airdrop/react/useEcdsaClaimAndUnwrap.d.ts +27 -0
- package/dist/fhe-airdrop/react/useEcdsaDomain.d.ts +41 -0
- package/dist/fhe-airdrop/react/useEffectiveDelegateToCompliance.d.ts +26 -0
- package/dist/fhe-airdrop/react/useEncryptCampaignAmounts.d.ts +59 -0
- package/dist/fhe-airdrop/react/useFactoryFees.d.ts +11 -4
- package/dist/fhe-airdrop/react/useIsActiveDelegate.d.ts +29 -0
- package/dist/fhe-airdrop/react/useIsAirdrop.d.ts +44 -0
- package/dist/fhe-airdrop/react/useIsMerkleRootMutable.d.ts +21 -0
- package/dist/fhe-airdrop/react/useIsSignatureValid.d.ts +46 -0
- package/dist/fhe-airdrop/react/useMerkleClaim.d.ts +7 -19
- package/dist/fhe-airdrop/react/useMerkleClaimAndUnwrap.d.ts +29 -0
- package/dist/fhe-airdrop/react/usePlanMerkleCampaign.d.ts +53 -0
- package/dist/fhe-airdrop/react/usePreflightClaim.d.ts +46 -0
- package/dist/fhe-airdrop/react/usePreflightCreateAirdrop.d.ts +67 -0
- package/dist/fhe-airdrop/react/useRefreshComplianceBalance.d.ts +36 -0
- package/dist/fhe-airdrop/react/useRescueERC20.d.ts +30 -0
- package/dist/fhe-airdrop/react/useRescueOtherConfidentialToken.d.ts +34 -0
- package/dist/fhe-airdrop/react/useResolveGasFee.d.ts +30 -0
- package/dist/fhe-airdrop/react/useRevokeComplianceDelegate.d.ts +37 -0
- package/dist/fhe-airdrop/react/useRotateMerkleRoot.d.ts +52 -0
- package/dist/fhe-airdrop/react/useSignClaimAuthorization.d.ts +42 -0
- package/dist/fhe-airdrop/react/useWithdrawGasFee.d.ts +37 -0
- package/dist/fhe-airdrop/types.d.ts +27 -1
- package/dist/fhe-disperse/index.cjs +21 -21
- package/dist/fhe-disperse/index.js +2 -2
- package/dist/fhe-disperse/react/index.cjs +22 -22
- package/dist/fhe-disperse/react/index.js +3 -3
- package/dist/fhe-vesting/advanced/index.cjs +5 -5
- package/dist/fhe-vesting/advanced/index.js +3 -3
- package/dist/fhe-vesting/advanced/react/index.cjs +7 -7
- package/dist/fhe-vesting/advanced/react/index.js +4 -4
- package/dist/fhe-vesting/index.cjs +8 -8
- package/dist/fhe-vesting/index.js +2 -2
- package/dist/fhe-vesting/react/index.cjs +114 -114
- package/dist/fhe-vesting/react/index.js +3 -3
- package/dist/index.cjs +18 -18
- package/dist/index.js +1 -1
- package/dist/testnet-faucet/index.cjs +14 -14
- package/dist/testnet-faucet/index.js +2 -2
- package/dist/testnet-faucet/react/index.cjs +8 -8
- package/dist/testnet-faucet/react/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-NCVX3K2N.cjs +0 -161
- 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>;
|
|
@@ -11,14 +11,21 @@ export interface FactoryFees {
|
|
|
11
11
|
feeCollector: Address;
|
|
12
12
|
/** Wei charged per claim on a fee-charging campaign, absent a per-creator custom fee. */
|
|
13
13
|
defaultGasFee: bigint;
|
|
14
|
+
/**
|
|
15
|
+
* The factory's own ceiling, in wei. Bounds both fee setters and the fee
|
|
16
|
+
* resolved at create, so it is the upper bound a `maxAcceptedGasFee` ever
|
|
17
|
+
* has to clear.
|
|
18
|
+
*/
|
|
19
|
+
maxGasFee: bigint;
|
|
14
20
|
}
|
|
15
21
|
/** @alpha */
|
|
16
22
|
export type UseFactoryFeesArgs = AirdropHookOptions<FactoryFees>;
|
|
17
23
|
/**
|
|
18
|
-
* Read the airdrop factory's
|
|
19
|
-
* `defaultGasFee` in one round trip. For a specific
|
|
20
|
-
*
|
|
21
|
-
*
|
|
24
|
+
* Read the airdrop factory's chain-wide fee configuration: `feeCollector`,
|
|
25
|
+
* `defaultGasFee` and `maxGasFee` in one round trip. For the number a specific
|
|
26
|
+
* creator's `maxAcceptedGasFee` is actually checked against, use
|
|
27
|
+
* `factory.resolveGasFee(creator)` from the headless client: it folds in that
|
|
28
|
+
* creator's `getCustomFee` override, which this hook does not read.
|
|
22
29
|
*
|
|
23
30
|
* @example
|
|
24
31
|
* const { data: fees } = useFactoryFees();
|
|
@@ -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,44 @@
|
|
|
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 UseIsAirdropArgs extends AirdropHookOptions<boolean> {
|
|
6
|
+
/** The address to check against the factory's registry. */
|
|
7
|
+
candidate?: Address;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Ask the canonical factory whether it created `candidate` - the genuineness
|
|
11
|
+
* check (audit-10).
|
|
12
|
+
*
|
|
13
|
+
* **Run this before trusting an address a user pasted, a link carried, or an
|
|
14
|
+
* indexer returned.** A look-alike instance with the same ABI, the same events
|
|
15
|
+
* and a pool the attacker controls is cheap to deploy, and nothing readable at
|
|
16
|
+
* the instance tells it apart. A claim against one succeeds and delivers
|
|
17
|
+
* nothing.
|
|
18
|
+
*
|
|
19
|
+
* The factory this asks is the one resolved from `src/core/addresses.ts` for
|
|
20
|
+
* the connected chain, which is what makes the answer worth anything: an
|
|
21
|
+
* instance that names its own factory names a fake one.
|
|
22
|
+
*
|
|
23
|
+
* **Only a `true` is cached.** The registry is append-only, so a `true` can
|
|
24
|
+
* never become `false` and is safe to hold forever. A `false` is not stable:
|
|
25
|
+
* the address can be created later by another tab, another service, or the
|
|
26
|
+
* headless client, none of which reaches this hook's invalidations - so caching
|
|
27
|
+
* it would serve a stale false negative indefinitely and, for a security check,
|
|
28
|
+
* in the direction that blocks a legitimate claim. Negative answers therefore
|
|
29
|
+
* stay fresh and refetch normally. Override either with `query.staleTime`.
|
|
30
|
+
*
|
|
31
|
+
* **The `address` override is the trust root.** Like every factory hook this
|
|
32
|
+
* accepts `address`, and `useMemoAirdropFactoryClient` prefers it over
|
|
33
|
+
* `src/core/addresses.ts`. That is what makes the hook usable on a local chain,
|
|
34
|
+
* but it also means an attacker-supplied factory address would answer `true`
|
|
35
|
+
* for its own look-alike. Pass `address` only from a source you trust at least
|
|
36
|
+
* as much as the registry; when in doubt, omit it.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* const { data: genuine } = useIsAirdrop({ candidate: fromUrl });
|
|
40
|
+
* if (genuine === false) return <Warning address={fromUrl} />;
|
|
41
|
+
*
|
|
42
|
+
* @alpha
|
|
43
|
+
*/
|
|
44
|
+
export declare function useIsAirdrop(args?: UseIsAirdropArgs): 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:**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
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,36 @@
|
|
|
1
|
+
import { type UseMutationResult } from "@tanstack/react-query";
|
|
2
|
+
import type { EncryptedViewResult } from "../../fhe/types.js";
|
|
3
|
+
import type { WriteAccountOverride } from "../airdrop-base.js";
|
|
4
|
+
import { type AirdropInstanceClientOptions } from "./_shared.js";
|
|
5
|
+
/**
|
|
6
|
+
* **Submits a transaction.** Re-grants the compliance-manager clone on the
|
|
7
|
+
* instance's current pool balance and returns the handle it was granted on.
|
|
8
|
+
*
|
|
9
|
+
* **Permissionless** (audit-04), unlike every other disclosure hook here. The
|
|
10
|
+
* token rotates the instance's balance handle on every incoming transfer,
|
|
11
|
+
* including a direct one no airdrop code observes, and the clone's existing
|
|
12
|
+
* grant does not follow. Anyone may restore it because there is no argument to
|
|
13
|
+
* abuse: the only handle read is the instance's own balance and the only
|
|
14
|
+
* grantee is the clone wired at initialization.
|
|
15
|
+
*
|
|
16
|
+
* The handle comes from the receipt's ACL `Allowed` event naming the CLONE, not
|
|
17
|
+
* the caller - so unless the connected account is the clone, it cannot decrypt
|
|
18
|
+
* what this returns. That is also why it is a mutation: the entrypoint calls
|
|
19
|
+
* `FHE.allow`, so its handle can never come from a simulation (CLAUDE.md
|
|
20
|
+
* Pitfall #1).
|
|
21
|
+
*
|
|
22
|
+
* **A snapshot, not a subscription.** The handle stays readable forever (ACL is
|
|
23
|
+
* append-only), but the next incoming transfer rotates the instance onto a new
|
|
24
|
+
* handle the clone was never granted on. Re-run this after any transfer in.
|
|
25
|
+
*
|
|
26
|
+
* **Invalidates:** nothing, and nothing invalidates it - a mutation result is
|
|
27
|
+
* not a cache entry, so no write can refresh it. Re-run it yourself after
|
|
28
|
+
* `useFundAirdrop` or `useWithdrawConfidential`.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* const refresh = useRefreshComplianceBalance({ address: airdropAddress });
|
|
32
|
+
* const { handle } = await refresh.mutateAsync();
|
|
33
|
+
*
|
|
34
|
+
* @alpha
|
|
35
|
+
*/
|
|
36
|
+
export declare function useRefreshComplianceBalance(options: AirdropInstanceClientOptions): UseMutationResult<EncryptedViewResult, Error, WriteAccountOverride | void>;
|
|
@@ -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>;
|