import { RouterDataV3 } from '@cetusprotocol/aggregator-sdk';
import { Transaction, TransactionObjectArgument } from '@mysten/sui/transactions';
import { SuiJsonRpcClient } from '@mysten/sui/jsonRpc';

/**
 * Cetus Aggregator V3 SDK wrapper — the ONLY file that imports @cetusprotocol/aggregator-sdk.
 * Documented CLAUDE.md exception: multi-DEX routing cannot be feasibly replaced by thin tx builders.
 *
 * [B5 v2 / @t2000/sdk@1.1.0 / 2026-04-30]
 * Overlay fee config is now per-call instead of a module-level singleton. CLI / direct
 * SDK callers (`T2000.swap()`) DON'T pass `overlayFee` → fee-free swap. Audric's
 * prepare/route.ts ALWAYS passes `overlayFee = { rate: OVERLAY_FEE_RATE, receiver:
 * T2000_OVERLAY_FEE_WALLET }` → fee charged. Structural inclusion (Audric's code can't
 * forget to pass it because it IS the code), not a toggle that defaults to safe.
 *
 * Pre-1.1.0: a module-level `OVERLAY_FEE_RECEIVER` constant defaulted to a Move object
 * ID. USDC sent there became OwnedObjects keyed to the object and was inaccessible.
 * Fixed by making the receiver a regular wallet address (T2000_OVERLAY_FEE_WALLET) AND
 * by removing the singleton pattern that hid the misconfig.
 */

interface OverlayFeeConfig {
    /** Fee rate as a fraction (e.g. 0.001 = 0.1%). Pass 0 to disable. */
    rate: number;
    /** Wallet address that receives the overlay fee. */
    receiver: string;
}
interface SwapRouteResult {
    routerData: RouterDataV3;
    amountIn: string;
    amountOut: string;
    byAmountIn: boolean;
    priceImpact: number;
    insufficientLiquidity: boolean;
}
interface SerializedCetusRoutePath {
    id: string;
    direction: boolean;
    provider: string;
    from: string;
    target: string;
    feeRate: number;
    amountIn: string;
    amountOut: string;
    version?: string;
    publishedAt?: string;
    extendedDetails?: Record<string, unknown>;
}
interface SerializedRouterDataV3 {
    quoteID?: string;
    /** RouterDataV3.amountIn (BN) → decimal string */
    amountIn: string;
    /** RouterDataV3.amountOut (BN) → decimal string */
    amountOut: string;
    byAmountIn: boolean;
    paths: SerializedCetusRoutePath[];
    insufficientLiquidity: boolean;
    deviationRatio: number;
    /** RouterDataV3.packages (Map) → Record */
    packages?: Record<string, string>;
    totalDeepFee?: number;
    error?: {
        code: number;
        msg: string;
    };
    overlayFee?: number;
}
interface SerializedCetusRoute {
    routerData: SerializedRouterDataV3;
    amountIn: string;
    amountOut: string;
    byAmountIn: boolean;
    priceImpact: number;
    insufficientLiquidity: boolean;
    /**
     * Wall-clock timestamp (ms since epoch) at which the route was discovered.
     * Used by audric's prepare-route for SPEC 20.2 D-3 TTL re-validation: if
     * the route is older than the threshold AND price impact has shifted
     * beyond tolerance, fall back to a fresh `findSwapRoute()` call.
     */
    discoveredAt: number;
    /**
     * Snapshot of the input/output coin types the route was discovered for.
     * SPEC 20.2 D-2 (b) structural verification: prepare-route asserts
     * input/output coins match before using the fast-path; mismatch falls
     * back to fresh discovery (defense against client-side tampering and
     * against legitimate token-type drift in the request).
     */
    fromCoinType: string;
    toCoinType: string;
}
declare function serializeCetusRoute(route: SwapRouteResult, context: {
    fromCoinType: string;
    toCoinType: string;
}): SerializedCetusRoute;
declare function deserializeCetusRoute(serialized: SerializedCetusRoute): SwapRouteResult;
/**
 * SPEC 20.2 D-2 (b) structural verification helper. Returns true when the
 * serialized route matches the requested coin types (i.e. it's safe to use
 * as the prepare-route fast-path), false otherwise (tampered, or input
 * mismatch from a legitimate but stale pending action). Caller falls back
 * to a fresh `findSwapRoute()` call when verification fails.
 */
