@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
|
@@ -49,17 +49,15 @@ export interface ExtractGrantedHandleArgs {
|
|
|
49
49
|
* `Allowed` event survives the `account` filter, so the choice between first
|
|
50
50
|
* and last is moot today:
|
|
51
51
|
*
|
|
52
|
-
* - `adminGetCurrentBalance`
|
|
53
|
-
*
|
|
54
|
-
* - `adminDiscloseBalanceToParty` — a single `FHE.allow(balance, party)` (`:367`).
|
|
52
|
+
* - `adminGetCurrentBalance` - a single `FHE.allow(balance, msg.sender)`.
|
|
53
|
+
* - `adminDiscloseBalanceToParty` - a single `FHE.allow(balance, party)`.
|
|
55
54
|
* - `adminBatchDiscloseBalanceToParties` — N grants, but the balance is read
|
|
56
|
-
* once
|
|
57
|
-
*
|
|
55
|
+
* once and the *same* handle is fanned out, so every candidate carries an
|
|
56
|
+
* identical value and ordering cannot matter.
|
|
58
57
|
* - `getClaimAmount` on both variants — the sibling grants target other
|
|
59
58
|
* addresses: `FHE.allowThis` grants `address(this)` and `_grantCompliance`
|
|
60
|
-
* grants the manager clone
|
|
61
|
-
*
|
|
62
|
-
* `MerkleConfidentialAirdrop.sol:264-266`).
|
|
59
|
+
* grants the manager clone, leaving one grant to the preview's grantee: the
|
|
60
|
+
* caller on ECDSA (`getClaimAmount`), `account` on Merkle (`_outstandingOf`).
|
|
63
61
|
*
|
|
64
62
|
* Last-wins is therefore chosen for entrypoints that do not exist yet, over
|
|
65
63
|
* `fhe-vesting`'s throw-on-ambiguous: a future compound view that grants twice
|
|
@@ -68,12 +66,50 @@ export interface ExtractGrantedHandleArgs {
|
|
|
68
66
|
*
|
|
69
67
|
* Note what is NOT a motivating case: the Merkle `claim` path does grant an
|
|
70
68
|
* intermediate handle before the outstanding one, but `claim` /
|
|
71
|
-
* `claimAndUnwrap` return void (`IMerkleConfidentialAirdrop
|
|
69
|
+
* `claimAndUnwrap` return void (`IMerkleConfidentialAirdrop`), so
|
|
72
70
|
* they run as plain writes and their receipts never reach this function.
|
|
73
71
|
*
|
|
74
72
|
* @throws {@link ReceiptEventNotFoundError} when no `Allowed` event names `account`.
|
|
75
73
|
*/
|
|
76
74
|
export declare function extractGrantedHandle(args: ExtractGrantedHandleArgs): Hex;
|
|
75
|
+
/**
|
|
76
|
+
* The unwrap a `claimAndUnwrap` started, decoded from the instance's
|
|
77
|
+
* `ClaimedAndUnwrapInitiated` event.
|
|
78
|
+
*
|
|
79
|
+
* @alpha
|
|
80
|
+
*/
|
|
81
|
+
export interface UnwrapRequest {
|
|
82
|
+
/** The claim identity, which is always the claim transaction's sender. */
|
|
83
|
+
claimant: Address;
|
|
84
|
+
/** The underlying ERC-20 recipient that `finalizeUnwrap` pays. */
|
|
85
|
+
beneficiary: Address;
|
|
86
|
+
/** The ECDSA dedup key (claimant address or `dedupId`) or the Merkle leaf. */
|
|
87
|
+
claimKey: Hex;
|
|
88
|
+
/**
|
|
89
|
+
* The wrapper's unwrap request id, the input to its `finalizeUnwrap`. With the stock
|
|
90
|
+
* `ERC7984ERC20Wrapper` it is also the burned amount's handle, which the wrapper makes
|
|
91
|
+
* publicly decryptable in the claim transaction.
|
|
92
|
+
*/
|
|
93
|
+
unwrapRequestId: Hex;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* What {@link AirdropBaseClient.parseUnwrapRequest} reads: a viem receipt, or its logs.
|
|
97
|
+
*
|
|
98
|
+
* @alpha
|
|
99
|
+
*/
|
|
100
|
+
export type UnwrapRequestSource = readonly {
|
|
101
|
+
address: Address;
|
|
102
|
+
topics: readonly Hex[];
|
|
103
|
+
data: Hex;
|
|
104
|
+
}[] | {
|
|
105
|
+
logs: readonly {
|
|
106
|
+
address: Address;
|
|
107
|
+
topics: readonly Hex[];
|
|
108
|
+
data: Hex;
|
|
109
|
+
}[];
|
|
110
|
+
transactionHash?: Hex | undefined;
|
|
111
|
+
status?: "success" | "reverted" | undefined;
|
|
112
|
+
};
|
|
77
113
|
/** @alpha */
|
|
78
114
|
export interface AirdropBaseClientConfig {
|
|
79
115
|
publicClient: PublicClient;
|
|
@@ -137,11 +173,16 @@ export interface WriteAccountOverride {
|
|
|
137
173
|
* do not care about (an admin panel listing campaigns, say). The ECDSA and
|
|
138
174
|
* Merkle clients extend it and add their own claim path.
|
|
139
175
|
*
|
|
140
|
-
* What it encapsulates beyond the raw ABI is the encrypted-view protocol:
|
|
176
|
+
* What it encapsulates beyond the raw ABI is the encrypted-view protocol: six
|
|
141
177
|
* of the contract's disclosure entrypoints look like getters and are not —
|
|
142
178
|
* they mutate ACL state, so they are transactions, and their result must be
|
|
143
179
|
* recovered from the receipt. See {@link extractGrantedHandle}.
|
|
144
180
|
*
|
|
181
|
+
* Those encrypted views and disclosures have no `waitForReceipt: false` option
|
|
182
|
+
* for Safe / multisig signers: the handle is only useful to an account that
|
|
183
|
+
* can user-decrypt in-session, so run them from an EOA or a delegate. The other
|
|
184
|
+
* writes here return a bare hash and never wait on a receipt.
|
|
185
|
+
*
|
|
145
186
|
* @example
|
|
146
187
|
* const airdrop = new AirdropBaseClient({ publicClient, walletClient, address });
|
|
147
188
|
* const { handle } = await airdrop.adminGetCurrentBalance();
|
|
@@ -197,6 +238,10 @@ export declare class AirdropBaseClient {
|
|
|
197
238
|
* The amount is not a parameter and never appears in plaintext anywhere:
|
|
198
239
|
* the contract reads its own encrypted balance and moves all of it.
|
|
199
240
|
*
|
|
241
|
+
* Refused while the campaign is unpaused inside its claim window (`ClawbackRequiresPause`,
|
|
242
|
+
* surfaced as {@link ClawbackRequiresPauseError}): pause first, or run it outside the window
|
|
243
|
+
* (before `startTime` or after `endTime`).
|
|
244
|
+
*
|
|
200
245
|
* @returns The transaction hash.
|
|
201
246
|
*/
|
|
202
247
|
withdrawConfidential(args: {
|
|
@@ -213,12 +258,29 @@ export declare class AirdropBaseClient {
|
|
|
213
258
|
recipient: Address;
|
|
214
259
|
amount: bigint;
|
|
215
260
|
} & WriteAccountOverride): Promise<Hex>;
|
|
261
|
+
/**
|
|
262
|
+
* Sweep ETH that landed on a ZERO-FEE instance without running its code (a forced send,
|
|
263
|
+
* a transfer to the predicted address before deploy). Requires `RESCUER_ROLE`.
|
|
264
|
+
*
|
|
265
|
+
* Refused while `gasFee() > 0` (`NativeRescueRequiresZeroFee`, surfaced as
|
|
266
|
+
* {@link NativeRescueRequiresZeroFeeError}): on a fee-charging campaign the ETH is fee
|
|
267
|
+
* revenue and belongs to `withdrawGasFee`. Reverts `ZeroBalance` with nothing to sweep.
|
|
268
|
+
*
|
|
269
|
+
* @returns The transaction hash.
|
|
270
|
+
*/
|
|
271
|
+
rescueNativeToken(args: {
|
|
272
|
+
recipient: Address;
|
|
273
|
+
} & WriteAccountOverride): Promise<Hex>;
|
|
216
274
|
/**
|
|
217
275
|
* Sweep a plain ERC-20 that was sent to the instance by mistake. Requires
|
|
218
276
|
* `RESCUER_ROLE`.
|
|
219
277
|
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
278
|
+
* Passing the campaign's own token reverts `CannotRescueAirdropToken`
|
|
279
|
+
* (audit-05), matching {@link rescueOtherConfidentialToken}. ERC-7984 and
|
|
280
|
+
* ERC-20 are not disjoint in practice - a wrapper token answers both
|
|
281
|
+
* interfaces - so "the pool token is confidential, therefore out of reach
|
|
282
|
+
* here" was never a guarantee, only an assumption. Use
|
|
283
|
+
* {@link withdrawConfidential} for the pool.
|
|
222
284
|
*
|
|
223
285
|
* @returns The transaction hash.
|
|
224
286
|
*/
|
|
@@ -253,6 +315,10 @@ export declare class AirdropBaseClient {
|
|
|
253
315
|
endTime(): Promise<number>;
|
|
254
316
|
/** Whether claimants may unwrap to the underlying ERC-20 as part of a claim. */
|
|
255
317
|
unwrappable(): Promise<boolean>;
|
|
318
|
+
/** Whether `extendClaimWindow` is permitted on this instance; frozen at create. */
|
|
319
|
+
canExtendClaimWindow(): Promise<boolean>;
|
|
320
|
+
/** The block this instance was initialized in (L2 block on Arbitrum). */
|
|
321
|
+
deploymentBlockNumber(): Promise<bigint>;
|
|
256
322
|
/** The instance's own compliance-manager clone — the only contract granted ACL on campaign handles. */
|
|
257
323
|
complianceManager(): Promise<Address>;
|
|
258
324
|
/** Per-claim ETH fee in wei; `0` on a fee-free campaign. */
|
|
@@ -279,7 +345,7 @@ export declare class AirdropBaseClient {
|
|
|
279
345
|
WINDOW_ADMIN_ROLE(): Promise<Hex>;
|
|
280
346
|
/** Gates {@link withdrawConfidential}. */
|
|
281
347
|
TREASURY_ROLE(): Promise<Hex>;
|
|
282
|
-
/** Gates {@link rescueERC20} / {@link rescueOtherConfidentialToken}. */
|
|
348
|
+
/** Gates {@link rescueERC20} / {@link rescueOtherConfidentialToken} / {@link rescueNativeToken}. */
|
|
283
349
|
RESCUER_ROLE(): Promise<Hex>;
|
|
284
350
|
/** Gates {@link withdrawGasFee}. The contract refuses to leave it empty on a fee-charging campaign. */
|
|
285
351
|
FEE_COLLECTOR_ROLE(): Promise<Hex>;
|
|
@@ -469,10 +535,38 @@ export declare class AirdropBaseClient {
|
|
|
469
535
|
* @alpha
|
|
470
536
|
*/
|
|
471
537
|
deploymentMode(): Promise<DeploymentMode>;
|
|
538
|
+
/**
|
|
539
|
+
* Re-grant the compliance-manager clone on the instance's current pool
|
|
540
|
+
* balance, and return the handle it was granted on.
|
|
541
|
+
*
|
|
542
|
+
* **Permissionless, and deliberately so** (audit-04). The token rotates the
|
|
543
|
+
* instance's balance handle on every incoming transfer, including one no
|
|
544
|
+
* airdrop code observes - a third party transferring in directly - and
|
|
545
|
+
* grants the fresh handle to the token and the holder only. Without this the
|
|
546
|
+
* compliance clone's grant can be stranded on a handle the token has already
|
|
547
|
+
* replaced, with no admin necessarily around to restore it. There is no
|
|
548
|
+
* argument to abuse: the only handle read is `address(this)`'s own balance,
|
|
549
|
+
* and the only grantee is the clone wired at initialization.
|
|
550
|
+
*
|
|
551
|
+
* This is therefore the normative way to obtain a readable live-balance
|
|
552
|
+
* handle - and it is a **snapshot, not a subscription**. Grants are
|
|
553
|
+
* append-only, so the handle this returns stays readable forever; but the
|
|
554
|
+
* next incoming transfer rotates the instance to a NEW handle the clone was
|
|
555
|
+
* never granted on. A compliance reader that refreshes once and stops is
|
|
556
|
+
* reading a stale balance, not a live one. Call it again after any transfer
|
|
557
|
+
* in, or before each read.
|
|
558
|
+
*
|
|
559
|
+
* @returns `{ handle, hash }` - the handle the compliance clone may now decrypt.
|
|
560
|
+
* @throws {@link ReceiptEventNotFoundError} when the transaction granted no ACL to the clone.
|
|
561
|
+
*/
|
|
562
|
+
refreshComplianceBalance(args?: WriteAccountOverride): Promise<EncryptedViewResult>;
|
|
472
563
|
/**
|
|
473
564
|
* Read the instance's own remaining pool balance as a handle the **caller**
|
|
474
565
|
* can decrypt. Requires `DISCLOSURE_ADMIN_ROLE`.
|
|
475
566
|
*
|
|
567
|
+
* Also re-grants the compliance-manager clone on the same handle (audit-04),
|
|
568
|
+
* so an admin read doubles as a {@link refreshComplianceBalance}.
|
|
569
|
+
*
|
|
476
570
|
* @returns `{ handle, hash }` — pass `handle` to the Zama relayer's `userDecrypt`.
|
|
477
571
|
* @throws {@link ReceiptEventNotFoundError} when the transaction granted no ACL to the caller.
|
|
478
572
|
*/
|
|
@@ -515,11 +609,18 @@ export declare class AirdropBaseClient {
|
|
|
515
609
|
/**
|
|
516
610
|
* Grant `party` decrypt access to a handle you already hold.
|
|
517
611
|
*
|
|
518
|
-
* Two gates apply on-chain: the
|
|
519
|
-
*
|
|
520
|
-
*
|
|
521
|
-
*
|
|
522
|
-
*
|
|
612
|
+
* Two gates apply on-chain. Gate #1: the handle must be **persistently**
|
|
613
|
+
* user-decryptable in the `(caller, instance)` context - BOTH legs, and a
|
|
614
|
+
* transient allowance does not satisfy either (audit-06). `DISCLOSURE_ADMIN_ROLE`
|
|
615
|
+
* bypasses gate #1 only. Gate #2: the instance must be allowed on the handle,
|
|
616
|
+
* so an arbitrary handle from another contract cannot be laundered through
|
|
617
|
+
* this campaign.
|
|
618
|
+
*
|
|
619
|
+
* **The transient case is the trap.** An `euint64` that just came back from
|
|
620
|
+
* an FHE op carries a transient allowance, which used to be enough here and
|
|
621
|
+
* no longer is. Handles worth disclosing come from the encrypted views on
|
|
622
|
+
* this client, whose grants are persistent. A gate #1 failure surfaces as
|
|
623
|
+
* `FheHandleNotAllowedError` carrying the offending handle.
|
|
523
624
|
*
|
|
524
625
|
* @param args.handle An existing `euint64` handle — a public pointer, not a value.
|
|
525
626
|
* @returns The transaction hash. No new handle is produced.
|
|
@@ -539,6 +640,29 @@ export declare class AirdropBaseClient {
|
|
|
539
640
|
handles: readonly Hex[];
|
|
540
641
|
party: Address;
|
|
541
642
|
} & WriteAccountOverride): Promise<Hex>;
|
|
643
|
+
/**
|
|
644
|
+
* Decode the unwrap request a `claimAndUnwrap` started, from its receipt or logs.
|
|
645
|
+
*
|
|
646
|
+
* Pure: no RPC. Only this instance's `ClaimedAndUnwrapInitiated` counts, so a
|
|
647
|
+
* receipt that also carries another instance's event (a batched transaction) still
|
|
648
|
+
* resolves to this one. Pass the result's `unwrapRequestId` to the wrapper's
|
|
649
|
+
* `finalizeUnwrap`; with Zama's SDK that is
|
|
650
|
+
* `sdk.createToken(wrapper).finalizeUnwrap(unwrapRequestId)`, which fetches the
|
|
651
|
+
* public-decryption proof itself.
|
|
652
|
+
*
|
|
653
|
+
* @throws {@link ReceiptEventNotFoundError} when no such event from this instance is present.
|
|
654
|
+
* @throws {@link ReceiptEventAmbiguousError} when the transaction started more than one.
|
|
655
|
+
*/
|
|
656
|
+
parseUnwrapRequest(source: UnwrapRequestSource): UnwrapRequest;
|
|
657
|
+
/**
|
|
658
|
+
* Wait for the `claimAndUnwrap` transaction `hash` to be mined and decode the unwrap
|
|
659
|
+
* request it started; see {@link parseUnwrapRequest}.
|
|
660
|
+
*
|
|
661
|
+
* `hash` must be the on-chain transaction hash. A Safe returns a `safeTxHash`, which
|
|
662
|
+
* no node can wait on: resolve the executed transaction first, or pass its receipt to
|
|
663
|
+
* {@link parseUnwrapRequest}.
|
|
664
|
+
*/
|
|
665
|
+
readUnwrapRequest(hash: Hex): Promise<UnwrapRequest>;
|
|
542
666
|
/**
|
|
543
667
|
* Submit a transaction for a function that returns an encrypted handle via
|
|
544
668
|
* `FHE.allow`, and recover that handle from the receipt.
|
|
@@ -5,8 +5,19 @@ import type { ConfidentialAirdropFactoryClient } from "./factory.js";
|
|
|
5
5
|
import type { MerkleAirdropClient } from "./merkle.js";
|
|
6
6
|
import { type MerkleLeafInput } from "./merkle-tree.js";
|
|
7
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";
|
|
8
|
+
import type { BuiltCampaign, CampaignRecipient, MerkleAirdropParams, PlannedCampaign } from "./types.js";
|
|
9
|
+
export type { BuiltCampaign, CampaignEntry, CampaignRecipient, PlannedCampaign } from "./types.js";
|
|
10
|
+
/**
|
|
11
|
+
* Recipients per relayer request: an input ciphertext packs at most 2048 bits, so 2048 / 64
|
|
12
|
+
* euint64 values share one proof.
|
|
13
|
+
*
|
|
14
|
+
* `@zama-fhe/sdk` does not check this client-side, so the campaign builders chunk every
|
|
15
|
+
* roster to this size. Each entry carries its own chunk's proof, so a claim is identical
|
|
16
|
+
* whichever chunk its leaf came from.
|
|
17
|
+
*
|
|
18
|
+
* @alpha
|
|
19
|
+
*/
|
|
20
|
+
export declare const MERKLE_BATCH_LIMIT: number;
|
|
10
21
|
/**
|
|
11
22
|
* Reject the campaign shapes that produce an unusable or misleading tree,
|
|
12
23
|
* before any encryption work is done.
|
|
@@ -46,45 +57,12 @@ export declare function validateCampaignRecipients(recipients: readonly Campaign
|
|
|
46
57
|
* pattern as `buildMerkleTreeInternal` in `./merkle-tree.js`.
|
|
47
58
|
*/
|
|
48
59
|
export declare function validateCampaignRecipientsInternal(recipients: readonly CampaignRecipient[], method: string): void;
|
|
49
|
-
/**
|
|
50
|
-
* Who will submit the claims, for every builder that encrypts a roster.
|
|
51
|
-
*
|
|
52
|
-
* Follows the same shared-option pattern as `WriteAccountOverride`, because the choice
|
|
53
|
-
* applies identically to all four builders and is frozen once the root is published.
|
|
54
|
-
*
|
|
55
|
-
* @alpha
|
|
56
|
-
*/
|
|
57
|
-
export interface CampaignSubmitterOption {
|
|
58
|
-
/**
|
|
59
|
-
* The single address that will send every `claim` in this campaign.
|
|
60
|
-
*
|
|
61
|
-
* Omit for a **self-claim** campaign: each recipient's input is bound to that
|
|
62
|
-
* recipient, one relayer request each, and only they can claim.
|
|
63
|
-
*
|
|
64
|
-
* Set it for a **relayed** campaign: the whole roster is bound to this one address and
|
|
65
|
-
* batched, so a single `inputProof` covers up to 32 recipients and only this address
|
|
66
|
-
* can submit. That batching is the point — one proof cannot be bound to many
|
|
67
|
-
* addresses, so per-recipient binding and batching are mutually exclusive.
|
|
68
|
-
*
|
|
69
|
-
* An input ciphertext packs at most 2048 bits, so a `euint64` roster is chunked at 32
|
|
70
|
-
* recipients per request; a longer roster simply issues more requests. Nothing about a
|
|
71
|
-
* claim changes, since every chunk's proof is bound to the same submitter.
|
|
72
|
-
*
|
|
73
|
-
* Either way the leaf still commits each recipient's own `account`, so payout and
|
|
74
|
-
* accounting are unaffected by who submits.
|
|
75
|
-
*
|
|
76
|
-
* **Frozen at publication.** An FHEVM handle encodes its `(instance, userAddress)`
|
|
77
|
-
* binding, so re-pointing a leaf at a different submitter means re-encrypting, which
|
|
78
|
-
* changes the handle and therefore the root. Choose before publishing, not after.
|
|
79
|
-
*/
|
|
80
|
-
submitter?: Address;
|
|
81
|
-
}
|
|
82
60
|
/**
|
|
83
61
|
* Inputs for {@link buildMerkleCampaign}.
|
|
84
62
|
*
|
|
85
63
|
* @alpha
|
|
86
64
|
*/
|
|
87
|
-
export interface BuildMerkleCampaignArgs
|
|
65
|
+
export interface BuildMerkleCampaignArgs {
|
|
88
66
|
/** The LIVE `MerkleConfidentialAirdrop` instance every input is bound to. Not the factory, not the implementation. */
|
|
89
67
|
instance: Address;
|
|
90
68
|
recipients: readonly CampaignRecipient[];
|
|
@@ -96,9 +74,7 @@ export interface BuildMerkleCampaignArgs extends CampaignSubmitterOption {
|
|
|
96
74
|
* @alpha
|
|
97
75
|
*/
|
|
98
76
|
export interface EncryptedCampaignLeaf extends MerkleLeafInput {
|
|
99
|
-
/** The
|
|
100
|
-
boundTo: Address;
|
|
101
|
-
/** The KMS input proof binding `handle` to `(instance, boundTo)`. Required at claim time, unused by the tree. */
|
|
77
|
+
/** The KMS input proof binding `handle` to `(instance, instance)`. Required at claim time, unused by the tree. */
|
|
102
78
|
inputProof: Hex;
|
|
103
79
|
}
|
|
104
80
|
/**
|
|
@@ -106,7 +82,7 @@ export interface EncryptedCampaignLeaf extends MerkleLeafInput {
|
|
|
106
82
|
*
|
|
107
83
|
* @alpha
|
|
108
84
|
*/
|
|
109
|
-
export interface EncryptCampaignAmountsArgs
|
|
85
|
+
export interface EncryptCampaignAmountsArgs {
|
|
110
86
|
/** The LIVE `MerkleConfidentialAirdrop` instance every input is bound to. Not the factory, not the implementation. */
|
|
111
87
|
instance: Address;
|
|
112
88
|
recipients: readonly CampaignRecipient[];
|
|
@@ -119,17 +95,15 @@ export interface EncryptCampaignAmountsArgs extends CampaignSubmitterOption {
|
|
|
119
95
|
* publishing a root, or to hand them to something else that builds the tree.
|
|
120
96
|
* If you just want a campaign, {@link buildMerkleCampaign} does both.
|
|
121
97
|
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
* recipients (the 2048-bit input-ciphertext limit), every leaf claimable only by that
|
|
125
|
-
* submitter.
|
|
98
|
+
* One relayer request per 32 recipients, issued concurrently; every leaf is submittable
|
|
99
|
+
* by any address.
|
|
126
100
|
*
|
|
127
101
|
* **The output is not reproducible.** Encryption is randomised, so calling this
|
|
128
102
|
* twice with the same roster yields different handles and therefore a different
|
|
129
103
|
* root. Persist what you get back; you cannot regenerate it.
|
|
130
104
|
*
|
|
131
105
|
* @param args The live instance, the roster, and an eager or lazy encryptor.
|
|
132
|
-
* @returns One `{ account,
|
|
106
|
+
* @returns One `{ account, handle, inputProof }` per roster entry, in roster order.
|
|
133
107
|
* @throws {@link InvalidArgumentError} on any roster problem {@link validateCampaignRecipients} rejects, or a zero `instance`.
|
|
134
108
|
* @throws {@link MissingEncryptorError} when `encryptor` resolves to `undefined`.
|
|
135
109
|
*
|
|
@@ -142,8 +116,7 @@ export interface EncryptCampaignAmountsArgs extends CampaignSubmitterOption {
|
|
|
142
116
|
export declare function encryptCampaignAmounts(args: EncryptCampaignAmountsArgs): Promise<readonly EncryptedCampaignLeaf[]>;
|
|
143
117
|
/**
|
|
144
118
|
* Encrypt every recipient's cumulative total, then build the tree those ciphertexts
|
|
145
|
-
* belong to.
|
|
146
|
-
* recipient; set, the whole roster is bound to that one submitter.
|
|
119
|
+
* belong to. Every input is bound to `(instance, instance)`.
|
|
147
120
|
*
|
|
148
121
|
* Use this on the **mutable-root** path: the instance already exists, so its
|
|
149
122
|
* address is known and encryption can bind to it directly. Publish the returned
|
|
@@ -160,9 +133,8 @@ export declare function encryptCampaignAmounts(args: EncryptCampaignAmountsArgs)
|
|
|
160
133
|
* claim, and no amount of on-chain data will reconstruct it. Persist the
|
|
161
134
|
* entries when this resolves and serve each recipient theirs.
|
|
162
135
|
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
* calls yourself if your relayer rate-limits.
|
|
136
|
+
* One relayer request per 32 recipients, issued concurrently; every leaf is submittable
|
|
137
|
+
* by any address. Split the roster across calls yourself if your relayer rate-limits.
|
|
166
138
|
*
|
|
167
139
|
* **Already hold the handles?** This function encrypts unconditionally, and
|
|
168
140
|
* encryption is randomised — so re-encrypting handles that exist elsewhere
|
|
@@ -185,13 +157,13 @@ export declare function encryptCampaignAmounts(args: EncryptCampaignAmountsArgs)
|
|
|
185
157
|
*
|
|
186
158
|
* @alpha
|
|
187
159
|
*/
|
|
188
|
-
export declare function buildMerkleCampaign({ instance, recipients, encryptor,
|
|
160
|
+
export declare function buildMerkleCampaign({ instance, recipients, encryptor, }: BuildMerkleCampaignArgs): Promise<BuiltCampaign>;
|
|
189
161
|
/**
|
|
190
162
|
* Inputs for {@link planMerkleCampaign}.
|
|
191
163
|
*
|
|
192
164
|
* @alpha
|
|
193
165
|
*/
|
|
194
|
-
export interface PlanMerkleCampaignArgs
|
|
166
|
+
export interface PlanMerkleCampaignArgs {
|
|
195
167
|
factory: ConfidentialAirdropFactoryClient;
|
|
196
168
|
/** The exact params the subsequent `createMerkleAirdrop` will use, except `merkleRoot` — supply the planned root there. */
|
|
197
169
|
params: MerkleAirdropParams;
|
|
@@ -202,19 +174,6 @@ export interface PlanMerkleCampaignArgs extends CampaignSubmitterOption {
|
|
|
202
174
|
recipients: readonly CampaignRecipient[];
|
|
203
175
|
encryptor: EncryptorSource;
|
|
204
176
|
}
|
|
205
|
-
/**
|
|
206
|
-
* A campaign built against a not-yet-deployed instance, plus the evidence needed to trust the prediction.
|
|
207
|
-
*
|
|
208
|
-
* @alpha
|
|
209
|
-
*/
|
|
210
|
-
export interface PlannedCampaign extends BuiltCampaign {
|
|
211
|
-
/** Where `createMerkleAirdrop({ mode, userSalt })` from `creator` will land. Every entry is bound to this address. */
|
|
212
|
-
predictedAddress: Address;
|
|
213
|
-
/** The factory's Merkle init-code hash read BEFORE the address was predicted. */
|
|
214
|
-
initCodeHashBefore: Hex;
|
|
215
|
-
/** The same hash read AFTER. Always equal to `initCodeHashBefore` on a returned plan - a difference throws instead. */
|
|
216
|
-
initCodeHashAfter: Hex;
|
|
217
|
-
}
|
|
218
177
|
/**
|
|
219
178
|
* Build a campaign for an instance that does not exist yet, so its root can be
|
|
220
179
|
* baked in at create time.
|
|
@@ -249,6 +208,13 @@ export interface PlannedCampaign extends BuiltCampaign {
|
|
|
249
208
|
* `preflightCreate` (`./guards.js`) for those, or let `createMerkleAirdrop`
|
|
250
209
|
* enforce them at send time.
|
|
251
210
|
*
|
|
211
|
+
* **Create from the plan.** Pass the returned plan as `plan` to
|
|
212
|
+
* `createMerkleAirdrop` / `createAndFundMerkleAirdrop` (and to
|
|
213
|
+
* `preflightCreate`). That pins `predictedAddress`, checks the root, and
|
|
214
|
+
* re-judges drift against `initCodeHashAfter` just before the send, so an
|
|
215
|
+
* implementation rotation after planning is refused rather than deployed at an
|
|
216
|
+
* address the entries are not bound to.
|
|
217
|
+
*
|
|
252
218
|
* **Distribution is yours** — same as {@link buildMerkleCampaign}: the chain
|
|
253
219
|
* keeps only the root, so each recipient must be handed their own
|
|
254
220
|
* `(handle, inputProof, merkleProof)` out of band or they cannot claim.
|
|
@@ -267,17 +233,18 @@ export interface PlannedCampaign extends BuiltCampaign {
|
|
|
267
233
|
* params: { ...params, merkleRoot: plan.root, isMerkleRootMutable: false },
|
|
268
234
|
* mode: "clone",
|
|
269
235
|
* userSalt,
|
|
236
|
+
* plan,
|
|
270
237
|
* });
|
|
271
238
|
*
|
|
272
239
|
* @alpha
|
|
273
240
|
*/
|
|
274
|
-
export declare function planMerkleCampaign({ factory, params, mode, creator, userSalt, recipients, encryptor,
|
|
241
|
+
export declare function planMerkleCampaign({ factory, params, mode, creator, userSalt, recipients, encryptor, }: PlanMerkleCampaignArgs): Promise<PlannedCampaign>;
|
|
275
242
|
/**
|
|
276
243
|
* Inputs for {@link rotateMerkleRoot}.
|
|
277
244
|
*
|
|
278
245
|
* @alpha
|
|
279
246
|
*/
|
|
280
|
-
export interface RotateMerkleRootArgs extends WriteAccountOverride
|
|
247
|
+
export interface RotateMerkleRootArgs extends WriteAccountOverride {
|
|
281
248
|
/** The live instance. Its `address` is read off the client — nothing is predicted here. */
|
|
282
249
|
airdrop: MerkleAirdropClient;
|
|
283
250
|
/** The FULL updated roster: cumulative totals, not the deltas since the last root. */
|
|
@@ -311,11 +278,8 @@ export interface RotatedCampaign extends BuiltCampaign {
|
|
|
311
278
|
* entries to every recipient**, including the ones whose total was unchanged —
|
|
312
279
|
* the chain stores only the root, so an un-updated recipient is simply stuck.
|
|
313
280
|
*
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
* a self-claim one - every new entry becomes claimable only by its own recipient, and the
|
|
317
|
-
* relayer that was settling for them can no longer submit anything. Pass the same
|
|
318
|
-
* `submitter` again to keep a relayed campaign relayed.
|
|
281
|
+
* One relayer request per 32 recipients, issued concurrently; every leaf is submittable
|
|
282
|
+
* by any address.
|
|
319
283
|
*
|
|
320
284
|
* Requires `MERKLE_ADMIN_ROLE` on the instance and an instance created with
|
|
321
285
|
* `isMerkleRootMutable: true`.
|
|
@@ -335,4 +299,4 @@ export interface RotatedCampaign extends BuiltCampaign {
|
|
|
335
299
|
*
|
|
336
300
|
* @alpha
|
|
337
301
|
*/
|
|
338
|
-
export declare function rotateMerkleRoot({ airdrop, recipients, encryptor,
|
|
302
|
+
export declare function rotateMerkleRoot({ airdrop, recipients, encryptor, account, }: RotateMerkleRootArgs): Promise<RotatedCampaign>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Address } from "viem";
|
|
2
|
+
/**
|
|
3
|
+
* Predict the compliance-manager clone the factory deploys for an instance.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors `AirdropFactory`: `Clones.cloneDeterministic(managerImpl,
|
|
6
|
+
* keccak256(abi.encode(predictedInstance, "compliance")))`, sent from the
|
|
7
|
+
* factory. The salt derives from the instance address, so the clone moves in
|
|
8
|
+
* lockstep with it.
|
|
9
|
+
*
|
|
10
|
+
* @param args.factory The factory that performs the create (the CREATE2 deployer).
|
|
11
|
+
* @param args.managerImplementation The implementation the clone is made from.
|
|
12
|
+
* @param args.airdrop The instance address the create lands at.
|
|
13
|
+
* @returns The checksummed clone address.
|
|
14
|
+
*
|
|
15
|
+
* @alpha
|
|
16
|
+
*/
|
|
17
|
+
export declare function predictComplianceManagerClone(args: {
|
|
18
|
+
factory: Address;
|
|
19
|
+
managerImplementation: Address;
|
|
20
|
+
airdrop: Address;
|
|
21
|
+
}): Address;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @alpha
|
|
5
5
|
*/
|
|
6
|
-
export declare const AIRDROP_CONTRACTS_COMMIT = "
|
|
6
|
+
export declare const AIRDROP_CONTRACTS_COMMIT = "005980df194e0dc66053bd517e9759bd4d580047";
|
|
7
7
|
/**
|
|
8
8
|
* Deployment shell selected at create time. Mirrors the contract's `DeploymentMode` enum
|
|
9
9
|
* (`IConfidentialAirdropTypes.sol`): `enum DeploymentMode { Clone, UUPS }`.
|
|
@@ -31,3 +31,13 @@ export declare const DEDUP_MODE: {
|
|
|
31
31
|
};
|
|
32
32
|
/** @alpha */
|
|
33
33
|
export type DedupMode = keyof typeof DEDUP_MODE;
|
|
34
|
+
/** {@link DEDUP_MODE} inverted: the contract's ordinal to the SDK's name. */
|
|
35
|
+
export declare const DEDUP_MODE_BY_ORDINAL: ReadonlyMap<number, DedupMode>;
|
|
36
|
+
/**
|
|
37
|
+
* The largest value `CommonAirdropParams.maxAcceptedGasFee` can carry - the
|
|
38
|
+
* `uint96` ceiling. Passing it accepts whatever fee the factory resolves, which
|
|
39
|
+
* is the opt-out, not the default.
|
|
40
|
+
*
|
|
41
|
+
* @alpha
|
|
42
|
+
*/
|
|
43
|
+
export declare const UINT96_MAX: bigint;
|