@tokenops/sdk 2.0.0-alpha.2 → 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.
- package/CHANGELOG.md +92 -3
- package/README.md +76 -34
- package/SUPPORT.md +1 -1
- package/dist/{chunk-PYYSB5ZN.js → chunk-2ND7US2I.js} +1 -1
- package/dist/{chunk-EYDA6Q6C.js → chunk-3ZSPRHR3.js} +63 -12
- package/dist/{chunk-X7WBPCEU.js → chunk-67Q6KSVV.js} +4578 -3383
- package/dist/{chunk-UHHMVBLU.cjs → chunk-6AYJRUGP.cjs} +7 -50
- package/dist/{chunk-FEDX7B6T.cjs → chunk-6FUHF73F.cjs} +5 -5
- package/dist/{chunk-NWFMBLSQ.js → chunk-7KY4K4PH.js} +1 -1
- package/dist/{chunk-FHWSBGWE.cjs → chunk-ARZ5C3FS.cjs} +7 -7
- package/dist/{chunk-SPLNGUFF.js → chunk-AX6MQAWU.js} +2 -2
- package/dist/{chunk-IGO5XSPS.js → chunk-BSXEX2SH.js} +3 -3
- package/dist/{chunk-44YJPMQC.js → chunk-CHGY6B7L.js} +34 -81
- package/dist/{chunk-IUKKNJ2R.cjs → chunk-DFK5GCJP.cjs} +55 -72
- package/dist/{chunk-PZZK3O3S.cjs → chunk-E4IV4M4E.cjs} +4598 -3403
- package/dist/{chunk-A4DCEE33.js → chunk-GHGF65LN.js} +16 -12
- package/dist/{chunk-TWT3STIX.js → chunk-K3R27WX4.js} +8 -46
- package/dist/{chunk-GADGBQJO.js → chunk-KJUNBOJQ.js} +52 -71
- package/dist/{chunk-MM5BV5CS.cjs → chunk-PO3A2AQX.cjs} +4 -4
- package/dist/{chunk-EBLBPUPI.cjs → chunk-QHDMPT7I.cjs} +72 -19
- package/dist/{chunk-3YHBO2DL.cjs → chunk-S47IBDTA.cjs} +36 -83
- package/dist/{chunk-UG5RKLU2.cjs → chunk-SUYBAF27.cjs} +1 -1
- package/dist/{chunk-WJMEBBU7.js → chunk-TWU7L5H7.js} +5 -48
- package/dist/{chunk-WJLECC22.cjs → chunk-UUSSWOPR.cjs} +9 -47
- package/dist/{chunk-AREQJHKA.cjs → chunk-VHKMWWBA.cjs} +428 -22
- package/dist/{chunk-FT5H2Q7Y.cjs → chunk-YAL6JSAZ.cjs} +16 -12
- package/dist/{chunk-VW356KR3.js → chunk-YMWMIWBP.js} +421 -25
- package/dist/core/addresses.d.ts +4 -4
- package/dist/core/errors.d.ts +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/pending.d.ts +57 -0
- package/dist/core/version.d.ts +1 -1
- package/dist/fhe/operators.d.ts +6 -5
- package/dist/fhe/types.d.ts +1 -1
- package/dist/fhe-airdrop/abis/airdrop-base.d.ts +97 -1
- package/dist/fhe-airdrop/abis/ecdsa.d.ts +117 -1
- package/dist/fhe-airdrop/abis/factory.d.ts +332 -1
- package/dist/fhe-airdrop/abis/merkle.d.ts +116 -1
- package/dist/fhe-airdrop/advanced/index.cjs +8 -4
- package/dist/fhe-airdrop/advanced/index.d.cts +1 -0
- package/dist/fhe-airdrop/advanced/index.d.ts +1 -0
- package/dist/fhe-airdrop/advanced/index.js +1 -1
- package/dist/fhe-airdrop/advanced/react/index.cjs +145 -137
- package/dist/fhe-airdrop/advanced/react/index.d.cts +1 -0
- package/dist/fhe-airdrop/advanced/react/index.d.ts +1 -0
- package/dist/fhe-airdrop/advanced/react/index.js +85 -78
- package/dist/fhe-airdrop/advanced/react/useClearCompliancePolicy.d.ts +3 -1
- package/dist/fhe-airdrop/advanced/react/useDisableCustomFee.d.ts +4 -1
- package/dist/fhe-airdrop/advanced/react/useFactoryComplianceDelegate.d.ts +2 -4
- package/dist/fhe-airdrop/advanced/react/useFactoryRenounceRole.d.ts +4 -3
- package/dist/fhe-airdrop/advanced/react/useFactoryRevokeRole.d.ts +9 -7
- package/dist/fhe-airdrop/advanced/react/useFactoryRoleMembers.d.ts +6 -5
- package/dist/fhe-airdrop/advanced/react/useSetComplianceDelegate.d.ts +7 -7
- package/dist/fhe-airdrop/advanced/react/useSetComplianceManagerImpl.d.ts +3 -1
- package/dist/fhe-airdrop/advanced/react/useSetCompliancePolicy.d.ts +2 -1
- package/dist/fhe-airdrop/advanced/react/useSetCustomFee.d.ts +4 -1
- package/dist/fhe-airdrop/advanced/react/useSetDefaultDelegateToCompliance.d.ts +5 -4
- package/dist/fhe-airdrop/advanced/react/useSetDefaultGasFee.d.ts +7 -3
- package/dist/fhe-airdrop/advanced/react/useSetMaxGasFee.d.ts +37 -0
- package/dist/fhe-airdrop/airdrop-base.d.ts +142 -18
- package/dist/fhe-airdrop/campaign.d.ts +37 -73
- package/dist/fhe-airdrop/compliance-clone.d.ts +21 -0
- package/dist/fhe-airdrop/constants.d.ts +11 -1
- package/dist/fhe-airdrop/ecdsa.d.ts +79 -26
- package/dist/fhe-airdrop/encryption.d.ts +19 -6
- package/dist/fhe-airdrop/errors.d.ts +136 -2
- package/dist/fhe-airdrop/factory-params.d.ts +2361 -0
- package/dist/fhe-airdrop/factory.d.ts +189 -75
- package/dist/fhe-airdrop/guards.d.ts +183 -19
- package/dist/fhe-airdrop/index.cjs +88 -56
- package/dist/fhe-airdrop/index.d.cts +12 -10
- package/dist/fhe-airdrop/index.d.ts +12 -10
- package/dist/fhe-airdrop/index.js +5 -5
- package/dist/fhe-airdrop/merkle-tree.d.ts +9 -9
- package/dist/fhe-airdrop/merkle.d.ts +32 -11
- package/dist/fhe-airdrop/react/_shared.d.ts +12 -6
- package/dist/fhe-airdrop/react/index.cjs +336 -240
- package/dist/fhe-airdrop/react/index.d.cts +19 -9
- package/dist/fhe-airdrop/react/index.d.ts +19 -9
- package/dist/fhe-airdrop/react/index.js +158 -97
- package/dist/fhe-airdrop/react/keys.d.ts +54 -7
- package/dist/fhe-airdrop/react/useAccessEcdsaClaimAmount.d.ts +6 -3
- package/dist/fhe-airdrop/react/useAccessMerkleClaimAmount.d.ts +2 -2
- package/dist/fhe-airdrop/react/useAirdropConfig.d.ts +8 -3
- package/dist/fhe-airdrop/react/useAirdropPause.d.ts +5 -0
- package/dist/fhe-airdrop/react/useBuildMerkleCampaign.d.ts +4 -6
- package/dist/fhe-airdrop/react/useComplianceManager.d.ts +2 -2
- package/dist/fhe-airdrop/react/useComplianceManagerOf.d.ts +1 -2
- package/dist/fhe-airdrop/react/useCreateAndFundEcdsaAirdrop.d.ts +16 -11
- package/dist/fhe-airdrop/react/useCreateAndFundMerkleAirdrop.d.ts +23 -7
- package/dist/fhe-airdrop/react/useCreateEcdsaAirdrop.d.ts +13 -8
- package/dist/fhe-airdrop/react/useCreateMerkleAirdrop.d.ts +27 -7
- package/dist/fhe-airdrop/react/useDedupMode.d.ts +16 -0
- package/dist/fhe-airdrop/react/useDiscloseHandleToParty.d.ts +4 -3
- package/dist/fhe-airdrop/react/useEcdsaClaim.d.ts +6 -4
- package/dist/fhe-airdrop/react/useEcdsaClaimAndUnwrap.d.ts +15 -8
- package/dist/fhe-airdrop/react/useEcdsaDomain.d.ts +1 -1
- package/dist/fhe-airdrop/react/useEncryptCampaignAmounts.d.ts +5 -7
- package/dist/fhe-airdrop/react/useExtendClaimWindow.d.ts +4 -1
- package/dist/fhe-airdrop/react/useFactoryFees.d.ts +11 -4
- package/dist/fhe-airdrop/react/useFundAirdrop.d.ts +3 -4
- package/dist/fhe-airdrop/react/useGrantInstanceRoles.d.ts +2 -1
- package/dist/fhe-airdrop/react/useIsAirdrop.d.ts +44 -0
- package/dist/fhe-airdrop/react/useIsSignatureValid.d.ts +5 -4
- package/dist/fhe-airdrop/react/useMerkleClaim.d.ts +4 -1
- package/dist/fhe-airdrop/react/useMerkleClaimAndUnwrap.d.ts +14 -3
- package/dist/fhe-airdrop/react/usePlanMerkleCampaign.d.ts +18 -3
- package/dist/fhe-airdrop/react/usePreflightClaim.d.ts +1 -1
- package/dist/fhe-airdrop/react/usePreflightCreateAirdrop.d.ts +34 -13
- package/dist/fhe-airdrop/react/useRefreshComplianceBalance.d.ts +36 -0
- package/dist/fhe-airdrop/react/useRescueERC20.d.ts +3 -3
- package/dist/fhe-airdrop/react/useRescueNativeToken.d.ts +23 -0
- package/dist/fhe-airdrop/react/useResolveGasFee.d.ts +30 -0
- package/dist/fhe-airdrop/react/useRotateMerkleRoot.d.ts +5 -2
- package/dist/fhe-airdrop/react/useSignClaimAuthorization.d.ts +4 -0
- package/dist/fhe-airdrop/react/useTokenOf.d.ts +29 -0
- package/dist/fhe-airdrop/react/useUnwrapRequest.d.ts +25 -0
- package/dist/fhe-airdrop/react/useWithdrawConfidential.d.ts +4 -0
- package/dist/fhe-airdrop/roles.d.ts +82 -7
- package/dist/fhe-airdrop/types.d.ts +122 -14
- package/dist/fhe-disperse/errors.d.ts +3 -3
- package/dist/fhe-disperse/index.cjs +22 -22
- package/dist/fhe-disperse/index.d.cts +2 -1
- package/dist/fhe-disperse/index.d.ts +2 -1
- package/dist/fhe-disperse/index.js +3 -3
- package/dist/fhe-disperse/react/index.cjs +27 -25
- package/dist/fhe-disperse/react/index.d.cts +2 -1
- package/dist/fhe-disperse/react/index.d.ts +2 -1
- package/dist/fhe-disperse/react/index.js +8 -6
- package/dist/fhe-disperse/react/useDisperse.d.ts +6 -2
- package/dist/fhe-disperse/react/useRegister.d.ts +9 -3
- package/dist/fhe-disperse/react/useSingletonWithdrawTokenFee.d.ts +7 -2
- package/dist/fhe-disperse/react/useWithdrawTokenFee.d.ts +7 -2
- package/dist/fhe-disperse/singleton.d.ts +33 -19
- package/dist/fhe-disperse/types.d.ts +48 -8
- package/dist/fhe-vesting/advanced/index.cjs +6 -6
- package/dist/fhe-vesting/advanced/index.js +4 -4
- package/dist/fhe-vesting/advanced/react/index.cjs +9 -9
- package/dist/fhe-vesting/advanced/react/index.js +6 -6
- package/dist/fhe-vesting/factory.d.ts +31 -8
- package/dist/fhe-vesting/index.cjs +23 -23
- package/dist/fhe-vesting/index.d.cts +3 -2
- package/dist/fhe-vesting/index.d.ts +3 -2
- package/dist/fhe-vesting/index.js +4 -4
- package/dist/fhe-vesting/manager.d.ts +27 -2
- package/dist/fhe-vesting/react/index.cjs +126 -126
- package/dist/fhe-vesting/react/index.d.cts +3 -2
- package/dist/fhe-vesting/react/index.d.ts +3 -2
- package/dist/fhe-vesting/react/index.js +5 -5
- package/dist/fhe-vesting/react/useCreateManager.d.ts +16 -9
- package/dist/fhe-vesting/react/useCreateManagerAndGetAddress.d.ts +9 -5
- package/dist/fhe-vesting/react/useSplitVesting.d.ts +9 -3
- package/dist/index.cjs +18 -18
- package/dist/index.js +1 -1
- package/dist/testnet-faucet/faucet.d.ts +3 -0
- package/dist/testnet-faucet/index.cjs +15 -15
- package/dist/testnet-faucet/index.js +3 -3
- package/dist/testnet-faucet/react/index.cjs +9 -9
- package/dist/testnet-faucet/react/index.js +4 -4
- package/package.json +1 -1
|
@@ -7,11 +7,22 @@ import { type AirdropInstanceClientOptions } from "./_shared.js";
|
|
|
7
7
|
* wrapper's unwrap, making `to` the underlying ERC-20 beneficiary.
|
|
8
8
|
*
|
|
9
9
|
* **Self-only, unlike {@link useMerkleClaim}.** This entrypoint takes no claim identity:
|
|
10
|
-
* the leaf
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* the leaf and the accounting are both `msg.sender`, so an entry whose `account` is not
|
|
11
|
+
* the sender is refused before the write. Gate the button on `sender === entry.account`
|
|
12
|
+
* and fall back to `useMerkleClaim` for third-party claims.
|
|
13
13
|
* Also requires an unwrappable campaign - see `useAirdropConfig().unwrappable`.
|
|
14
14
|
*
|
|
15
|
+
* A third party can still settle the same entry first through `useMerkleClaim`, after
|
|
16
|
+
* which an unwrap pays an encrypted zero; see {@link MerkleClaimArgs.entry}.
|
|
17
|
+
*
|
|
18
|
+
* **The amount is public from the claim transaction.** With the stock wrapper the unwrapped
|
|
19
|
+
* amount is publicly decryptable at once (the emitted `unwrapRequestId` is its handle);
|
|
20
|
+
* `finalizeUnwrap` only releases the ERC-20. Only a plain claim keeps it confidential.
|
|
21
|
+
*
|
|
22
|
+
* Resolves to the claim's transaction hash; the underlying ERC-20 moves only at the
|
|
23
|
+
* wrapper's later `finalizeUnwrap`. Pass the hash to `useUnwrapRequest` for the
|
|
24
|
+
* `unwrapRequestId` that call takes.
|
|
25
|
+
*
|
|
15
26
|
* **Invalidates:** `useClaimedAmount` for the SENDING account on this instance. The
|
|
16
27
|
* contract advances `claimedAmount[msg.sender]` here, so the key is built from the
|
|
17
28
|
* sender resolved in `onMutate` (`variables.account ?? walletClient.account`) and NOT
|
|
@@ -19,8 +19,13 @@ export type UsePlanMerkleCampaignArgs = Omit<PlanMerkleCampaignArgs, "factory" |
|
|
|
19
19
|
* hook breaks it with the factory's CREATE2 prediction oracle, then feeds
|
|
20
20
|
* `root` to {@link useCreateMerkleAirdrop} (or
|
|
21
21
|
* {@link useCreateAndFundMerkleAirdrop}) with the SAME `mode`, `creator` and
|
|
22
|
-
* `userSalt`.
|
|
23
|
-
*
|
|
22
|
+
* `userSalt`.
|
|
23
|
+
*
|
|
24
|
+
* Pass the returned plan to that create as `plan` (and to `usePreflightCreateAirdrop`). The
|
|
25
|
+
* entries are bound to `plan.predictedAddress`, so the create pins it, checks the root, and
|
|
26
|
+
* refuses to send once the factory's Merkle implementation has moved since planning
|
|
27
|
+
* ({@link PredictionDriftError}). `expected: { airdrop: plan.predictedAddress }` is the
|
|
28
|
+
* lower-level equivalent of the pin alone.
|
|
24
29
|
*
|
|
25
30
|
* **Surface {@link PredictionDriftError}, never swallow it.** It means the
|
|
26
31
|
* factory's Merkle implementation pointer moved mid-build, so every entry is
|
|
@@ -34,6 +39,9 @@ export type UsePlanMerkleCampaignArgs = Omit<PlanMerkleCampaignArgs, "factory" |
|
|
|
34
39
|
* `(variant, mode, creator, userSalt)` predict the same address however
|
|
35
40
|
* different their params.
|
|
36
41
|
*
|
|
42
|
+
* One relayer request per 32 recipients, issued concurrently; every leaf is
|
|
43
|
+
* submittable by any address.
|
|
44
|
+
*
|
|
37
45
|
* **Invalidates:** nothing. Two init-code-hash reads and a prediction — no
|
|
38
46
|
* state moves until the create lands.
|
|
39
47
|
*
|
|
@@ -44,9 +52,16 @@ export type UsePlanMerkleCampaignArgs = Omit<PlanMerkleCampaignArgs, "factory" |
|
|
|
44
52
|
*
|
|
45
53
|
* @example
|
|
46
54
|
* const plan = usePlanMerkleCampaign({ encryptor: () => sdk.relayer });
|
|
47
|
-
* const
|
|
55
|
+
* const create = useCreateMerkleAirdrop();
|
|
56
|
+
* const planned = await plan.mutateAsync({
|
|
48
57
|
* params, mode: "clone", creator, userSalt, recipients,
|
|
49
58
|
* });
|
|
59
|
+
* await create.mutateAsync({
|
|
60
|
+
* params: { ...params, merkleRoot: planned.root, isMerkleRootMutable: false },
|
|
61
|
+
* mode: "clone",
|
|
62
|
+
* userSalt,
|
|
63
|
+
* plan: planned,
|
|
64
|
+
* });
|
|
50
65
|
*
|
|
51
66
|
* @alpha
|
|
52
67
|
*/
|
|
@@ -13,7 +13,7 @@ export interface UsePreflightClaimArgs extends AirdropInstanceHookOptions<Prefli
|
|
|
13
13
|
dedupMode?: DedupMode;
|
|
14
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
15
|
claimant?: Address;
|
|
16
|
-
/** Merkle campaigns only: the claim identity, when it is not the
|
|
16
|
+
/** Merkle campaigns only: the claim identity, when it is not the sender. Defaults to `claimant`. Any address may send a Merkle claim; only the account itself may redirect with `to`. */
|
|
17
17
|
account?: Address;
|
|
18
18
|
/** The payout destination, if one will be passed. */
|
|
19
19
|
to?: Address;
|
|
@@ -1,21 +1,30 @@
|
|
|
1
1
|
import { type UseQueryResult } from "@tanstack/react-query";
|
|
2
2
|
import type { Address, Hex } from "viem";
|
|
3
|
-
import type { PreflightResult } from "../../core/preflight.js";
|
|
4
3
|
import type { DeploymentMode } from "../constants.js";
|
|
5
|
-
import
|
|
4
|
+
import { type PreflightCreateResult } from "../guards.js";
|
|
5
|
+
import type { CreateCommitments, EcdsaAirdropParams, MerkleAirdropParams, PlannedCampaign } from "../types.js";
|
|
6
6
|
import { type AirdropHookOptions } from "./_shared.js";
|
|
7
7
|
/** The variant-independent half of {@link UsePreflightCreateAirdropArgs}. */
|
|
8
8
|
/** @alpha */
|
|
9
|
-
export interface PreflightCreateAirdropCommon extends AirdropHookOptions<
|
|
9
|
+
export interface PreflightCreateAirdropCommon extends AirdropHookOptions<PreflightCreateResult> {
|
|
10
10
|
mode?: DeploymentMode;
|
|
11
11
|
/** The account that will send `create*`. CREATE2 salts are per-deployer. */
|
|
12
12
|
creator?: Address;
|
|
13
13
|
userSalt?: Hex;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* The init-code hash the address was predicted against. Supplying it turns
|
|
16
|
+
* the implementation-drift check on; omitting it skips that one check. A
|
|
17
|
+
* Merkle `plan` supplies it for you.
|
|
17
18
|
*/
|
|
18
19
|
expectedInitCodeHash?: Hex;
|
|
20
|
+
/**
|
|
21
|
+
* Commitments to pin instead of quoting fresh at send time. Anything omitted is read
|
|
22
|
+
* from the factory just before the transaction. For a {@link PlannedCampaign}, pass
|
|
23
|
+
* `plan` on the Merkle arm instead; `{ airdrop: plan.predictedAddress }` here is the
|
|
24
|
+
* lower-level equivalent of its pin. A pinned field that differs from the factory's
|
|
25
|
+
* fresh quote is reported as a `CreateCommitmentMismatchError` blocker.
|
|
26
|
+
*/
|
|
27
|
+
expected?: Partial<CreateCommitments> | undefined;
|
|
19
28
|
}
|
|
20
29
|
/**
|
|
21
30
|
* `variant` and `params` are correlated, mirroring the headless
|
|
@@ -34,22 +43,35 @@ export type UsePreflightCreateAirdropArgs = PreflightCreateAirdropCommon & ({
|
|
|
34
43
|
} | {
|
|
35
44
|
variant: "merkle";
|
|
36
45
|
params?: MerkleAirdropParams;
|
|
46
|
+
/**
|
|
47
|
+
* The {@link PlannedCampaign} the create will realise: pins its address and
|
|
48
|
+
* checks drift against `plan.initCodeHashAfter`. A disagreeing root, pin or
|
|
49
|
+
* `expectedInitCodeHash` is reported as an `InvalidArgumentError` blocker.
|
|
50
|
+
*/
|
|
51
|
+
plan?: PlannedCampaign;
|
|
37
52
|
});
|
|
38
53
|
/**
|
|
39
54
|
* Read-only preflight for `useCreateEcdsaAirdrop` / `useCreateMerkleAirdrop`.
|
|
40
55
|
* Runs every create-time guardrail the write path enforces - chain support,
|
|
41
|
-
* the Merkle/UUPS refusal, the
|
|
56
|
+
* the Merkle/UUPS refusal, params the new instance's initializer would revert
|
|
57
|
+
* on (zero token, an `endTime` less than a minute away, a window that does not
|
|
58
|
+
* open before it closes, a zero immutable Merkle root, a zero ECDSA signer),
|
|
59
|
+
* the resolved fee against the factory's ceiling and the creator's bound,
|
|
60
|
+
* the creator's effective upgradeability policy for
|
|
42
61
|
* `mode: "uups"`, the stock-wrapper probe when `params.common.unwrappable` is
|
|
43
|
-
* set, a salt collision on the predicted address,
|
|
44
|
-
*
|
|
62
|
+
* set, a salt collision on the predicted address, a pinned `expected`
|
|
63
|
+
* commitment that drifted from the fresh quote, and implementation drift
|
|
64
|
+
* when `expectedInitCodeHash` (or a Merkle `plan`) is supplied.
|
|
45
65
|
*
|
|
46
66
|
* **The point is disabling the submit button, not catching after the fact.**
|
|
47
67
|
* `blockers` carries the same typed errors `create*` would have thrown, so a
|
|
48
68
|
* UI branches on `error.code` here exactly as it does in `onError`.
|
|
69
|
+
* `commitments` is what the create would be sent with, for showing the creator
|
|
70
|
+
* before they sign.
|
|
49
71
|
*
|
|
50
72
|
* Disabled until `variant`, `params`, `mode`, `creator` and `userSalt` are all
|
|
51
|
-
* set.
|
|
52
|
-
*
|
|
73
|
+
* set. Factory writes made through this SDK's admin hooks invalidate it;
|
|
74
|
+
* refetch after a factory change made anywhere else.
|
|
53
75
|
*
|
|
54
76
|
* @remarks
|
|
55
77
|
* Named `…Airdrop` rather than `…Create` so a consumer importing both this and
|
|
@@ -57,11 +79,10 @@ export type UsePreflightCreateAirdropArgs = PreflightCreateAirdropCommon & ({
|
|
|
57
79
|
*
|
|
58
80
|
* @example
|
|
59
81
|
* const { data: report } = usePreflightCreateAirdrop({
|
|
60
|
-
* variant: "merkle", params, mode: "clone", creator, userSalt,
|
|
61
|
-
* expectedInitCodeHash: plan.initCodeHashAfter,
|
|
82
|
+
* variant: "merkle", params, mode: "clone", creator, userSalt, plan,
|
|
62
83
|
* });
|
|
63
84
|
* const canSubmit = report?.ready === true;
|
|
64
85
|
*
|
|
65
86
|
* @alpha
|
|
66
87
|
*/
|
|
67
|
-
export declare function usePreflightCreateAirdrop(args?: UsePreflightCreateAirdropArgs): UseQueryResult<
|
|
88
|
+
export declare function usePreflightCreateAirdrop(args?: UsePreflightCreateAirdropArgs): UseQueryResult<PreflightCreateResult, 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>;
|
|
@@ -13,9 +13,9 @@ export interface RescueERC20Args extends WriteAccountOverride {
|
|
|
13
13
|
* Sweep a plain ERC-20 that was sent to an airdrop instance by mistake.
|
|
14
14
|
* Requires `RESCUER_ROLE`.
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* {@link useWithdrawConfidential}
|
|
16
|
+
* Passing the campaign's own token reverts `CannotRescueAirdropToken` (a wrapper token
|
|
17
|
+
* answers both interfaces, so this is a check, not an assumption); use
|
|
18
|
+
* {@link useWithdrawConfidential} for the pool and
|
|
19
19
|
* {@link useRescueOtherConfidentialToken} for a stranded ERC-7984.
|
|
20
20
|
*
|
|
21
21
|
* **Invalidates:** nothing. This subpath has no read hook over arbitrary
|
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
/**
|
|
6
|
+
* Sweep ETH stranded on a zero-fee airdrop instance (a forced send, or a transfer to the
|
|
7
|
+
* predicted address before deploy) to `recipient`. Requires `RESCUER_ROLE`.
|
|
8
|
+
*
|
|
9
|
+
* Refused on a fee-charging campaign (`NativeRescueRequiresZeroFeeError`): there the ETH is
|
|
10
|
+
* fee revenue and belongs to `withdrawGasFee`.
|
|
11
|
+
*
|
|
12
|
+
* **Invalidates:** nothing. No read hook in this subpath exposes the instance's ETH balance,
|
|
13
|
+
* so there is no cached query left stale by the sweep.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const rescue = useRescueNativeToken({ address: airdropAddress });
|
|
17
|
+
* await rescue.mutateAsync({ recipient: treasuryAddress });
|
|
18
|
+
*
|
|
19
|
+
* @alpha
|
|
20
|
+
*/
|
|
21
|
+
export declare function useRescueNativeToken(options: AirdropInstanceClientOptions): UseMutationResult<Hex, Error, {
|
|
22
|
+
recipient: Address;
|
|
23
|
+
} & WriteAccountOverride>;
|
|
@@ -0,0 +1,30 @@
|
|
|
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 UseResolveGasFeeArgs extends AirdropHookOptions<bigint> {
|
|
6
|
+
/** The account that will send `create*`. Fee overrides are per-creator. */
|
|
7
|
+
creator?: Address;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The per-claim fee a `create*` from `creator` would freeze into the new
|
|
11
|
+
* instance right now: their `setCustomFee` override when enabled, else the
|
|
12
|
+
* factory default.
|
|
13
|
+
*
|
|
14
|
+
* **This is the number `common.maxAcceptedGasFee` is checked against**, so it is
|
|
15
|
+
* what a create form should show before the creator picks a bound. Composing it
|
|
16
|
+
* from `useFactoryFees` and `useFactoryCustomFee` by hand means re-implementing
|
|
17
|
+
* the override-over-default rule in every consumer, and getting it wrong reads
|
|
18
|
+
* as "no fee" on exactly the accounts that have one.
|
|
19
|
+
*
|
|
20
|
+
* **A snapshot, not a quote.** `FEE_MANAGER_ROLE` can move it between this read
|
|
21
|
+
* and the create landing, which is the case `maxAcceptedGasFee` exists to catch -
|
|
22
|
+
* so treat this as what to *show*, never as a reason to skip the bound.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* const { data: fee } = useResolveGasFee({ creator: address });
|
|
26
|
+
* // then: params.common.maxAcceptedGasFee = fee ?? 0n
|
|
27
|
+
*
|
|
28
|
+
* @alpha
|
|
29
|
+
*/
|
|
30
|
+
export declare function useResolveGasFee(args?: UseResolveGasFeeArgs): UseQueryResult<bigint, Error>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type UseMutationResult } from "@tanstack/react-query";
|
|
2
2
|
import type { WriteAccountOverride } from "../airdrop-base.js";
|
|
3
|
-
import { type
|
|
3
|
+
import { type RotatedCampaign } from "../campaign.js";
|
|
4
4
|
import type { CampaignRecipient } from "../types.js";
|
|
5
5
|
import { type AirdropInstanceClientOptions } from "./_shared.js";
|
|
6
6
|
/**
|
|
@@ -8,7 +8,7 @@ import { type AirdropInstanceClientOptions } from "./_shared.js";
|
|
|
8
8
|
*
|
|
9
9
|
* @alpha
|
|
10
10
|
*/
|
|
11
|
-
export interface UseRotateMerkleRootArgs extends
|
|
11
|
+
export interface UseRotateMerkleRootArgs extends WriteAccountOverride {
|
|
12
12
|
/** The FULL updated roster, carrying each account's new CUMULATIVE total — never the delta since the last root. */
|
|
13
13
|
recipients: readonly CampaignRecipient[];
|
|
14
14
|
}
|
|
@@ -23,6 +23,9 @@ export interface UseRotateMerkleRootArgs extends CampaignSubmitterOption, WriteA
|
|
|
23
23
|
* rosters. A total below what an account already received pays nothing; a
|
|
24
24
|
* rotation cannot claw back.
|
|
25
25
|
*
|
|
26
|
+
* One relayer request per 32 recipients, issued concurrently; every leaf is
|
|
27
|
+
* submittable by any address.
|
|
28
|
+
*
|
|
26
29
|
* The root is published LAST, so a failed rebuild leaves the previous campaign
|
|
27
30
|
* intact and claimable. Once it lands the old proofs stop verifying:
|
|
28
31
|
* **distribute the new entries to every recipient**, including those whose
|
|
@@ -19,6 +19,10 @@ export interface SignClaimAuthorizationArgs extends WriteAccountOverride {
|
|
|
19
19
|
* dedupId, uint256 deadline)` authorization for an `ECDSAConfidentialAirdrop`
|
|
20
20
|
* instance. The signer must hold `SIGNER_ROLE` on that instance.
|
|
21
21
|
*
|
|
22
|
+
* **Never sign with an EIP-7702-delegated key.** A delegation switches verification to
|
|
23
|
+
* ERC-1271 against the delegate, so every outstanding voucher fails although the key
|
|
24
|
+
* keeps the role. See {@link signClaimAuthorization}.
|
|
25
|
+
*
|
|
22
26
|
* `airdrop` and `chainId` come from the hook's own options, so a component
|
|
23
27
|
* supplies only the claim fields.
|
|
24
28
|
*
|
|
@@ -0,0 +1,29 @@
|
|
|
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 UseTokenOfArgs extends AirdropHookOptions<Address> {
|
|
6
|
+
/** The airdrop instance whose recorded token to resolve. */
|
|
7
|
+
airdrop?: Address;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the token the factory recorded for an airdrop instance at create - what
|
|
11
|
+
* `fundAirdrop` pulls, regardless of what the instance reports today.
|
|
12
|
+
*
|
|
13
|
+
* A zero address means the instance did not come from this factory.
|
|
14
|
+
*
|
|
15
|
+
* Cached indefinitely once non-zero: the mapping is written once, inside `createX`.
|
|
16
|
+
* A zero answer (not created yet, or not from this factory) is not cached forever: it
|
|
17
|
+
* stays stale and refetches on the next mount, focus or `refetch`, because the address
|
|
18
|
+
* can be created later by another tab, a server or the headless client, none of which
|
|
19
|
+
* reaches a hook invalidation. The create hooks in this subpath also invalidate this
|
|
20
|
+
* key for the address they deploy, so a zero already on screen updates immediately;
|
|
21
|
+
* the per-result `staleTime` covers every other create path, the same policy as
|
|
22
|
+
* {@link useIsAirdrop}. Override through `query.staleTime`.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* const { data: token } = useTokenOf({ airdrop: airdropAddress });
|
|
26
|
+
*
|
|
27
|
+
* @alpha
|
|
28
|
+
*/
|
|
29
|
+
export declare function useTokenOf(args?: UseTokenOfArgs): UseQueryResult<Address, Error>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type UseQueryResult } from "@tanstack/react-query";
|
|
2
|
+
import type { Hex } from "viem";
|
|
3
|
+
import type { UnwrapRequest } from "../airdrop-base.js";
|
|
4
|
+
import { type AirdropInstanceHookOptions } from "./_shared.js";
|
|
5
|
+
/** @alpha */
|
|
6
|
+
export type UseUnwrapRequestArgs = AirdropInstanceHookOptions<UnwrapRequest> & {
|
|
7
|
+
/** The `claimAndUnwrap` transaction hash. The query stays idle until it is set. */
|
|
8
|
+
hash: Hex | undefined;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* The unwrap request a `claimAndUnwrap` started: waits for `hash` to be mined and
|
|
12
|
+
* decodes the instance's `ClaimedAndUnwrapInitiated` event.
|
|
13
|
+
*
|
|
14
|
+
* Hand `unwrapRequestId` to the wrapper's `finalizeUnwrap` to release the underlying
|
|
15
|
+
* ERC-20; with Zama's SDK, `sdk.createToken(wrapper).finalizeUnwrap(unwrapRequestId)`.
|
|
16
|
+
* The amount was already public from the claim transaction; finalizing discloses nothing new.
|
|
17
|
+
* A mined receipt does not change, so the result never goes stale.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* const unwrap = useEcdsaClaimAndUnwrap({ address: airdropAddress });
|
|
21
|
+
* const { data: request } = useUnwrapRequest({ address: airdropAddress, hash: unwrap.data });
|
|
22
|
+
*
|
|
23
|
+
* @alpha
|
|
24
|
+
*/
|
|
25
|
+
export declare function useUnwrapRequest(args: UseUnwrapRequestArgs): UseQueryResult<UnwrapRequest, Error>;
|
|
@@ -8,6 +8,10 @@ import { type AirdropInstanceClientOptions } from "./_shared.js";
|
|
|
8
8
|
* never appears in plaintext anywhere — the contract reads its own encrypted
|
|
9
9
|
* balance and moves all of it.
|
|
10
10
|
*
|
|
11
|
+
* Refused while the campaign is unpaused inside its claim window
|
|
12
|
+
* (`ClawbackRequiresPauseError`): pause with {@link useAirdropPause} first, or run it
|
|
13
|
+
* outside the window.
|
|
14
|
+
*
|
|
11
15
|
* **Invalidates:** nothing. No read hook in this subpath's list exposes the
|
|
12
16
|
* confidential pool balance (see {@link useFundAirdrop}'s TSDoc for the same
|
|
13
17
|
* reasoning), so there is no cached query left stale by a withdrawal.
|
|
@@ -26,6 +26,10 @@ export interface InstanceRoleAssignment {
|
|
|
26
26
|
disclosureAdmin?: Address;
|
|
27
27
|
upgrader?: Address;
|
|
28
28
|
merkleAdmin?: Address;
|
|
29
|
+
/**
|
|
30
|
+
* `SIGNER_ROLE`. A dedicated key that is never EIP-7702-delegated (or an ERC-1271 contract
|
|
31
|
+
* signer): a delegation invalidates every outstanding voucher.
|
|
32
|
+
*/
|
|
29
33
|
signer?: Address;
|
|
30
34
|
/** Granting this always fails from DEFAULT_ADMIN — see planInstanceRoleSplit. */
|
|
31
35
|
feeCollector?: Address;
|
|
@@ -66,20 +70,18 @@ export interface RoleGrantOutcome {
|
|
|
66
70
|
* would only revert on-chain:
|
|
67
71
|
*
|
|
68
72
|
* 1. **`feeCollector`.** `FEE_COLLECTOR_ROLE` is self-administered
|
|
69
|
-
* (`_setRoleAdmin(FEE_COLLECTOR_ROLE, FEE_COLLECTOR_ROLE)
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
* (the factory's collector is seeded instead, `:143`).
|
|
73
|
+
* (`_setRoleAdmin(FEE_COLLECTOR_ROLE, FEE_COLLECTOR_ROLE)` at initialization)
|
|
74
|
+
* - `DEFAULT_ADMIN_ROLE` cannot grant it, only an existing member can, and
|
|
75
|
+
* the campaign creator never is one (the factory's collector is seeded instead).
|
|
73
76
|
* 2. **`admin` set to the zero address.** Mirrors the contract's
|
|
74
|
-
* unconditional `ZeroAdminGrant` guard
|
|
77
|
+
* unconditional `ZeroAdminGrant` guard in `_grantRole`.
|
|
75
78
|
* 3. **A variant-only role on the wrong campaign** — `merkleAdmin` on an
|
|
76
79
|
* ECDSA instance, or `signer` on a Merkle one. Neither role exists there;
|
|
77
80
|
* the getter itself would revert.
|
|
78
81
|
*
|
|
79
82
|
* `admin`, when present, always produces two steps — grant the new admin,
|
|
80
83
|
* then revoke `args.caller` — and the revoke is always ORDERED LAST, after
|
|
81
|
-
* every other step in the plan. `_revokeRole`'s `LastAdmin` floor
|
|
82
|
-
* (`ConfidentialAirdropBase.sol:261`) blocks removing the sole
|
|
84
|
+
* every other step in the plan. `_revokeRole`'s `LastAdmin` floor blocks removing the sole
|
|
83
85
|
* `DEFAULT_ADMIN_ROLE` member, so revoking the creator first would strand
|
|
84
86
|
* every later grant with no admin left to authorize it.
|
|
85
87
|
*
|
|
@@ -96,6 +98,73 @@ export declare function planInstanceRoleSplit(args: {
|
|
|
96
98
|
caller: Address;
|
|
97
99
|
airdropType: "ecdsa" | "merkle";
|
|
98
100
|
}): RoleGrantStep[];
|
|
101
|
+
/**
|
|
102
|
+
* One call of a Safe MultiSend batch: a zero-value `grantRole` / `revokeRole`
|
|
103
|
+
* on the instance.
|
|
104
|
+
*
|
|
105
|
+
* @alpha
|
|
106
|
+
*/
|
|
107
|
+
export interface InstanceRoleCall {
|
|
108
|
+
to: Address;
|
|
109
|
+
data: Hex;
|
|
110
|
+
value: 0n;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The `bytes32` constants {@link encodeInstanceRoleSplit} encodes, keyed by
|
|
114
|
+
* {@link RoleName}. Read them off the instance (the `*_ROLE()` getters on
|
|
115
|
+
* `AirdropBaseClient` and its subclasses, or `useAirdropRoleConstants`);
|
|
116
|
+
* hashing the names yourself would silently grant a role nothing checks if a
|
|
117
|
+
* constant is ever renamed. `DEFAULT_ADMIN_ROLE` may be omitted: it is
|
|
118
|
+
* OpenZeppelin's fixed `bytes32(0)`.
|
|
119
|
+
*
|
|
120
|
+
* @alpha
|
|
121
|
+
*/
|
|
122
|
+
export type InstanceRoleConstants = Partial<Record<RoleName, Hex>>;
|
|
123
|
+
/**
|
|
124
|
+
* Encode a {@link planInstanceRoleSplit} plan as the ordered calls a Safe
|
|
125
|
+
* executes in one MultiSend batch - the multisig counterpart of
|
|
126
|
+
* {@link grantInstanceRoles}.
|
|
127
|
+
*
|
|
128
|
+
* {@link grantInstanceRoles} must mine each step before simulating the next,
|
|
129
|
+
* which a threshold Safe cannot do in one session. A batch does not need to:
|
|
130
|
+
* its calls run in order inside one transaction, so the plan's
|
|
131
|
+
* grant-before-revoke ordering holds and the `LastAdmin` floor never sees the
|
|
132
|
+
* new admin missing. Plan with `caller` set to the Safe address, since the Safe
|
|
133
|
+
* is the account whose `DEFAULT_ADMIN_ROLE` the handoff revokes.
|
|
134
|
+
*
|
|
135
|
+
* The batch is atomic: one reverting call reverts the whole split, unlike the
|
|
136
|
+
* per-step outcomes of {@link grantInstanceRoles}.
|
|
137
|
+
*
|
|
138
|
+
* To keep the Safe as co-admin (the `revokeFromCreator: false` of
|
|
139
|
+
* {@link grantInstanceRoles}), drop the `revoke` `DEFAULT_ADMIN_ROLE` step
|
|
140
|
+
* from the plan before encoding.
|
|
141
|
+
*
|
|
142
|
+
* Each call is a plain CALL, so `operation` is omitted. Safe SDKs type `value`
|
|
143
|
+
* as a decimal string; map it when handing the calls over.
|
|
144
|
+
*
|
|
145
|
+
* @param args.airdrop The instance the calls target.
|
|
146
|
+
* @param args.steps The plan, in the order {@link planInstanceRoleSplit} returned it.
|
|
147
|
+
* @param args.roleConstants The role constants read off the instance.
|
|
148
|
+
* @returns One {@link InstanceRoleCall} per step, in plan order.
|
|
149
|
+
* @throws {@link InvalidArgumentError} when a step names a role whose constant is missing.
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* const steps = planInstanceRoleSplit({ assignment, caller: safeAddress, airdropType: "merkle" });
|
|
153
|
+
* const calls = encodeInstanceRoleSplit({
|
|
154
|
+
* airdrop,
|
|
155
|
+
* steps,
|
|
156
|
+
* roleConstants: { PAUSER_ROLE: await client.PAUSER_ROLE() },
|
|
157
|
+
* });
|
|
158
|
+
* // One MultiSend transaction; Safe SDKs take `value` as a string.
|
|
159
|
+
* const transactions = calls.map((c) => ({ ...c, value: "0" }));
|
|
160
|
+
*
|
|
161
|
+
* @alpha
|
|
162
|
+
*/
|
|
163
|
+
export declare function encodeInstanceRoleSplit(args: {
|
|
164
|
+
airdrop: Address;
|
|
165
|
+
steps: readonly RoleGrantStep[];
|
|
166
|
+
roleConstants: InstanceRoleConstants;
|
|
167
|
+
}): InstanceRoleCall[];
|
|
99
168
|
/**
|
|
100
169
|
* Execute an {@link InstanceRoleAssignment} against a live instance:
|
|
101
170
|
* {@link planInstanceRoleSplit} the steps, then submit them one at a time,
|
|
@@ -113,6 +182,12 @@ export declare function planInstanceRoleSplit(args: {
|
|
|
113
182
|
* intentionally: correctness of the ordering guarantee in
|
|
114
183
|
* {@link planInstanceRoleSplit} depends on it.
|
|
115
184
|
*
|
|
185
|
+
* **Safe / multisig signers cannot use this.** A threshold Safe cannot mine
|
|
186
|
+
* one step before proposing the next, so there is deliberately no
|
|
187
|
+
* `waitForReceipt: false` here. Plan with {@link planInstanceRoleSplit}
|
|
188
|
+
* (`caller` = the Safe) and submit {@link encodeInstanceRoleSplit}'s calls as
|
|
189
|
+
* one MultiSend batch instead.
|
|
190
|
+
*
|
|
116
191
|
* **This is several transactions, not one — never atomic.** Each step is
|
|
117
192
|
* caught individually, so one failing grant or revoke does not abort the
|
|
118
193
|
* rest; inspect each {@link RoleGrantOutcome} rather than assuming
|