declare function verifyCetusRouteCoinMatch(serialized: SerializedCetusRoute, expected: {
    fromCoinType: string;
    toCoinType: string;
}): boolean;
/**
 * SPEC 20.2 D-3 (b) TTL helper. Returns true when the serialized route is
 * fresh enough to use as the fast-path (< `maxAgeMs` old). Returns false
 * for stale routes — caller falls back to fresh `findSwapRoute()` to pick
 * up any pool-price drift since route discovery.
 *
 * Default 30s aligns with the existing quote-freshness contract surfaced
 * to users via `pending_action.quoteAge` (the PermissionCard "QUOTE Ns OLD"
 * badge starts warning the user past 30s).
 */
declare function isCetusRouteFresh(serialized: SerializedCetusRoute, maxAgeMs?: number): boolean;
/**
 * Default Audric swap overlay fee — 0.1%. Exported for consumers that want to use
 * the canonical Audric rate (the Audric prepare-route does this). Changing this
 * rate requires a coordinated SDK + audric release.
 */
declare const OVERLAY_FEE_RATE = 0.001;
/**
 * Find the optimal swap route via Cetus Aggregator REST API.
 *
 * Pass `overlayFee` to charge an overlay fee on the output (Audric's pattern).
 * Omit it for a fee-free swap (CLI / direct SDK pattern).
 */
declare function findSwapRoute(params: {
    walletAddress: string;
    from: string;
    to: string;
    amount: bigint;
    byAmountIn: boolean;
    overlayFee?: OverlayFeeConfig;
    /**
     * Optional Cetus provider allow-list. When omitted, all 30+ DEXes
     * are eligible. Sponsored flows (Enoki) MUST pass an exclusion list
     * computed via `getProvidersExcluding([...])` from the Cetus SDK to
     * remove Pyth-dependent providers (HAEDALPMM, METASTABLE, OBRIC,
     * STEAMM_OMM, STEAMM_OMM_V2, SEVENK, HAEDALHMMV2) — those reference
     * `tx.gas` for oracle fees, which Enoki rejects in sponsored txs.
     * Non-sponsored callers (CLI, direct SDK) leave this undefined.
     */
    providers?: string[];
}): Promise<SwapRouteResult | null>;
/**
 * Build a swap PTB from a route result. The caller must provide an input coin
 * obtained by splitting/merging wallet coins.
 *
 * **Important:** Cetus's `routerSwap` reads the overlay-fee config from the
 * AggregatorClient instance. The `overlayFee` param here MUST match the one
 * passed to `findSwapRoute` for the same swap (otherwise you'll hit the cache
 * boundary and get a different client with different overlay config).
 */
