import { type Address, type Hex } from "viem"; import type { LucidlyClient } from "./client.js"; import { type MerkleTree } from "./merkle.js"; /** A single call whitelisted in the vault's Merkle root. */ export interface AllowedCall { key: string; protocol: string; action: "approve" | "supply" | "withdraw" | "swap"; asset: Address; /** For swaps: the output token. */ tokenOut?: Address; target: Address; selector: Hex; abi: readonly unknown[]; decoderFn: string; leafArgs: readonly unknown[]; buildExecArgs: (amount: bigint, minOut?: bigint) => readonly unknown[]; leaf: Hex; packedArgs: Hex; index: number; } export interface IntegrationState { decoder: Address; /** Full syUSD decoder the baseline is regenerated against (vault.deploy repointed). */ syUsdDecoder?: Address; strategist: Address; manager: Address; vault: Address; accountant: Address; protocols: string[]; assets: Address[]; pairs: [Address, Address][]; fee: number; keepSyUsdBaseline: boolean; tree: MerkleTree; calls: AllowedCall[]; } /** Minimal, JSON-serializable descriptor sufficient to rebuild the full in-memory state. */ export interface IntegrationDescriptor { vault: Address; decoder: Address; syUsdDecoder?: Address; strategist: Address; manager: Address; accountant: Address; protocols: string[]; assets: Address[]; pairs: [Address, Address][]; fee: number; keepSyUsdBaseline: boolean; } export interface EnableOptions { strategist?: Address; decoder?: Address; /** Assets to whitelist for asset-keyed protocols (AaveV3). Defaults to ["USDC"]. */ assets?: (Address | string)[]; /** Token pairs [from, to] to whitelist for swap protocols (UniswapV3). Defaults to [[USDC, WETH]]. */ pairs?: [Address | string, Address | string][]; /** Uniswap V3 fee tier used when building swap leaves (the decoder ignores fee, so any tier works). */ fee?: number; /** Keep the syUSD baseline leaves in the root and append the new protocol leaves. Defaults to true. */ keepSyUsdBaseline?: boolean; } export interface EnableResult { decoder: Address; root: Hex; calls: AllowedCall[]; descriptor: IntegrationDescriptor; } export declare class IntegrationsModule { private readonly c; private state; constructor(c: LucidlyClient); getState(vault: Address): IntegrationState | undefined; deployDecoder(vault?: Address): Promise
; /** Build the call specs (no leaves yet) for the requested protocols/assets. */ private buildSpecs; /** Derive packed args + leaf for each spec by eth_call-ing the decoder. */ private deriveCalls; /** * Build the manage tree from `baselineDigests` (the kept syUSD whitelist, repointed to this * vault's decoder) followed by the new protocol leaves. Reindexes each call to its position in * the combined tree so proofFor(tree, call.index) is correct. */ private combine; /** * syUSD baseline digests to keep. If a full syUSD decoder is known (repointed deploy), regenerate * the baseline against it (executable). Otherwise fall back to the published (verbatim) digests. */ private baselineDigestsFor; /** * Enable protocols on a vault: deploy/register the decoder, build the allowed leaves, * and set the Merkle root for the strategist. */ enable(protocols: string[], opts?: EnableOptions, vault?: Address): Promise