import type { Connection } from '@solana/web3.js'; import type { IAddress, IEnv, ISolanaNetwork, IStellarNetwork, IWSMonitorHeaders } from '../../types'; /** * Structural interface for the Solana adapter surface used by vault operations. * Avoids importing the concrete SolanaAdapter class to prevent circular dependencies. */ export interface ISolanaService { connection: Connection; getVaultState: (vaultProgramId: any, idl: any, vaultAddress?: any) => Promise; fetchUserShareBalance: (publicKey: any, shareMint: any) => Promise; /** * Raw (BigInt-safe) variant. Required — `fetchUserShareBalance` alone * returns a JS-number `uiAmount` which is lossy and silently encodes * against 18 decimals when fed back through `toNormalizedBn` without an * explicit decimals argument. Every consumer that needs a correct * `walletBalance.raw` (positions, redemptions, max actions) MUST use this * entry point. * * Returns `{ amount, decimals }`: * - `amount` is the on-chain u64 as a base-units string (always set; * `'0'` when no balance / no account / no args / RPC failure). * - `decimals` matches the mint when a parsed `tokenAmount` is * available; otherwise **`null`**. `decimals === null` is the * "scale unknown" signal — callers must substitute a known decimals * value (typically the deposit mint's decimals from backend metadata) * before constructing an `INormalizedNumber`. Never throws. */ fetchUserShareBalanceRaw: (publicKey: any, shareMint: any) => Promise<{ amount: string; decimals: number | null; }>; /** * Canonical program id for this service's network, as * `SolanaAdapter.getProgramId`. Optional so a hand-built service keeps * working: without it the withdrawal-queue reads are skipped, and vaults and * positions come back without queue data. */ getProgramId?: (type: 'vault' | 'withdrawalQueue') => string; /** * This service's network, as `SolanaAdapter.network`. When present, the * withdrawal-queue reads look the queue program up in `programIds` directly * instead of calling `getProgramId`. */ network?: ISolanaNetwork; } /** * Base configuration for vault operations. */ export interface IVaultBaseOptions { rpcUrl: string; env?: IEnv; augustKey?: string; subgraphKey?: string; chainId?: number; solanaService?: ISolanaService; /** * Optional Soroban RPC override (e.g. a keyed Alchemy URL) for Stellar vault * reads, threaded from the SDK's `stellar` config. Carries the network it was * configured for so it is only applied to matching-network vaults — a testnet * override must not be used for a mainnet read. Unset → built-in endpoints. */ stellarRpc?: { rpcUrl: string; network: IStellarNetwork; }; headers?: IWSMonitorHeaders; /** * Portfolio mode: when true, the per-vault EVM getter does NOT null out a * closed + invisible vault. Needed so a user's position in a closed, * invisible vault can still resolve its metadata. Defaults to undefined * (false) so marketplace/discovery reads keep hiding closed staging vaults. */ includeClosed?: boolean; } /** * Optional enrichment options for vault queries. */ export interface IVaultCustomOptions { loans?: boolean; allocations?: boolean; wallet?: IAddress; solanaWallet?: string; stellarWallet?: string; /** * Portfolio mode for a SINGLE vault read: when true, a `closed` + * `is_visible: false` vault resolves normally instead of coming back as * null. Needed by any caller reading ONE vault by address on behalf of a * holder — a position in a closed vault must still resolve its metadata, or * the holder is left with no way to act on it. * * The plural counterpart is {@link IGetVaultsOptions.includeClosed}; this is * the same flag on the per-address path. * * @default false */ includeClosed?: boolean; } /** * Options accepted by `getVaults` — on both the `AugustSDK` facade and the * underlying `AugustVaults` module. Defined once so the two signatures cannot * drift (the facade previously declared a narrower inline type that rejected * documented options like `includeClosed` at compile time). */ export interface IGetVaultsOptions extends IVaultCustomOptions { chainIds?: number[]; headers?: IWSMonitorHeaders; loadSubaccounts?: boolean; loadSnapshots?: boolean; /** * Portfolio mode: include closed vaults in the result. * * By default (`false`) closed vaults are excluded, so marketplace / * discovery callers never receive a `status: 'closed'` vault. When set, * closed vaults are returned regardless of `is_visible` (closed + * invisible vaults bucket as closed), so a consumer joining user * positions can render a position held in a closed vault on the * portfolio page. * * In this mode, loans/allocations enrichment is also skipped for closed * vaults: they have none, and the per-vault enrichment * (`getVault` → `getVaultAllocations`) otherwise re-throws when a closed * vault has no live strategy/debank data or no subaccounts, which would * land the vault in the `failed` bucket and silently drop it before it * reaches the filter. Skipping enrichment lets the vault survive on its * backend metadata + base on-chain read. * * @default false */ includeClosed?: boolean; /** * Maximum primary-fetch attempts per vault before the fallback * strategies (fallback RPCs, minimal fetch, extended retry) run. * Attempt `n` waits `baseDelay * 2^(n-1)` ms before retrying, so the * default (5 attempts, 2000 ms base) can spend up to 30s of backoff on * a single persistently-failing vault. Callers racing this method * against their own timeout should lower it (e.g. `2`) so one flaky * vault cannot exhaust the whole budget. * * @default 5 */ maxRetries?: number; /** * Base backoff delay in **milliseconds** for the per-vault retry * schedule (see `maxRetries`). * * @default 2000 */ baseDelay?: number; }