declare function buildSwapTx(params: {
    walletAddress: string;
    route: SwapRouteResult;
    tx: Transaction;
    inputCoin: TransactionObjectArgument;
    slippage: number;
    overlayFee?: OverlayFeeConfig;
}): Promise<TransactionObjectArgument>;
/**
 * Append a swap fragment to an existing PTB. SPEC 7 § "Layer 1" Cetus
 * appender. Two modes, dispatched by the presence of `input.inputCoin`:
 *
 * - **Wallet mode** (`inputCoin` omitted) — sources `from`-asset funds
 *   via `coinWithBalance({ type, balance })` (resolves coin objects +
 *   address balance at build time), runs the swap. Mirrors the audric
 *   host's `transactions/prepare/route.ts` swap branch (P2.2c will
 *   retire that branch in favor of this appender via `composeTx`).
 *
 * - **Chain mode** (`inputCoin` provided) — consumes the passed-in coin
 *   reference (typically produced by an upstream appender like
 *   `addWithdrawToTx`) directly, no wallet fetch / no merge / no
 *   split. This is the SPEC 7 multi-write enabler ("withdraw → swap →
 *   save" without intermediate wallet materialization).
 *
 * **SUI in wallet mode:** ALWAYS sources through `selectSuiCoin` (which
 * routes via `coinWithBalance({ type: SUI, useGasCoin: false })` under
 * sponsored flows, OR `tx.splitCoins(tx.gas, ...)` under self-funded
 * flows). The caller MUST set `sponsoredContext` correctly — otherwise
 * sponsored swaps with SUI source fail with `Cannot use GasCoin as a
 * transaction argument` (Enoki owns `tx.gas`, the PTB body referencing
 * it as an argument is invalid for sponsorship). 2.14.0 shipped without
 * this branch and broke audric/web-v2 SUI→USDC swaps; restored in 2.14.1
 * (S.260). For non-sponsored flows (CLI), `T2000.swap()` pre-builds the
 * inputCoin via `tx.splitCoins(tx.gas, [rawAmount])[0]` and uses chain
 * mode, sidestepping wallet-mode entirely — this branch is a defensive
 * safety net for future direct SDK users who pass SUI in wallet mode.
 *
 * **`swapAll` semantics (wallet mode):** if the requested raw amount
 * is >= the wallet's total `from` balance, the appender consumes the
 * entire merged primary coin (not a split), matching audric's host
 * route's `swapAll` clipping. The returned `effectiveAmountIn` reflects
 * the actual consumed amount in display units.
 *
 * **Slippage:** clamped to [0.001, 0.05] (0.1% – 5%). Defaults to 0.01.
 *
 * @returns
 * - `coin` — output coin reference, ready for downstream consumption
 *   (e.g. `addSaveToTx`) or wallet transfer (`tx.transferObjects`).
 * - `effectiveAmountIn` — display-units input amount the swap actually
 *   consumes (handles `swapAll` clipping in wallet mode; in chain mode
 *   echoes the requested `input.amount`).
 * - `expectedAmountOut` — display-units output amount per the route
 *   quote. Actual on-chain output may differ within slippage.
 * - `route` — raw `SwapRouteResult` for downstream telemetry / logging.
 */
declare function addSwapToTx(tx: Transaction, client: SuiJsonRpcClient, address: string, input: {
    from: string;
    to: string;
    amount: number;
    slippage?: number;
    byAmountIn?: boolean;
    overlayFee?: OverlayFeeConfig;
    inputCoin?: TransactionObjectArgument;
    /**
     * Optional Cetus provider allow-list. Forwarded to `findSwapRoute`.
     * Sponsored flows (Enoki) MUST pass `getProvidersExcluding([...])`
     * to remove Pyth-dependent providers — see `findSwapRoute`'s JSDoc
     * for the exclusion list. Non-sponsored callers omit this.
     */
    providers?: string[];
    /**
     * [SPEC 20.2 D-3 (b)] Precomputed route from a prior `findSwapRoute()`
     * call (typically captured by `swap_quote` and threaded through
     * `pending_action.cetusRoute`). When present AND not stale (per
     * `isCetusRouteFresh`) AND the input/output coins match, this skips
     * the ~400-500ms `findSwapRoute()` discovery call. Stale routes are
     * silently ignored (caller falls back to fresh discovery).
     *
     * Caller responsibility: pass the SAME `overlayFee` / `providers` /
     * `byAmountIn` that produced the precomputed route. Mismatch will
     * still produce a working swap but may use the wrong overlay-fee
     * config (the route data already encodes the chosen DEX path).
     */
    precomputedRoute?: SwapRouteResult;
    /**
     * Whether this swap is being built inside a sponsored-tx flow (Enoki)
     * vs self-funded (CLI / direct sign). Load-bearing for SUI-source
     * swaps in wallet mode: under sponsored flows, `tx.gas` belongs to
     * the sponsor and CANNOT be referenced as a transaction argument
     * (Sui protocol rejects with `Cannot use GasCoin as a transaction
     * argument`). When `true`, SUI source routes through `selectSuiCoin`
     * with `useGasCoin: false` so the resolver sources from the user's
     * SUI coin objects + address balance instead. Defaults to `false`
     * (back-compat — pre-2.14.1 behavior). Audric/web-v2's compose path
     * threads this through via `composeTx({ sponsoredContext: true })`.
     */
    sponsoredContext?: boolean;
}): Promise<{
    coin: TransactionObjectArgument;
    effectiveAmountIn: number;
    expectedAmountOut: number;
    route: SwapRouteResult;
    /** True when `precomputedRoute` was used (no `findSwapRoute()` call). */
    usedPrecomputedRoute: boolean;
}>;

