/** * Off-chain mirror of the `august_vault` pricing math. * * Used to quote what a deposit or redeem is expected to return so a slippage * floor can be handed to `deposit_checked` / `redeem_checked`. Mirrors * `VaultState::shares_for_deposit_with_offset` and * `assets_for_redeem_with_offset` (`programs/august-vault/src/state/vault.rs`): * `u128` intermediates, a per-vault virtual-share offset defaulting to * `EXTRA_SHARES = 1_000_000`, a pro-rata floor (deposit) or cap (redeem), * every division rounded down; plus the withdrawal fee `redeem_checked` takes, * `ceil(assets * fee / 1e6)` at `FEE_RATE_DENOMINATOR_VALUE = 1_000_000`. * * A quote is only a quote. The program prices at execution, against state * that may have moved since the read; the floor derived here is what protects * the caller when the two differ. * * This mirror cannot validate itself — agreeing with its own tests proves * nothing about the program — so every claim below about program behaviour is * cited to its handler in `fractal-protocol/solana-upshift-vault-programs`, by * file and function rather than line. Verified against that repo at 3b91c86. * Do not "fix" the math here against intuition; re-read the handler. * * Adapter-internal. These functions are exported for `vault.actions.ts` and * the unit tests only — deliberately absent from the `adapters/solana` barrel, * so they are not public SDK surface and carry no benchmark or telemetry * taxonomy obligation. Promoting one to the barrel means taking both on. * * @packageDocumentation */ /** What the program uses when a vault stores `share_offset == 0` (vaults created before the field existed). */ export declare const DEFAULT_SHARE_OFFSET = 1000000n; /** Slippage tolerance applied when a caller gives neither `slippageBps` nor an explicit floor. */ export declare const DEFAULT_SLIPPAGE_BPS = 50; /** * Coerce an on-chain integer as Anchor decodes it (`BN`, `number`, decimal * string, or `bigint`) to `bigint`. * * @param value - The decoded field. * @param label - Named in the error when the value is not a non-negative integer. * @throws AugustSDKError when the value cannot be read as a non-negative integer. */ export declare function toBigInt(value: unknown, label: string): bigint; /** * The vault's effective share offset. A stored zero (or a state decoded from * an IDL that predates the field) resolves to the program default, exactly as * `VaultState::share_offset()` does on-chain. * * @param raw - `VaultState.shareOffset` as decoded, or `undefined`. */ export declare function resolveShareOffset(raw: unknown): bigint; /** * `localAum + deployedAum`, the `total_assets()` the program prices against. * * @param state - Decoded `VaultState`. * @throws AugustSDKError when either field is missing, which means the state * was decoded with an IDL this SDK cannot price against. */ export declare function totalAssetsOf(state: { localAum?: unknown; deployedAum?: unknown; }): bigint; /** * Whether the vault has a share price. Mirrors `SharePriceUndefined`: * outstanding shares against no assets has no price in either direction. */ export declare function hasSharePrice(supply: bigint, totalAssets: bigint): boolean; /** * Shares minted for depositing `amount` base units. * * `floor(max(amount * (supply + offset) / (totalAssets + offset), amount * supply / totalAssets))`. * Above par the offset term is the larger and binds; below par the pro-rata * floor binds so a depositor never hands value to incumbents on arrival. * * @param input - Share supply, total assets and the vault's resolved offset, * all in raw base units. * @throws AugustValidationError when the vault has no share price. */ export declare function sharesForDeposit(input: { supply: bigint; totalAssets: bigint; amount: bigint; offset: bigint; }): bigint; /** * Assets paid, before the withdrawal fee, for burning `shares`. * * `floor(min(shares * (totalAssets + offset) / (supply + offset), shares * totalAssets / supply))`. * The mirror of {@link sharesForDeposit}: above par the offset term binds, * below par the pro-rata cap does, so no redeemer takes more than its share. * * @param input - Share supply, total assets and the vault's resolved offset, * all in raw base units. * @throws AugustValidationError when the vault has no share price. */ export declare function assetsForRedeem(input: { supply: bigint; totalAssets: bigint; shares: bigint; offset: bigint; }): bigint; /** * The withdrawal fee the program takes from a gross redemption: * `ceil(assets * feePpm / 1e6)`, rounded **up** as on-chain. * * @param assets - Gross assets from {@link assetsForRedeem}. * @param feePpm - `VaultState.withdrawalFee`, parts per million. */ export declare function withdrawalFee(assets: bigint, feePpm: bigint): bigint; /** * Refuse a `slippageBps` that is not an integer in `0 .. 10_000`. * * @throws AugustValidationError when it is out of range or not an integer. */ export declare function validateSlippageBps(slippageBps: number): void; /** * Lower `expected` by `slippageBps` basis points, rounding down. * * @param expected - The quoted output in raw base units. * @param slippageBps - Integer basis points, `0` to `10_000`. * @throws AugustValidationError when `slippageBps` is out of range or not an integer. */ export declare function applySlippage(expected: bigint, slippageBps: number): bigint; /** * The `min_shares_out` to pass to `deposit_checked`: the quoted shares for * `amount`, lowered by `slippageBps`. * * Nothing is netted out, because there is no deposit-side fee. In * `instructions/deposit.rs::handler_checked` the comparison is * `require!(shares >= min_shares_out, SlippageExceeded)` directly on the * `shares_for_deposit` result, with no fee term anywhere in the handler. * Structurally too: `VaultState` carries exactly one fee field, * `withdrawal_fee`, and `deposit_checked` takes no `fee_recipient_account` * among its accounts (`redeem_checked` does), so it has no account to pay one * to. Gross and net are the same quantity here. * * Quoting from state read *before* the transaction is correct despite the * handler transferring the deposit in first: `transfer_in_ctx` moves SPL * tokens into the vault ATA, but `total_assets()` sums the stored `local_aum` * and `deployed_aum` fields, and `local_aum` is incremented only *after* * `shares_for_deposit` has been computed. Supply is likewise read before the * mint. The handler prices against the same pre-deposit figures this quote * does. * * @param input - Vault state, deposit amount and tolerance. */ export declare function quoteDepositFloor(input: { supply: bigint; totalAssets: bigint; amount: bigint; offset: bigint; slippageBps: number; }): bigint; /** * The `min_assets_out` to pass to `redeem_checked`: the quoted payout for * `shares` **net of the withdrawal fee** — which is what `redeem_checked` * compares against — lowered by `slippageBps`. * * Net rather than gross is the hinge of the whole guarantee, so it is pinned * here rather than left to be re-derived. In * `instructions/redeem.rs::handler_checked` the program computes the gross * `assets`, subtracts `fees` — the `ceil_div` of `assets * withdrawal_fee` * over `FEE_RATE_DENOMINATOR_VALUE` — and compares `min_assets_out` against * that difference, which is the figure the caller actually receives. * `Redeem::ceil_div` is `(n + d - 1) / d`, which is what * {@link withdrawalFee} reproduces. * * Getting this wrong fails quietly in the dangerous direction. Quote against * the gross payout and the floor sits a whole fee above what the program * measures, so it binds early and reverts healthy redemptions. Net it twice — * or drop the fee from a vault that charges one — and the floor sits below the * real payout by the fee, leaving protection weaker than the advertised * `slippageBps` instead of visibly broken. `withdrawal_fee` is capped just * under 10% (`set_withdrawal_fee`), which bounds that silent gap. * * @param input - Vault state, shares to burn, fee and tolerance. */ export declare function quoteRedeemFloor(input: { supply: bigint; totalAssets: bigint; shares: bigint; offset: bigint; feePpm: bigint; slippageBps: number; }): bigint;