@tokenops/sdk 1.6.0 → 2.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -8
- package/CONTRIBUTING.md +4 -2
- package/README.md +146 -90
- package/SUPPORT.md +47 -0
- package/dist/{chunk-HETNKZEE.js → chunk-335Z2W67.js} +1 -1
- package/dist/{chunk-BD4LZBVF.cjs → chunk-3QHNYEQD.cjs} +18 -17
- package/dist/chunk-456VDDA3.js +370 -0
- package/dist/{chunk-6WSNS3UV.js → chunk-4RAAATVY.js} +2 -4
- package/dist/{chunk-4KJ66YRH.js → chunk-4TSDNZQ3.js} +2 -2
- package/dist/{chunk-WUXUWTFW.cjs → chunk-5576FRT3.cjs} +31 -7
- package/dist/chunk-66IHPTOK.cjs +20 -0
- package/dist/{chunk-2RNW4MIJ.cjs → chunk-67OV5CX2.cjs} +0 -18
- package/dist/{chunk-PD7ME2BT.js → chunk-6GNR22OV.js} +2 -1
- package/dist/{chunk-VHSNYUYV.js → chunk-6NAVMWZQ.js} +5 -5
- package/dist/{chunk-EUKPOXWR.cjs → chunk-6PXXGACR.cjs} +17 -15
- package/dist/{chunk-WTK6JDSI.js → chunk-74QFZ5MK.js} +6 -4
- package/dist/{chunk-WOEETTH7.cjs → chunk-7AFPOE7N.cjs} +6 -6
- package/dist/{chunk-U57COLUE.js → chunk-AXIPOR3C.js} +2 -2
- package/dist/chunk-CTED3MTR.cjs +380 -0
- package/dist/{chunk-QKKBBH7I.js → chunk-DZHYSUGY.js} +28 -7
- package/dist/{chunk-V5D7BHW3.js → chunk-EAJ7SYHE.js} +6 -4
- package/dist/{chunk-SYHNZSZZ.cjs → chunk-FAXIIH5R.cjs} +3 -3
- package/dist/{chunk-7G7UOQV4.cjs → chunk-FGEB7RMY.cjs} +4 -4
- package/dist/chunk-GKKDAW44.js +8823 -0
- package/dist/{chunk-QET3Q4JP.js → chunk-H5POPGOZ.js} +8 -6
- package/dist/{chunk-VR3FREBX.cjs → chunk-JK4XMMKM.cjs} +3 -3
- package/dist/{chunk-CBRL2PJA.cjs → chunk-JQYC66TO.cjs} +12 -12
- package/dist/{chunk-YFIWCYHC.cjs → chunk-JZLGCTGK.cjs} +56 -54
- package/dist/{chunk-4ZCXK4VI.cjs → chunk-KFRDLKMA.cjs} +14 -14
- package/dist/chunk-KWFFIJYX.js +11 -0
- package/dist/chunk-M4IT6DNJ.cjs +608 -0
- package/dist/{chunk-43RFBQ73.cjs → chunk-MVDQMV25.cjs} +29 -32
- package/dist/chunk-NCVX3K2N.cjs +161 -0
- package/dist/chunk-NWFMBLSQ.js +4 -0
- package/dist/chunk-O5676ZWY.js +585 -0
- package/dist/chunk-PUX5VXDB.cjs +8845 -0
- package/dist/{chunk-DRSPMIZ7.js → chunk-QBJ7O2B4.js} +1 -11
- package/dist/{chunk-UJS4N2XM.cjs → chunk-TEBM66WA.cjs} +12 -12
- package/dist/{chunk-TN65XNTI.js → chunk-TWT3STIX.js} +8 -6
- package/dist/chunk-UG5RKLU2.cjs +6 -0
- package/dist/chunk-VP2B4WM2.js +154 -0
- package/dist/{chunk-BK7YIVLK.cjs → chunk-WJLECC22.cjs} +75 -73
- package/dist/{chunk-NFW7AUEX.js → chunk-WMACINXO.js} +1 -1
- package/dist/{chunk-AYGRYDBX.cjs → chunk-XAYGD4E4.cjs} +37 -35
- package/dist/{chunk-46T67CE2.js → chunk-ZA673I3O.js} +1 -1
- package/dist/{chunk-YPYCWLYP.js → chunk-ZWXJTBZO.js} +1 -1
- package/dist/core/addresses.d.ts +14 -2
- package/dist/core/brands.d.ts +8 -2
- package/dist/core/errors.d.ts +71 -10
- package/dist/core/preflight.d.ts +1 -0
- package/dist/fhe/erc7984-abi.d.ts +1 -0
- package/dist/fhe/index.cjs +64 -63
- package/dist/fhe/index.js +7 -6
- package/dist/fhe/operators.d.ts +22 -5
- package/dist/fhe/react/index.cjs +13 -12
- package/dist/fhe/react/index.js +6 -5
- package/dist/fhe/types.d.ts +6 -0
- package/dist/fhe-airdrop/abis/{cloneable.d.ts → airdrop-base.d.ts} +254 -396
- package/dist/fhe-airdrop/abis/compliance.d.ts +422 -0
- package/dist/fhe-airdrop/abis/ecdsa.d.ts +1316 -0
- package/dist/fhe-airdrop/abis/factory.d.ts +1319 -190
- package/dist/fhe-airdrop/abis/index.d.ts +5 -2
- package/dist/fhe-airdrop/abis/merkle.d.ts +1238 -0
- package/dist/fhe-airdrop/advanced/index.cjs +11 -12
- package/dist/fhe-airdrop/advanced/index.d.cts +34 -11
- package/dist/fhe-airdrop/advanced/index.d.ts +34 -11
- package/dist/fhe-airdrop/advanced/index.js +3 -8
- package/dist/fhe-airdrop/advanced/react/index.cjs +37 -50
- package/dist/fhe-airdrop/advanced/react/index.d.cts +9 -3
- package/dist/fhe-airdrop/advanced/react/index.d.ts +9 -3
- package/dist/fhe-airdrop/advanced/react/index.js +36 -50
- package/dist/fhe-airdrop/advanced/react/usePredictEcdsaAirdropAddress.d.ts +33 -0
- package/dist/fhe-airdrop/advanced/react/usePredictMerkleAirdropAddress.d.ts +27 -0
- package/dist/fhe-airdrop/airdrop-base.d.ts +600 -0
- package/dist/fhe-airdrop/campaign.d.ts +297 -0
- package/dist/fhe-airdrop/compliance.d.ts +302 -0
- package/dist/fhe-airdrop/constants.d.ts +33 -0
- package/dist/fhe-airdrop/ecdsa.d.ts +263 -0
- package/dist/fhe-airdrop/encryption.d.ts +92 -14
- package/dist/fhe-airdrop/errors.d.ts +245 -15
- package/dist/fhe-airdrop/factory.d.ts +533 -274
- package/dist/fhe-airdrop/guards.d.ts +273 -0
- package/dist/fhe-airdrop/index.cjs +1131 -74
- package/dist/fhe-airdrop/index.d.cts +46 -8
- package/dist/fhe-airdrop/index.d.ts +46 -8
- package/dist/fhe-airdrop/index.js +931 -8
- package/dist/fhe-airdrop/merkle-tree.d.ts +103 -0
- package/dist/fhe-airdrop/merkle.d.ts +180 -0
- package/dist/fhe-airdrop/react/_shared.d.ts +144 -71
- package/dist/fhe-airdrop/react/index.cjs +399 -459
- package/dist/fhe-airdrop/react/index.d.cts +53 -74
- package/dist/fhe-airdrop/react/index.d.ts +53 -74
- package/dist/fhe-airdrop/react/index.js +261 -374
- package/dist/fhe-airdrop/react/useAirdropGasFee.d.ts +10 -5
- package/dist/fhe-airdrop/react/useAirdropHasRole.d.ts +15 -6
- package/dist/fhe-airdrop/react/useAirdropPause.d.ts +30 -0
- package/dist/fhe-airdrop/react/useAirdropPaused.d.ts +17 -0
- package/dist/fhe-airdrop/react/useAirdropToken.d.ts +11 -4
- package/dist/fhe-airdrop/react/useAirdropWindow.d.ts +37 -0
- package/dist/fhe-airdrop/react/useClaimedAmount.d.ts +29 -0
- package/dist/fhe-airdrop/react/useComplianceManager.d.ts +16 -0
- package/dist/fhe-airdrop/react/useCreateEcdsaAirdrop.d.ts +28 -0
- package/dist/fhe-airdrop/react/useCreateMerkleAirdrop.d.ts +25 -0
- package/dist/fhe-airdrop/react/useEcdsaClaim.d.ts +23 -0
- package/dist/fhe-airdrop/react/useEffectiveUpgradeable.d.ts +20 -0
- package/dist/fhe-airdrop/react/useExtendClaimWindow.d.ts +17 -12
- package/dist/fhe-airdrop/react/useFactoryFees.d.ts +28 -0
- package/dist/fhe-airdrop/react/useFactoryRegistry.d.ts +35 -0
- package/dist/fhe-airdrop/react/useFundAirdrop.d.ts +35 -0
- package/dist/fhe-airdrop/react/useGrantInstanceRoles.d.ts +35 -0
- package/dist/fhe-airdrop/react/useMerkleClaim.d.ts +34 -0
- package/dist/fhe-airdrop/react/useMerkleRoot.d.ts +15 -0
- package/dist/fhe-airdrop/react/useSetMerkleRoot.d.ts +22 -0
- package/dist/fhe-airdrop/react/useWithdrawConfidential.d.ts +23 -0
- package/dist/fhe-airdrop/roles.d.ts +147 -0
- package/dist/fhe-airdrop/types.d.ts +67 -65
- package/dist/fhe-disperse/index.cjs +70 -68
- package/dist/fhe-disperse/index.js +10 -8
- package/dist/fhe-disperse/react/index.cjs +94 -92
- package/dist/fhe-disperse/react/index.js +13 -11
- package/dist/fhe-vesting/advanced/index.cjs +10 -8
- package/dist/fhe-vesting/advanced/index.js +8 -6
- package/dist/fhe-vesting/advanced/react/index.cjs +16 -14
- package/dist/fhe-vesting/advanced/react/index.js +13 -11
- package/dist/fhe-vesting/index.cjs +74 -72
- package/dist/fhe-vesting/index.js +11 -9
- package/dist/fhe-vesting/react/index.cjs +228 -226
- package/dist/fhe-vesting/react/index.js +15 -13
- package/dist/index.cjs +100 -87
- package/dist/index.js +3 -2
- package/dist/testnet-faucet/index.cjs +57 -55
- package/dist/testnet-faucet/index.js +7 -5
- package/dist/testnet-faucet/react/index.cjs +55 -53
- package/dist/testnet-faucet/react/index.js +9 -7
- package/package.json +6 -2
- package/dist/chunk-CNP4L3GF.js +0 -105
- package/dist/chunk-KSDSXJ34.js +0 -41
- package/dist/chunk-LBWRFZR3.cjs +0 -1681
- package/dist/chunk-OL6SHN3D.cjs +0 -44
- package/dist/chunk-S2XD75JM.js +0 -1637
- package/dist/chunk-SPGSO5SO.cjs +0 -1644
- package/dist/chunk-UE5XK2SY.js +0 -1673
- package/dist/chunk-WO72UBQD.cjs +0 -109
- package/dist/fhe-airdrop/advanced/factory-advanced.d.ts +0 -53
- package/dist/fhe-airdrop/advanced/react/usePredictAirdropAddress.d.ts +0 -49
- package/dist/fhe-airdrop/airdrop.d.ts +0 -317
- package/dist/fhe-airdrop/react/useAccessClaimAmount.d.ts +0 -37
- package/dist/fhe-airdrop/react/useAirdropCanExtendClaimWindow.d.ts +0 -7
- package/dist/fhe-airdrop/react/useAirdropClaimTypehash.d.ts +0 -10
- package/dist/fhe-airdrop/react/useAirdropClaimedSignatures.d.ts +0 -16
- package/dist/fhe-airdrop/react/useAirdropDeploymentBlockNumber.d.ts +0 -6
- package/dist/fhe-airdrop/react/useAirdropDomainSeparator.d.ts +0 -8
- package/dist/fhe-airdrop/react/useAirdropEndTime.d.ts +0 -10
- package/dist/fhe-airdrop/react/useAirdropFactoryCustomFee.d.ts +0 -17
- package/dist/fhe-airdrop/react/useAirdropFactoryDefaultGasFee.d.ts +0 -10
- package/dist/fhe-airdrop/react/useAirdropFactoryDisableCustomFee.d.ts +0 -15
- package/dist/fhe-airdrop/react/useAirdropFactoryFeeCollector.d.ts +0 -11
- package/dist/fhe-airdrop/react/useAirdropFactoryInitCodeHash.d.ts +0 -17
- package/dist/fhe-airdrop/react/useAirdropFactorySetCustomFee.d.ts +0 -17
- package/dist/fhe-airdrop/react/useAirdropFactorySetDefaultGasFee.d.ts +0 -16
- package/dist/fhe-airdrop/react/useAirdropFactorySetFeeCollector.d.ts +0 -15
- package/dist/fhe-airdrop/react/useAirdropGrantRole.d.ts +0 -16
- package/dist/fhe-airdrop/react/useAirdropHasClaimEnded.d.ts +0 -7
- package/dist/fhe-airdrop/react/useAirdropHasClaimStarted.d.ts +0 -7
- package/dist/fhe-airdrop/react/useAirdropIsClaimWindowActive.d.ts +0 -9
- package/dist/fhe-airdrop/react/useAirdropIsPaused.d.ts +0 -8
- package/dist/fhe-airdrop/react/useAirdropIsSignatureClaimed.d.ts +0 -22
- package/dist/fhe-airdrop/react/useAirdropIsSignatureValid.d.ts +0 -51
- package/dist/fhe-airdrop/react/useAirdropRevokeRole.d.ts +0 -15
- package/dist/fhe-airdrop/react/useAirdropStartTime.d.ts +0 -10
- package/dist/fhe-airdrop/react/useAirdropWithdrawGasFee.d.ts +0 -15
- package/dist/fhe-airdrop/react/useAirdropWithdrawOtherConfidentialToken.d.ts +0 -14
- package/dist/fhe-airdrop/react/useAirdropWithdrawOtherToken.d.ts +0 -14
- package/dist/fhe-airdrop/react/useClaim.d.ts +0 -39
- package/dist/fhe-airdrop/react/useConfidentialAirdropFactoryImplementation.d.ts +0 -11
- package/dist/fhe-airdrop/react/useCreateAndFundConfidentialAirdrop.d.ts +0 -41
- package/dist/fhe-airdrop/react/useCreateAndFundConfidentialAirdropAndGetAddress.d.ts +0 -48
- package/dist/fhe-airdrop/react/useCreateConfidentialAirdrop.d.ts +0 -29
- package/dist/fhe-airdrop/react/useCreateConfidentialAirdropAndGetAddress.d.ts +0 -31
- package/dist/fhe-airdrop/react/useDisableCustomFee.d.ts +0 -14
- package/dist/fhe-airdrop/react/useFactoryCustomFee.d.ts +0 -17
- package/dist/fhe-airdrop/react/useFactoryDefaultGasFee.d.ts +0 -10
- package/dist/fhe-airdrop/react/useFactoryFeeCollector.d.ts +0 -11
- package/dist/fhe-airdrop/react/useFactoryInitCodeHash.d.ts +0 -17
- package/dist/fhe-airdrop/react/useFundConfidentialAirdrop.d.ts +0 -33
- package/dist/fhe-airdrop/react/usePreflightCreateAirdrop.d.ts +0 -51
- package/dist/fhe-airdrop/react/useSetCustomFee.d.ts +0 -16
- package/dist/fhe-airdrop/react/useSetDefaultGasFee.d.ts +0 -15
- package/dist/fhe-airdrop/react/useSetFeeCollector.d.ts +0 -14
- package/dist/fhe-airdrop/react/useSetPaused.d.ts +0 -14
- package/dist/fhe-airdrop/react/useSignClaimAuthorization.d.ts +0 -31
- package/dist/fhe-airdrop/react/useWithdraw.d.ts +0 -12
- package/dist/fhe-airdrop/react/useWithdrawOtherConfidentialToken.d.ts +0 -13
- package/dist/fhe-airdrop/react/useWithdrawOtherToken.d.ts +0 -13
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import type { Address, Hex } from "viem";
|
|
2
|
+
import type { WriteAccountOverride } from "./airdrop-base.js";
|
|
3
|
+
import { type EncryptorSource } from "./encryption.js";
|
|
4
|
+
import type { ConfidentialAirdropFactoryClient } from "./factory.js";
|
|
5
|
+
import type { MerkleAirdropClient } from "./merkle.js";
|
|
6
|
+
import { type MerkleLeafInput } from "./merkle-tree.js";
|
|
7
|
+
import type { DeploymentMode } from "./constants.js";
|
|
8
|
+
import type { BuiltCampaign, CampaignRecipient, MerkleAirdropParams } from "./types.js";
|
|
9
|
+
export type { BuiltCampaign, CampaignEntry, CampaignRecipient } from "./types.js";
|
|
10
|
+
/**
|
|
11
|
+
* Reject the campaign shapes that produce an unusable or misleading tree,
|
|
12
|
+
* before any encryption work is done.
|
|
13
|
+
*
|
|
14
|
+
* Five rules, each of which is silent rather than loud if left unchecked:
|
|
15
|
+
*
|
|
16
|
+
* - **Well-formed address.** A malformed one would otherwise escape as a raw
|
|
17
|
+
* viem `InvalidAddressError` out of the zero-address check below - an
|
|
18
|
+
* untyped throw from the function whose job is producing typed ones.
|
|
19
|
+
* - **No duplicate recipient.** `claimedAmount` is a cumulative running total
|
|
20
|
+
* keyed by account alone (`ConfidentialAirdropMerkleStorage`), and a claim
|
|
21
|
+
* pays `total - min(total, claimed)`. Two leaves for one account under one
|
|
22
|
+
* root therefore pay `max(totalA, totalB)`, in either claim order — never
|
|
23
|
+
* the sum the author almost certainly intended.
|
|
24
|
+
* - **No zero address.** A zero-address leaf is unclaimable and silently
|
|
25
|
+
* burns its share of the pool.
|
|
26
|
+
* - **`uint64` range.** The contract's `euint64` arithmetic cannot represent
|
|
27
|
+
* anything else; a wider total would be rejected far downstream, at
|
|
28
|
+
* encryption time.
|
|
29
|
+
* - **Non-empty.** An empty tree has no root to publish.
|
|
30
|
+
*
|
|
31
|
+
* @param recipients The campaign roster to check.
|
|
32
|
+
* @throws {@link InvalidArgumentError} on any of the five. The thrown error
|
|
33
|
+
* never carries a `cumulativeTotal`: the totals are the confidential part of
|
|
34
|
+
* a confidential airdrop, so they are named by index, never by value.
|
|
35
|
+
*
|
|
36
|
+
* @alpha
|
|
37
|
+
*/
|
|
38
|
+
export declare function validateCampaignRecipients(recipients: readonly CampaignRecipient[]): void;
|
|
39
|
+
/**
|
|
40
|
+
* Real implementation behind {@link validateCampaignRecipients}, parameterised
|
|
41
|
+
* on the function name a thrown {@link InvalidArgumentError} blames.
|
|
42
|
+
*
|
|
43
|
+
* Not part of the public surface - exported from this module only so the
|
|
44
|
+
* orchestrators can attribute a roster failure to themselves rather than to a
|
|
45
|
+
* validator the caller never invoked. Neither barrel re-exports it. Same
|
|
46
|
+
* pattern as `buildMerkleTreeInternal` in `./merkle-tree.js`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function validateCampaignRecipientsInternal(recipients: readonly CampaignRecipient[], method: string): void;
|
|
49
|
+
/**
|
|
50
|
+
* Inputs for {@link buildMerkleCampaign}.
|
|
51
|
+
*
|
|
52
|
+
* @alpha
|
|
53
|
+
*/
|
|
54
|
+
export interface BuildMerkleCampaignArgs {
|
|
55
|
+
/** The LIVE `MerkleConfidentialAirdrop` instance every input is bound to. Not the factory, not the implementation. */
|
|
56
|
+
instance: Address;
|
|
57
|
+
recipients: readonly CampaignRecipient[];
|
|
58
|
+
encryptor: EncryptorSource;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* One recipient's encrypted allocation, ready to be fed to {@link buildMerkleTree}.
|
|
62
|
+
*
|
|
63
|
+
* @alpha
|
|
64
|
+
*/
|
|
65
|
+
export interface EncryptedCampaignLeaf extends MerkleLeafInput {
|
|
66
|
+
/** The KMS input proof binding `handle` to `(instance, recipient)`. Required at claim time, unused by the tree. */
|
|
67
|
+
inputProof: Hex;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Inputs for {@link encryptCampaignAmounts}.
|
|
71
|
+
*
|
|
72
|
+
* @alpha
|
|
73
|
+
*/
|
|
74
|
+
export interface EncryptCampaignAmountsArgs {
|
|
75
|
+
/** The LIVE `MerkleConfidentialAirdrop` instance every input is bound to. Not the factory, not the implementation. */
|
|
76
|
+
instance: Address;
|
|
77
|
+
recipients: readonly CampaignRecipient[];
|
|
78
|
+
encryptor: EncryptorSource;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Encrypt a plaintext roster into per-recipient handles, without building a tree.
|
|
82
|
+
*
|
|
83
|
+
* Use this when you want the two stages apart — to persist the handles before
|
|
84
|
+
* publishing a root, or to hand them to something else that builds the tree.
|
|
85
|
+
* If you just want a campaign, {@link buildMerkleCampaign} does both.
|
|
86
|
+
*
|
|
87
|
+
* **One relayer request per recipient, issued concurrently.** Each input binds
|
|
88
|
+
* to `(instance, that recipient)`, so they cannot share a proof: a single
|
|
89
|
+
* batched proof binds every value to one account and produces a campaign only
|
|
90
|
+
* that account can claim against.
|
|
91
|
+
*
|
|
92
|
+
* **The output is not reproducible.** Encryption is randomised, so calling this
|
|
93
|
+
* twice with the same roster yields different handles and therefore a different
|
|
94
|
+
* root. Persist what you get back; you cannot regenerate it.
|
|
95
|
+
*
|
|
96
|
+
* @param args The live instance, the roster, and an eager or lazy encryptor.
|
|
97
|
+
* @returns One `{ recipient, handle, inputProof }` per roster entry, in roster order.
|
|
98
|
+
* @throws {@link InvalidArgumentError} on any roster problem {@link validateCampaignRecipients} rejects, or a zero `instance`.
|
|
99
|
+
* @throws {@link MissingEncryptorError} when `encryptor` resolves to `undefined`.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* const leaves = await encryptCampaignAmounts({ instance: airdrop, recipients, encryptor });
|
|
103
|
+
* const { root, entries } = buildMerkleTree({ instance: airdrop, leaves });
|
|
104
|
+
*
|
|
105
|
+
* @alpha
|
|
106
|
+
*/
|
|
107
|
+
export declare function encryptCampaignAmounts(args: EncryptCampaignAmountsArgs): Promise<readonly EncryptedCampaignLeaf[]>;
|
|
108
|
+
/**
|
|
109
|
+
* Encrypt every recipient's cumulative total against their own address, then
|
|
110
|
+
* build the tree those ciphertexts belong to.
|
|
111
|
+
*
|
|
112
|
+
* Use this on the **mutable-root** path: the instance already exists, so its
|
|
113
|
+
* address is known and encryption can bind to it directly. Publish the returned
|
|
114
|
+
* `root` with {@link MerkleAirdropClient.setMerkleRoot} — or let
|
|
115
|
+
* {@link rotateMerkleRoot} do both in one call. For an instance whose root is
|
|
116
|
+
* fixed at create time, use {@link planMerkleCampaign} instead: this function
|
|
117
|
+
* cannot help you, because there is no address to encrypt against yet.
|
|
118
|
+
*
|
|
119
|
+
* **Distribution is yours.** The returned `entries` are the campaign — nothing
|
|
120
|
+
* about them is recoverable from the chain. The instance stores only the
|
|
121
|
+
* 32-byte root; there is no getter that maps an account to its handle, its
|
|
122
|
+
* input proof, or its Merkle branch, and no event that emits them. A recipient
|
|
123
|
+
* who does not hold their own `(handle, inputProof, merkleProof)` triple cannot
|
|
124
|
+
* claim, and no amount of on-chain data will reconstruct it. Persist the
|
|
125
|
+
* entries when this resolves and serve each recipient theirs.
|
|
126
|
+
*
|
|
127
|
+
* **One relayer request per recipient, issued concurrently.** Each input has a
|
|
128
|
+
* different `userAddress`, so they cannot share a proof — see the note on
|
|
129
|
+
* `encryptUint64Batch` below. Large rosters fan out correspondingly; chunk the
|
|
130
|
+
* roster yourself if your relayer rate-limits.
|
|
131
|
+
*
|
|
132
|
+
* **Already hold the handles?** This function encrypts unconditionally, and
|
|
133
|
+
* encryption is randomised — so re-encrypting handles that exist elsewhere
|
|
134
|
+
* produces a tree committing to handles nobody holds. Use
|
|
135
|
+
* {@link buildMerkleTree} directly instead.
|
|
136
|
+
*
|
|
137
|
+
* @param args The live instance, the roster, and an eager or lazy encryptor.
|
|
138
|
+
* @returns The root to publish and one proof-bearing {@link CampaignEntry} per recipient, in roster order.
|
|
139
|
+
* @throws {@link InvalidArgumentError} on any roster problem {@link validateCampaignRecipients} rejects, or a zero `instance`.
|
|
140
|
+
* @throws {@link MissingEncryptorError} when `encryptor` resolves to `undefined`.
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* const { root, entries } = await buildMerkleCampaign({
|
|
144
|
+
* instance: airdrop.address,
|
|
145
|
+
* recipients: [{ recipient: alice, cumulativeTotal: 1_000_000n }],
|
|
146
|
+
* encryptor,
|
|
147
|
+
* });
|
|
148
|
+
* await airdrop.setMerkleRoot({ newRoot: root });
|
|
149
|
+
* // then hand `entries[i]` to `entries[i].recipient`, out of band
|
|
150
|
+
*
|
|
151
|
+
* @alpha
|
|
152
|
+
*/
|
|
153
|
+
export declare function buildMerkleCampaign({ instance, recipients, encryptor, }: BuildMerkleCampaignArgs): Promise<BuiltCampaign>;
|
|
154
|
+
/**
|
|
155
|
+
* Inputs for {@link planMerkleCampaign}.
|
|
156
|
+
*
|
|
157
|
+
* @alpha
|
|
158
|
+
*/
|
|
159
|
+
export interface PlanMerkleCampaignArgs {
|
|
160
|
+
factory: ConfidentialAirdropFactoryClient;
|
|
161
|
+
/** The exact params the subsequent `createMerkleAirdrop` will use, except `merkleRoot` — supply the planned root there. */
|
|
162
|
+
params: MerkleAirdropParams;
|
|
163
|
+
mode: DeploymentMode;
|
|
164
|
+
/** The account that will send `createMerkleAirdrop`. CREATE2 salts are per-deployer. */
|
|
165
|
+
creator: Address;
|
|
166
|
+
userSalt: Hex;
|
|
167
|
+
recipients: readonly CampaignRecipient[];
|
|
168
|
+
encryptor: EncryptorSource;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* A campaign built against a not-yet-deployed instance, plus the evidence needed to trust the prediction.
|
|
172
|
+
*
|
|
173
|
+
* @alpha
|
|
174
|
+
*/
|
|
175
|
+
export interface PlannedCampaign extends BuiltCampaign {
|
|
176
|
+
/** Where `createMerkleAirdrop({ mode, userSalt })` from `creator` will land. Every entry is bound to this address. */
|
|
177
|
+
predictedAddress: Address;
|
|
178
|
+
/** The factory's Merkle init-code hash read BEFORE the address was predicted. */
|
|
179
|
+
initCodeHashBefore: Hex;
|
|
180
|
+
/** The same hash read AFTER. Always equal to `initCodeHashBefore` on a returned plan - a difference throws instead. */
|
|
181
|
+
initCodeHashAfter: Hex;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Build a campaign for an instance that does not exist yet, so its root can be
|
|
185
|
+
* baked in at create time.
|
|
186
|
+
*
|
|
187
|
+
* This is the **immutable-root** path, and it exists because that path is
|
|
188
|
+
* otherwise circular: the root must be known before `createMerkleAirdrop`, the
|
|
189
|
+
* root depends on every recipient's ciphertext, and every ciphertext is bound
|
|
190
|
+
* to the instance address `createMerkleAirdrop` has not produced yet. The
|
|
191
|
+
* factory's `predictMerkleAirdropAddress` oracle breaks it — encryption binds
|
|
192
|
+
* to the predicted address, and the create call then lands exactly there.
|
|
193
|
+
*
|
|
194
|
+
* **Passing the planned root back in `params` is safe.** A predicted address
|
|
195
|
+
* commits only to `(implementation, mode, deployer, userSalt)`; the params
|
|
196
|
+
* struct is accepted by the oracle and ignored
|
|
197
|
+
* (`predictECDSAAirdropAddress` does not even name its params argument). So
|
|
198
|
+
* calling this with a placeholder root and then creating with the real one does
|
|
199
|
+
* not move the address. The corollary is the trap: two campaigns sharing a
|
|
200
|
+
* `(variant, mode, creator, userSalt)` tuple predict the SAME address however
|
|
201
|
+
* different their params — pick a fresh `userSalt` per campaign.
|
|
202
|
+
*
|
|
203
|
+
* **Drift is judged, the rest is not.** The factory's Merkle init-code hash is
|
|
204
|
+
* read once BEFORE `predictMerkleAirdropAddress` and once AFTER the campaign
|
|
205
|
+
* is built, so the window brackets the prediction itself as well as the
|
|
206
|
+
* build — an implementation-pointer swap landing in either gap is caught. A
|
|
207
|
+
* difference between the two means the factory's Merkle implementation
|
|
208
|
+
* pointer moved and `predictedAddress` is stale: every entry would be bound
|
|
209
|
+
* to an address the create will not produce, so this function throws
|
|
210
|
+
* {@link PredictionDriftError} rather than hand back a campaign that cannot
|
|
211
|
+
* be claimed. Both observations are still returned on the success path, for
|
|
212
|
+
* callers that want to record them. What it does NOT check is whether
|
|
213
|
+
* `creator` may deploy `mode` and whether the salt is free - run
|
|
214
|
+
* `preflightCreate` (`./guards.js`) for those, or let `createMerkleAirdrop`
|
|
215
|
+
* enforce them at send time.
|
|
216
|
+
*
|
|
217
|
+
* **Distribution is yours** — same as {@link buildMerkleCampaign}: the chain
|
|
218
|
+
* keeps only the root, so each recipient must be handed their own
|
|
219
|
+
* `(handle, inputProof, merkleProof)` out of band or they cannot claim.
|
|
220
|
+
*
|
|
221
|
+
* @param args The factory client, the create arguments the campaign is planned against, the roster and an encryptor.
|
|
222
|
+
* @returns The built campaign, the predicted instance address, and the two init-code-hash observations.
|
|
223
|
+
* @throws {@link InvalidArgumentError} on any roster problem {@link validateCampaignRecipients} rejects.
|
|
224
|
+
* @throws {@link MissingEncryptorError} when `encryptor` resolves to `undefined`.
|
|
225
|
+
* @throws {@link PredictionDriftError} when the factory's Merkle implementation pointer moved mid-build.
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* const plan = await planMerkleCampaign({
|
|
229
|
+
* factory, params, mode: "clone", creator, userSalt, recipients, encryptor,
|
|
230
|
+
* });
|
|
231
|
+
* await factory.createMerkleAirdrop({
|
|
232
|
+
* params: { ...params, merkleRoot: plan.root, isMerkleRootMutable: false },
|
|
233
|
+
* mode: "clone",
|
|
234
|
+
* userSalt,
|
|
235
|
+
* });
|
|
236
|
+
*
|
|
237
|
+
* @alpha
|
|
238
|
+
*/
|
|
239
|
+
export declare function planMerkleCampaign({ factory, params, mode, creator, userSalt, recipients, encryptor, }: PlanMerkleCampaignArgs): Promise<PlannedCampaign>;
|
|
240
|
+
/**
|
|
241
|
+
* Inputs for {@link rotateMerkleRoot}.
|
|
242
|
+
*
|
|
243
|
+
* @alpha
|
|
244
|
+
*/
|
|
245
|
+
export interface RotateMerkleRootArgs extends WriteAccountOverride {
|
|
246
|
+
/** The live instance. Its `address` is read off the client — nothing is predicted here. */
|
|
247
|
+
airdrop: MerkleAirdropClient;
|
|
248
|
+
/** The FULL updated roster: cumulative totals, not the deltas since the last root. */
|
|
249
|
+
recipients: readonly CampaignRecipient[];
|
|
250
|
+
encryptor: EncryptorSource;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* A rebuilt campaign together with the transaction that published its root.
|
|
254
|
+
*
|
|
255
|
+
* @alpha
|
|
256
|
+
*/
|
|
257
|
+
export interface RotatedCampaign extends BuiltCampaign {
|
|
258
|
+
/** The `setMerkleRoot` transaction hash. */
|
|
259
|
+
hash: Hex;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Republish a campaign with updated cumulative totals: rebuild every entry
|
|
263
|
+
* against the live instance, then set the new root.
|
|
264
|
+
*
|
|
265
|
+
* **A rotation is a top-up, not a second payout.** `claimedAmount` survives the
|
|
266
|
+
* rotation, and a claim against the new root pays
|
|
267
|
+
* `newTotal - min(newTotal, alreadyDelivered)` — so `recipients` must carry
|
|
268
|
+
* each account's new CUMULATIVE total, never the increment. Passing increments
|
|
269
|
+
* pays out the increment minus everything already delivered, which for most
|
|
270
|
+
* rosters is encrypted zero. A total lower than what an account already
|
|
271
|
+
* received pays nothing; a rotation cannot claw back.
|
|
272
|
+
*
|
|
273
|
+
* Every entry is re-encrypted because the tree commits to handles, and a new
|
|
274
|
+
* total is a new ciphertext. Entries from the previous root do not survive:
|
|
275
|
+
* once the root moves, the old proofs no longer verify. **Distribute the new
|
|
276
|
+
* entries to every recipient**, including the ones whose total was unchanged —
|
|
277
|
+
* the chain stores only the root, so an un-updated recipient is simply stuck.
|
|
278
|
+
*
|
|
279
|
+
* Requires `MERKLE_ADMIN_ROLE` on the instance and an instance created with
|
|
280
|
+
* `isMerkleRootMutable: true`.
|
|
281
|
+
*
|
|
282
|
+
* @param args The live client, the full updated roster, an encryptor and an optional sending account.
|
|
283
|
+
* @returns The new root, the rebuilt entries, and the `setMerkleRoot` transaction hash.
|
|
284
|
+
* @throws {@link InvalidArgumentError} on any roster problem {@link validateCampaignRecipients} rejects.
|
|
285
|
+
* @throws {@link MissingEncryptorError} when `encryptor` resolves to `undefined`.
|
|
286
|
+
* @throws {@link FeatureDisabledError} when the instance was created with `isMerkleRootMutable: false`.
|
|
287
|
+
*
|
|
288
|
+
* @example
|
|
289
|
+
* const { root, entries, hash } = await rotateMerkleRoot({
|
|
290
|
+
* airdrop,
|
|
291
|
+
* recipients: [{ recipient: alice, cumulativeTotal: 1_500_000n }], // was 1_000_000n
|
|
292
|
+
* encryptor,
|
|
293
|
+
* });
|
|
294
|
+
*
|
|
295
|
+
* @alpha
|
|
296
|
+
*/
|
|
297
|
+
export declare function rotateMerkleRoot({ airdrop, recipients, encryptor, account, }: RotateMerkleRootArgs): Promise<RotatedCampaign>;
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import type { Address, Hex, PublicClient, WalletClient } from "viem";
|
|
2
|
+
import { type SdkTelemetry } from "../core/telemetry.js";
|
|
3
|
+
import type { WriteAccountOverride } from "./airdrop-base.js";
|
|
4
|
+
/**
|
|
5
|
+
* Whether `error` is the relayer's transient "the ACL hasn't propagated to
|
|
6
|
+
* the gateway yet" condition — as opposed to a genuine, non-retryable
|
|
7
|
+
* failure (a malformed handle, an unauthenticated request, an unrelated
|
|
8
|
+
* server error, etc.).
|
|
9
|
+
*
|
|
10
|
+
* **Why this exists:** after {@link ComplianceManagerClient.addDelegate}
|
|
11
|
+
* lands, a delegate is authorized on-chain immediately, but the gateway that
|
|
12
|
+
* serves a delegated read needs time to observe that change. Calling it in
|
|
13
|
+
* that window fails with the *same* HTTP status a permission failure or an
|
|
14
|
+
* unrelated server error would use, so a caller that treats every failure of
|
|
15
|
+
* that status as "access denied" will conclude the delegation is broken and
|
|
16
|
+
* go debug the wrong thing, when the correct response is to retry with
|
|
17
|
+
* backoff.
|
|
18
|
+
*
|
|
19
|
+
* The SDK does not call the relayer's delegated-decrypt itself (that call
|
|
20
|
+
* belongs to the relayer client the consumer already holds) — this function
|
|
21
|
+
* only classifies whatever error that call throws, so a caller can
|
|
22
|
+
* distinguish "retry me" from "this delegation really doesn't exist."
|
|
23
|
+
*
|
|
24
|
+
* **What counts as a match**, verified against the shipped `@zama-fhe/sdk`
|
|
25
|
+
* source rather than assumed (see the module comment above):
|
|
26
|
+
* - `error.code === "DELEGATION_NOT_PROPAGATED"` or
|
|
27
|
+
* `error.name === "DelegationNotPropagatedError"` — an exact discriminator,
|
|
28
|
+
* true regardless of status or message. This is how the SDK's own
|
|
29
|
+
* `ConfidentialFungibleToken#decryptBalanceAs` reports the condition, and
|
|
30
|
+
* that error carries no status field at all.
|
|
31
|
+
* - Otherwise, a status of `400` **or** `500` (read from `.status`,
|
|
32
|
+
* `.statusCode`, `.cause.status`, or `.cause.statusCode` — a raw relayer
|
|
33
|
+
* error may report it on any of those four) combined with a message (read
|
|
34
|
+
* from `.message` or `.cause.message`) that names the propagation
|
|
35
|
+
* condition — see {@link matchesPropagationMessage}.
|
|
36
|
+
*
|
|
37
|
+
* **Erring broad is the correct trade-off here**, not erring narrow: this
|
|
38
|
+
* classifier only gates whether a caller retries a read. A false positive
|
|
39
|
+
* costs a handful of unnecessary retries; a false negative sends an engineer
|
|
40
|
+
* to debug correct delegation wiring that was never broken. The matcher is
|
|
41
|
+
* therefore permissive about status and phrasing, while still refusing to
|
|
42
|
+
* classify a message that says nothing about propagation — an unrelated 400
|
|
43
|
+
* or 500 (bad signature, malformed handle, a genuine outage) still returns
|
|
44
|
+
* `false`.
|
|
45
|
+
*
|
|
46
|
+
* @param error The error thrown by a relayer's delegated-decrypt call — a
|
|
47
|
+
* plain object, an `Error` subclass, or the `@zama-fhe/sdk` package's own
|
|
48
|
+
* `DelegationNotPropagatedError` / `RelayerRequestFailedError` all satisfy
|
|
49
|
+
* this; only duck-typed field access is used, so no import of
|
|
50
|
+
* `@zama-fhe/sdk` (an optional peer dependency) is required.
|
|
51
|
+
* @returns `true` for the propagation condition, in any of the shapes above.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* try {
|
|
55
|
+
* await relayer.delegatedUserDecrypt({ handle, delegate });
|
|
56
|
+
* } catch (err) {
|
|
57
|
+
* if (isAclPropagationError(err)) {
|
|
58
|
+
* // retry with backoff — the delegation is fine, the gateway just hasn't caught up yet
|
|
59
|
+
* } else {
|
|
60
|
+
* throw err;
|
|
61
|
+
* }
|
|
62
|
+
* }
|
|
63
|
+
*
|
|
64
|
+
* @alpha
|
|
65
|
+
*/
|
|
66
|
+
export declare function isAclPropagationError(error: unknown): boolean;
|
|
67
|
+
/** @alpha */
|
|
68
|
+
export interface ComplianceManagerClientConfig {
|
|
69
|
+
publicClient: PublicClient;
|
|
70
|
+
walletClient?: WalletClient | undefined;
|
|
71
|
+
/** The `ComplianceRoleManager` clone — read it off `factory.createX(...)`'s result, or `factory.complianceManagerOf(airdrop)`. */
|
|
72
|
+
address: Address;
|
|
73
|
+
/**
|
|
74
|
+
* Chain id used for the support check. Defaults to `publicClient.chain?.id`;
|
|
75
|
+
* one of the two must resolve, because the client refuses to talk to a
|
|
76
|
+
* chain it cannot name.
|
|
77
|
+
*/
|
|
78
|
+
chainId?: number | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* Optional telemetry sink. When provided, the SDK emits a
|
|
81
|
+
* `fhe-airdrop.client.init` event on construction and brackets write
|
|
82
|
+
* methods with named spans (`fhe-airdrop.compliance.addDelegate`, …).
|
|
83
|
+
* Defaults to a no-op.
|
|
84
|
+
*/
|
|
85
|
+
telemetry?: SdkTelemetry | undefined;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Client for one `ComplianceRoleManager` clone — the per-airdrop-instance
|
|
89
|
+
* contract that holds account-level user-decryption delegations, so a
|
|
90
|
+
* compliance team or platform operator can decrypt an airdrop's handles
|
|
91
|
+
* without the airdrop contract itself granting them ACL one handle at a time.
|
|
92
|
+
*
|
|
93
|
+
* One clone serves exactly one airdrop instance (see {@link airdrop}), is
|
|
94
|
+
* created and `initialize`d atomically by the factory inside `createX(...)` —
|
|
95
|
+
* **this client never exposes `initialize`**, since calling it directly would
|
|
96
|
+
* either revert (already initialized) or, on a stand-alone clone nobody else
|
|
97
|
+
* has wired, produce a delegation nobody intended. There is consequently no
|
|
98
|
+
* externally observable "deployed but not yet wired" state: by the time an
|
|
99
|
+
* address is reachable through this client, `initialize` has already run.
|
|
100
|
+
*
|
|
101
|
+
* Two delegate slots exist per clone:
|
|
102
|
+
* - **The platform compliance delegate** — set once, at `initialize`, iff the
|
|
103
|
+
* factory's compliance policy was ON for that creator at create time.
|
|
104
|
+
* {@link complianceDelegate} returns the zero address when the policy was
|
|
105
|
+
* OFF; because of the point above, a zero return is unambiguous — it always
|
|
106
|
+
* means "this clone was created with the policy off," never "not wired
|
|
107
|
+
* yet." This delegate is **irrevocable by construction**: no method on this
|
|
108
|
+
* contract (or this client) ever revokes it.
|
|
109
|
+
* - **Client delegates** — zero or more addresses the client adds/removes
|
|
110
|
+
* itself via {@link addDelegate} / {@link revokeDelegate}, gated by
|
|
111
|
+
* {@link DELEGATION_ADMIN_ROLE}.
|
|
112
|
+
*
|
|
113
|
+
* **The propagation gotcha** (see {@link isAclPropagationError}'s TSDoc for
|
|
114
|
+
* the full mechanics): {@link addDelegate} and {@link revokeDelegate} are
|
|
115
|
+
* effective on-chain the instant their transaction lands, but the Zama
|
|
116
|
+
* gateway that serves a delegated read observes that change out of band, with
|
|
117
|
+
* a lag. A caller who wires a delegate and immediately attempts a delegated
|
|
118
|
+
* decrypt should expect the SDK-observed shapes of this condition — an HTTP
|
|
119
|
+
* 400 reading "ACL check not propagated" from the gateway directly, or, via
|
|
120
|
+
* `@zama-fhe/sdk`'s own `decryptBalanceAs`, an HTTP 500 wrapped as a
|
|
121
|
+
* `DelegationNotPropagatedError` — for a short window (the SDK's own guidance
|
|
122
|
+
* is 1-2 minutes), and should **retry with backoff** rather than conclude the
|
|
123
|
+
* delegation failed. This client does not call the relayer's delegated-decrypt
|
|
124
|
+
* itself (that belongs to whatever relayer client the consumer already
|
|
125
|
+
* holds); it only gives you {@link isAclPropagationError} to classify the
|
|
126
|
+
* error that call throws.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* const compliance = new ComplianceManagerClient({ publicClient, walletClient, address });
|
|
130
|
+
* await compliance.addDelegate({ delegate: complianceOfficer });
|
|
131
|
+
* // ... later, from wherever `delegatedUserDecrypt` is called:
|
|
132
|
+
* // if (isAclPropagationError(err)) { retry with backoff; }
|
|
133
|
+
*
|
|
134
|
+
* @alpha
|
|
135
|
+
*/
|
|
136
|
+
export declare class ComplianceManagerClient {
|
|
137
|
+
#private;
|
|
138
|
+
readonly publicClient: PublicClient;
|
|
139
|
+
readonly walletClient?: WalletClient | undefined;
|
|
140
|
+
readonly address: Address;
|
|
141
|
+
readonly chainId: number;
|
|
142
|
+
constructor(config: ComplianceManagerClientConfig);
|
|
143
|
+
/**
|
|
144
|
+
* Add a client delegate: grants `delegate` permanent (never-expiring)
|
|
145
|
+
* user-decryption delegation over this clone's airdrop. Requires
|
|
146
|
+
* {@link DELEGATION_ADMIN_ROLE}.
|
|
147
|
+
*
|
|
148
|
+
* Effective on-chain immediately; see the class TSDoc for the gateway
|
|
149
|
+
* propagation lag before `delegatedUserDecrypt` catches up.
|
|
150
|
+
*
|
|
151
|
+
* @throws {@link InvalidArgumentError} (`argument: "delegate"`) when `delegate` is the zero address
|
|
152
|
+
* (`ZeroDelegate`), already an active client delegate (`DelegateAlreadyAdded`), or targets the
|
|
153
|
+
* irrevocable platform compliance delegate (`CannotManageComplianceDelegate`).
|
|
154
|
+
* @returns The transaction hash.
|
|
155
|
+
*/
|
|
156
|
+
addDelegate(args: {
|
|
157
|
+
delegate: Address;
|
|
158
|
+
} & WriteAccountOverride): Promise<Hex>;
|
|
159
|
+
/**
|
|
160
|
+
* Revoke a client delegate. Requires {@link DELEGATION_ADMIN_ROLE}.
|
|
161
|
+
*
|
|
162
|
+
* Effective on-chain immediately — but off-chain, gateway-served
|
|
163
|
+
* `delegatedUserDecrypt` calls stop succeeding only once the gateway
|
|
164
|
+
* observes the revocation, which is not instantaneous either. Cannot target
|
|
165
|
+
* the platform compliance delegate, which is irrevocable by construction.
|
|
166
|
+
*
|
|
167
|
+
* **Not in the same block as {@link addDelegate} for the same delegate.**
|
|
168
|
+
* The FHEVM ACL rejects an add and a revoke of one delegate within a single
|
|
169
|
+
* block (`AlreadyDelegatedOrRevokedInSameBlock`), and because that revert
|
|
170
|
+
* comes from the ACL rather than from this contract, it surfaces as an
|
|
171
|
+
* opaque {@link ContractRevertError} with no decodable selector — nothing
|
|
172
|
+
* names the delegate or the cause. Batching an add and a revoke into one
|
|
173
|
+
* multicall, or sending both inside one block, is the way to hit it; wait a
|
|
174
|
+
* block between them. This is the sequencing counterpart to the propagation
|
|
175
|
+
* gotcha on the class TSDoc: that one is the gateway lagging the chain, this
|
|
176
|
+
* one is the chain refusing two conflicting writes at the same height.
|
|
177
|
+
*
|
|
178
|
+
* @throws {@link InvalidArgumentError} (`argument: "delegate"`) when `delegate` is the zero address
|
|
179
|
+
* (`ZeroDelegate`), not currently an active client delegate (`DelegateNotFound`), or targets the
|
|
180
|
+
* irrevocable platform compliance delegate (`CannotManageComplianceDelegate`).
|
|
181
|
+
* @returns The transaction hash.
|
|
182
|
+
*/
|
|
183
|
+
revokeDelegate(args: {
|
|
184
|
+
delegate: Address;
|
|
185
|
+
} & WriteAccountOverride): Promise<Hex>;
|
|
186
|
+
/** The one airdrop instance this clone serves — set once, at `initialize`. */
|
|
187
|
+
airdrop(): Promise<Address>;
|
|
188
|
+
/**
|
|
189
|
+
* The platform compliance delegate.
|
|
190
|
+
*
|
|
191
|
+
* @returns The delegate address, or the zero address when this clone was
|
|
192
|
+
* created with the platform compliance policy OFF. Because `initialize`
|
|
193
|
+
* always runs atomically before this client can reach the clone (see the
|
|
194
|
+
* class TSDoc), a zero return never means "not wired yet" — there is no
|
|
195
|
+
* such observable state on this contract. It unambiguously means "no
|
|
196
|
+
* platform delegate for this airdrop."
|
|
197
|
+
*/
|
|
198
|
+
complianceDelegate(): Promise<Address>;
|
|
199
|
+
/** The current set of active client delegates (excludes the platform compliance delegate, if any). */
|
|
200
|
+
clientDelegates(): Promise<readonly Address[]>;
|
|
201
|
+
/**
|
|
202
|
+
* Authoritative active-delegate check for `delegate` — reads the ACL
|
|
203
|
+
* expiration date directly rather than the contract's `EnumerableSet`
|
|
204
|
+
* mirror, so it reflects the platform compliance delegate too (which never
|
|
205
|
+
* appears in {@link clientDelegates}).
|
|
206
|
+
*
|
|
207
|
+
* On-chain truth only: a `true` result means the delegation is live in the
|
|
208
|
+
* ACL, not that the gateway has caught up with it yet — see the class
|
|
209
|
+
* TSDoc's propagation note.
|
|
210
|
+
*/
|
|
211
|
+
isActiveDelegate(delegate: Address): Promise<boolean>;
|
|
212
|
+
/** Gates {@link addDelegate} / {@link revokeDelegate}. */
|
|
213
|
+
DELEGATION_ADMIN_ROLE(): Promise<Hex>;
|
|
214
|
+
/**
|
|
215
|
+
* OpenZeppelin's root role (`bytes32(0)`), read from the clone rather than
|
|
216
|
+
* hard-coded. It administers {@link DELEGATION_ADMIN_ROLE}.
|
|
217
|
+
*/
|
|
218
|
+
DEFAULT_ADMIN_ROLE(): Promise<Hex>;
|
|
219
|
+
/**
|
|
220
|
+
* Whether `holder` holds `role`.
|
|
221
|
+
*
|
|
222
|
+
* The role subject is called `holder`, not `account`: on the writes below
|
|
223
|
+
* `account` already means "who sends this transaction", and one key cannot
|
|
224
|
+
* be both.
|
|
225
|
+
*
|
|
226
|
+
* @param args.role A `bytes32` from {@link DELEGATION_ADMIN_ROLE} or {@link DEFAULT_ADMIN_ROLE}.
|
|
227
|
+
*/
|
|
228
|
+
hasRole(args: {
|
|
229
|
+
role: Hex;
|
|
230
|
+
holder: Address;
|
|
231
|
+
}): Promise<boolean>;
|
|
232
|
+
/** The role whose holders may {@link grantRole} and {@link revokeRole} `role`. */
|
|
233
|
+
getRoleAdmin(role: Hex): Promise<Hex>;
|
|
234
|
+
/** How many accounts hold `role`. */
|
|
235
|
+
getRoleMemberCount(role: Hex): Promise<bigint>;
|
|
236
|
+
/**
|
|
237
|
+
* The `index`-th holder of `role`, in `EnumerableSet` order - which is not
|
|
238
|
+
* stable across grants and revokes. Prefer {@link getRoleMembers}.
|
|
239
|
+
*/
|
|
240
|
+
getRoleMember(args: {
|
|
241
|
+
role: Hex;
|
|
242
|
+
index: bigint;
|
|
243
|
+
}): Promise<Address>;
|
|
244
|
+
/**
|
|
245
|
+
* Every account currently holding `role`.
|
|
246
|
+
*
|
|
247
|
+
* With {@link DELEGATION_ADMIN_ROLE} this answers "who may add or revoke a
|
|
248
|
+
* delegate on this clone?" - the administrative counterpart to
|
|
249
|
+
* {@link clientDelegates}, which answers "who may currently decrypt?".
|
|
250
|
+
*/
|
|
251
|
+
getRoleMembers(role: Hex): Promise<readonly Address[]>;
|
|
252
|
+
/**
|
|
253
|
+
* Grant `role` to `holder`. Requires the role's admin role
|
|
254
|
+
* ({@link getRoleAdmin}).
|
|
255
|
+
*
|
|
256
|
+
* This is how a second operator is added to {@link DELEGATION_ADMIN_ROLE} -
|
|
257
|
+
* the delegation verbs themselves are unaffected, the grant only widens who
|
|
258
|
+
* may call them.
|
|
259
|
+
*
|
|
260
|
+
* @returns The transaction hash.
|
|
261
|
+
*/
|
|
262
|
+
grantRole(args: {
|
|
263
|
+
role: Hex;
|
|
264
|
+
holder: Address;
|
|
265
|
+
} & WriteAccountOverride): Promise<Hex>;
|
|
266
|
+
/**
|
|
267
|
+
* Revoke `role` from `holder`. Requires the role's admin role.
|
|
268
|
+
*
|
|
269
|
+
* Revoking a delegation admin does **not** revoke the delegations they
|
|
270
|
+
* created: an existing delegate keeps decrypting until
|
|
271
|
+
* {@link revokeDelegate} is called for it explicitly.
|
|
272
|
+
*
|
|
273
|
+
* @returns The transaction hash.
|
|
274
|
+
*/
|
|
275
|
+
revokeRole(args: {
|
|
276
|
+
role: Hex;
|
|
277
|
+
holder: Address;
|
|
278
|
+
} & WriteAccountOverride): Promise<Hex>;
|
|
279
|
+
/**
|
|
280
|
+
* Give up `role` yourself.
|
|
281
|
+
*
|
|
282
|
+
* The contract's signature is `renounceRole(role, callerConfirmation)` and
|
|
283
|
+
* it reverts `AccessControlBadConfirmation` unless `callerConfirmation` is
|
|
284
|
+
* the sender, so this method takes no holder and fills the confirmation from
|
|
285
|
+
* the resolved sending account. Renouncing for somebody else is not a call
|
|
286
|
+
* that can succeed; use {@link revokeRole} to remove another account's role.
|
|
287
|
+
*
|
|
288
|
+
* @returns The transaction hash.
|
|
289
|
+
*/
|
|
290
|
+
renounceRole(args: {
|
|
291
|
+
role: Hex;
|
|
292
|
+
} & WriteAccountOverride): Promise<Hex>;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Create a {@link ComplianceManagerClient}. Mirrors viem's `create*` convention.
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* const compliance = createComplianceManagerClient({ publicClient, walletClient, address });
|
|
299
|
+
*
|
|
300
|
+
* @alpha
|
|
301
|
+
*/
|
|
302
|
+
export declare function createComplianceManagerClient(config: ComplianceManagerClientConfig): ComplianceManagerClient;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contract commit every vendored ABI and deployed address in this module resolves against.
|
|
3
|
+
*
|
|
4
|
+
* @alpha
|
|
5
|
+
*/
|
|
6
|
+
export declare const AIRDROP_CONTRACTS_COMMIT = "8e5b144bdbcdf35b9f36b62f5257d795bf954e8e";
|
|
7
|
+
/**
|
|
8
|
+
* Deployment shell selected at create time. Mirrors the contract's `DeploymentMode` enum
|
|
9
|
+
* (`IConfidentialAirdropTypes.sol`): `enum DeploymentMode { Clone, UUPS }`.
|
|
10
|
+
*
|
|
11
|
+
* @alpha
|
|
12
|
+
*/
|
|
13
|
+
export declare const DEPLOYMENT_MODE: {
|
|
14
|
+
readonly clone: 0;
|
|
15
|
+
readonly uups: 1;
|
|
16
|
+
};
|
|
17
|
+
/** @alpha */
|
|
18
|
+
export type DeploymentMode = keyof typeof DEPLOYMENT_MODE;
|
|
19
|
+
/**
|
|
20
|
+
* Replay-protection policy for ECDSA campaigns. Mirrors the contract's `DedupMode` enum
|
|
21
|
+
* (`IECDSAConfidentialAirdropTypes.sol`):
|
|
22
|
+
* `enum DedupMode { PerAddress, PerDedupId, Both, None }`.
|
|
23
|
+
*
|
|
24
|
+
* @alpha
|
|
25
|
+
*/
|
|
26
|
+
export declare const DEDUP_MODE: {
|
|
27
|
+
readonly perAddress: 0;
|
|
28
|
+
readonly perDedupId: 1;
|
|
29
|
+
readonly both: 2;
|
|
30
|
+
readonly none: 3;
|
|
31
|
+
};
|
|
32
|
+
/** @alpha */
|
|
33
|
+
export type DedupMode = keyof typeof DEDUP_MODE;
|