interface T2000Options {
    keyPath?: string;
    /** PIN to decrypt the key file. Accepts any string (4+ chars). */
    pin?: string;
    /** @deprecated Use `pin` instead. */
    passphrase?: string;
    network?: 'mainnet' | 'testnet';
    rpcUrl?: string;
}
interface GasReserve {
    sui: number;
    usdEquiv: number;
}
interface BalanceResponse {
    available: number;
    savings: number;
    debt: number;
    pendingRewards: number;
    gasReserve: GasReserve;
    total: number;
    stables: Record<string, number>;
}
interface SendResult {
    success: boolean;
    tx: string;
    amount: number;
    to: string;
    /** Set when the recipient was resolved via the legacy `contacts.json` alias. */
    contactName?: string;
    /**
     * [S.279] Set when the recipient was resolved via SuiNS (e.g. `alex.sui`).
     * CLI receipts render "Sent to alex.sui (0xabc...)" when present.
     */
    suinsName?: string;
    gasCost: number;
    gasCostUnit: string;
    balance: BalanceResponse;
}
interface SaveResult {
    success: boolean;
    tx: string;
    amount: number;
    apy: number;
    fee: number;
    gasCost: number;
    savingsBalance: number;
}
interface WithdrawResult {
    success: boolean;
    tx: string;
    amount: number;
    asset?: string;
    gasCost: number;
}
interface BorrowResult {
    success: boolean;
    tx: string;
    amount: number;
    /** [v0.51.0] Asset borrowed — 'USDC' or 'USDsui'. Optional for backward compat. */
    asset?: string;
    fee: number;
    healthFactor: number;
    gasCost: number;
}
interface RepayResult {
    success: boolean;
    tx: string;
    amount: number;
    /** [v0.51.1] Asset repaid — 'USDC' or 'USDsui'. Optional for backward compat. */
    asset?: string;
    remainingDebt: number;
    gasCost: number;
}
interface HealthFactorResult {
    healthFactor: number;
    supplied: number;
    borrowed: number;
    maxBorrow: number;
    liquidationThreshold: number;
}
interface MaxWithdrawResult {
    maxAmount: number;
    healthFactorAfter: number;
    currentHF: number;
}
interface MaxBorrowResult {
    maxAmount: number;
    healthFactorAfter: number;
    currentHF: number;
}
interface AssetRates {
    saveApy: number;
    borrowApy: number;
}
interface RatesResult {
    [asset: string]: AssetRates;
}
interface PositionEntry {
    protocol: string;
    asset: string;
    type: 'save' | 'borrow';
    amount: number;
    amountUsd?: number;
    apy: number;
}
interface PositionsResult {
    positions: PositionEntry[];
}
interface EarningsResult {
    totalYieldEarned: number;
    currentApy: number;
    dailyEarning: number;
    supplied: number;
}
interface FundStatusResult {
    supplied: number;
    apy: number;
    earnedToday: number;
    earnedAllTime: number;
    projectedMonthly: number;
}
interface DepositInfo {
    address: string;
    network: string;
    supportedAssets: string[];
    instructions: string;
}
interface PaymentRequest {
    address: string;
    network: string;
    amount: number | null;
    currency: string;
    memo: string | null;
    label: string | null;
    /** Unique payment identifier (UUID) for Payment Kit registry */
    nonce: string;
    /** Payment Kit URI (sui:pay?...) for QR codes and wallet deep links */
    qrUri: string;
    /** Human-readable summary */
    displayText: string;
}
/**
 * One non-zero user balance change for a transaction. Sui collapses
 * balance changes by coin type, so a 3-step bundle that touches USDC
 * three times surfaces as ONE leg of net USDC delta — not three.
 *
 * [Activity rebuild / 2026-05-10] Added so consumers can render swap
 * + bundle txs accurately instead of picking a single "primary leg"
 * (which made `Swapped 987.60 MANIFEST` look like +$987 of value when
 * the user actually paid 1 USDC for it).
 */
