import type { Address } from "viem"; export type ChainName = "ethereum" | "base" | "arbitrum" | "baseSepolia"; /** Exchange-rate guardrails for the Accountant, expressed as +/- bps offsets. */ export interface ExchangeRateBounds { /** Max allowed upward rate change per update, in bps (e.g. 50 = +0.5% => 10050 on the 1e4 scale). */ upperBps: number; /** Max allowed downward rate change per update, in bps (e.g. 50 = -0.5% => 9950 on the 1e4 scale). */ lowerBps: number; /** Minimum seconds between rate updates. */ minUpdateDelay: number; } /** * Parameters for {@link VaultModule.deploy}. Mirrors the documented SDK contract * (resources/sdk/deploy.md) and the proven Foundry engine (DeployLucidlyVault.s.sol). * Token-like fields accept a symbol resolved via the active chain's address book, or a raw 0x address. */ export interface DeployParams { name: string; symbol: string; /** Share-token decimals. Defaults to the base asset's decimals for clean 1:1 share math. */ decimals?: number; /** Unit of account for the exchange rate (e.g. USDC). */ baseAsset: Address | string; /** Assets enabled for deposit/withdraw on the Teller. Defaults to [baseAsset]. */ allowedDepositAssets?: (Address | string)[]; /** Initial NAV in base-asset units (e.g. 1_000_000n for 1.0 in 6dp USDC). Defaults to 10**decimals. */ initialRate?: bigint; /** Rate guardrails. Defaults to +/-0.5% and a 3600s min delay. */ exchangeRateBounds?: ExchangeRateBounds; /** Platform/management fee in bps on the 1e4 scale (100 = 1%). Defaults to 0. */ managementFeeBps?: number; /** Performance fee in bps on the 1e4 scale. Defaults to 0. */ performanceFeeBps?: number; /** Anti-MEV deposit lock in seconds. Defaults to 0. */ shareLockSeconds?: number; /** Fee payout address. Defaults to the owner (or deployer if owner unset). */ payout?: Address | string; /** OWNER-role recipient (multisig/timelock). If finalizeOwnership, control is handed here. */ owner?: Address | string; /** Address granted STRATEGIST role. */ strategist?: Address | string; /** Address granted UPDATE_EXCHANGE_RATE role. */ rateUpdater?: Address | string; /** Address granted SOLVER role (bulkDeposit/bulkWithdraw). */ solver?: Address | string; /** Make teller.deposit/depositWithPermit public. Defaults to true. */ allowPublicDeposits?: boolean; /** * Irreversibly hand ownership to `owner` (transfers each contract's ownership to 0, * roles to OWNER). Only set true with a real multisig/timelock owner. Defaults to false. */ finalizeOwnership?: boolean; /** Run the full sequence without broadcasting (eth_call/estimate only where possible). */ simulate?: boolean; /** * Seed the vault's initial manage root with the syUSD baseline strategy set at deploy time. * Defaults to true (= "verbatim"). Kept for back-compat; prefer `syUsdSeedMode`. */ seedSyUsdLeaves?: boolean; /** * How to seed the syUSD baseline at deploy: * - "repointed" : deploy this vault's own decoder and regenerate every syUSD leaf against it * (recipient/onBehalfOf -> this vault, fee approvals -> this accountant). Executable * by an independent vault. **Default.** * - "verbatim" : seed the published syUSD root as-is (syUSD's decoder + recipients). * - "none" : do not seed. */ syUsdSeedMode?: "verbatim" | "repointed" | "none"; /** Bypass blocking preflight errors (e.g. EOA owner on finalize). Not recommended for mainnet. */ allowUnsafe?: boolean; } export interface Deployed { rolesAuthority: Address; vault: Address; manager: Address; accountant: Address; teller: Address; /** Convenience composite decoder (ERC20+Aave+Uniswap), deployed lazily by integrations.enable. */ decoder?: Address; /** Full syUSD decoder (all 47 syUSD signatures), deployed in repointed mode for the baseline. */ syUsdDecoder?: Address; /** AtomicQueue for asynchronous (queued) redemptions, deployed by queue.deployQueue(). */ queue?: Address; /** LucidlyRedeemSolver that fulfills queued redemptions, deployed alongside the queue. */ redeemSolver?: Address; } /** Canonical Boring Vault role IDs (must match the on-chain deployment). */ export const Roles = { MANAGER: 1, MINTER: 2, BURNER: 3, MANAGER_INTERNAL: 4, STRATEGIST: 7, OWNER: 8, UPDATE_EXCHANGE_RATE: 11, SOLVER: 12, } as const; export type RoleName = keyof typeof Roles; /** Result of a state-changing call: the tx hash plus a helper to await the receipt. */ export interface TxResult { hash: Address; wait: () => Promise; }