interface TransactionLeg {
    /** Full Sui coin type string (e.g. `0x...usdc::USDC`). */
    coinType: string;
    /** Display symbol (USDC, SUI, GOLD, MANIFEST, …) from the token registry. */
    asset: string;
    /** On-chain decimals for this coin (used to format `amount`). */
    decimals: number;
    /** Token quantity as a positive number (e.g. 987.60). */
    amount: number;
    /** Signed raw bigint as a string (preserves sign + precision). */
    rawAmount: string;
    /** `'out'` if the user spent this coin, `'in'` if they received it. */
    direction: 'in' | 'out';
}
interface TransactionRecord {
    digest: string;
    /** Coarse bucket — `'send' | 'lending' | 'swap' | 'transaction'`. STABLE. */
    action: string;
    /**
     * Finer-grained display label derived from the Move-call function
     * name (e.g. `'deposit'`, `'withdraw'`, `'payment_link'`,
     * `'on-chain'`). Optional — frontends should fall back to `action`
     * when missing. Never used by ACI filters.
     */
    label?: string;
    /**
     * All non-zero user balance legs for this transaction. Single-write
     * txs have `legs.length === 1`; swaps have `2` (one `out`, one
     * `in`); bundles have `> 2`. Order is RPC order — not sorted by
     * size or USD value (audric's activity route prices + sorts).
     *
     * @since SDK v1.27.2 — was missing from earlier shapes; older
     * consumers can keep using `amount` / `asset` / `direction` (which
     * still resolve to the largest absolute leg).
     */
    legs: TransactionLeg[];
    /**
     * Largest-absolute-leg amount, kept for back-compat with consumers
     * that pre-date `legs[]`. New code should iterate `legs` instead.
     */
    amount?: number;
    /** @see {@link amount} — back-compat alias for `legs[primary].asset`. */
    asset?: string;
    recipient?: string;
    /**
     * Direction of the user's principal (non-gas) balance movement on
     * this tx — `'out'` if they spent, `'in'` if they received.
     * Computed from on-chain balance changes (NOT from `label`), so the
     * card can render the correct sign even for opaque actions like
     * `swap`/`router`. Undefined when no user balance change is
     * detectable (e.g. pure read-only or admin txs).
     *
     * @see {@link amount} — back-compat alias for `legs[primary].direction`.
     */
    direction?: 'in' | 'out';
    timestamp: number;
    gasCost?: number;
}
interface PendingReward {
    protocol: string;
    asset: string;
    coinType: string;
    symbol: string;
    amount: number;
    estimatedValueUsd: number;
}
interface ClaimRewardsResult {
    success: boolean;
    tx: string;
    rewards: PendingReward[];
    totalValueUsd: number;
    gasCost: number;
}
interface CompoundRewardsResult {
    success: boolean;
    claimTx: string;
    swapTxs: string[];
    depositTx: string;
    rewards: PendingReward[];
    totalCompoundedUsdc: number;
    totalGasCost: number;
}
interface StakeVSuiResult {
    success: boolean;
    tx: string;
    amountSui: number;
    vSuiReceived: number;
    apy: number;
    gasCost: number;
}
interface UnstakeVSuiResult {
    success: boolean;
    tx: string;
    vSuiAmount: number;
    suiReceived: number;
    gasCost: number;
}
interface SwapResult {
    success: boolean;
    tx: string;
    fromToken: string;
    toToken: string;
    fromAmount: number;
    toAmount: number;
    priceImpact: number;
    route: string;
    gasCost: number;
}
interface SwapQuoteResult {
    fromToken: string;
    toToken: string;
    fromAmount: number;
    toAmount: number;
    priceImpact: number;
    route: string;
    /**
     * [SPEC 20.2 / D-1 (a)] Structured Cetus route captured at quote time.
     * Threaded through `pending_action.cetusRoute` so the prepare-route can
     * skip the ~400-500ms `findSwapRoute()` re-discovery, and so the
     * post-write resume system prompt can ground LLM narration against the
     * canonical route (closing S19-F2). Optional for backward compat with
     * pre-SPEC-20.2 callers (CLI, server-only direct calls).
     */
    serializedRoute?: SerializedCetusRoute;
}
interface PayOptions {
    url: string;
    method?: string;
    body?: string;
    headers?: Record<string, string>;
    maxPrice?: number;
}
interface PayResult {
    status: number;
    body: unknown;
    paid: boolean;
    cost?: number;
    /**
     * SUI gas cost actually paid on chain. Zero for gasless payments —
     * which means an MPP payment hit the protocol's gasless allowlist
     * (USDC / USDsui / USDY / FdUSD / AUSD / BUCK / USDB / SUI_USDE) and
     * was accepted with `gasPrice=0, gasBudget=0, gasPayment=[]`. See
     * https://docs.sui.io/develop/transaction-payment/gasless-stablecoin-transfers
     */
    gasCostSui?: number;
    receipt?: {
        reference: string;
        timestamp: string;
    };
}
type HFAlertLevel = 'none' | 'warn' | 'critical';
interface FinancialSummary {
    walletAddress: string;
    usdcAvailable: number;
    savingsBalance: number;
    debtBalance: number;
    idleUsdc: number;
    healthFactor: number;
    hfAlertLevel: HFAlertLevel;
    saveApy: number;
    borrowApy: number;
    dailyYield: number;
    gasReserveSui: number;
    gasReserveUsd: number;
    fetchedAt: number;
}

export { type AssetRates as A, type BalanceResponse as B, type ClaimRewardsResult as C, type DepositInfo as D, type EarningsResult as E, type FundStatusResult as F, type GasReserve as G, type HealthFactorResult as H, isCetusRouteFresh as I, serializeCetusRoute as J, verifyCetusRouteCoinMatch as K, type MaxBorrowResult as M, OVERLAY_FEE_RATE as O, type PayOptions as P, type RatesResult as R, type SaveResult as S, type TransactionLeg as T, type UnstakeVSuiResult as U, type WithdrawResult as W, type BorrowResult as a, type MaxWithdrawResult as b, type OverlayFeeConfig as c, type PayResult as d, type PendingReward as e, type PositionEntry as f, type PositionsResult as g, type RepayResult as h, type SendResult as i, type SwapRouteResult as j, type TransactionRecord as k, buildSwapTx as l, findSwapRoute as m, type T2000Options as n, type StakeVSuiResult as o, type SwapResult as p, type SwapQuoteResult as q, type PaymentRequest as r, type CompoundRewardsResult as s, type FinancialSummary as t, type HFAlertLevel as u, type SerializedCetusRoute as v, type SerializedCetusRoutePath as w, type SerializedRouterDataV3 as x, addSwapToTx as y, deserializeCetusRoute as z };
