import { Amount, AssetType, Bps, ChainId, Leverage, Timestamp, Token, UnderlyingToken } from "./primitives.js"; import { Curator } from "./curators.js"; import { ChainScopedFilter, Filterable } from "./filters.js"; import { KycRequirement } from "./rwa.js"; import { Address } from "viem"; //#region src/model/opportunities.d.ts /** * Discriminator of the two opportunity kinds. * * - `"pool"` — passive lending: deposit the underlying, earn the supply rate. * - `"strategy"` — leveraged position: deposit collateral, borrow the * underlying against it inside a credit account. **/ export type OpportunityKind = "pool" | "strategy"; /** * An off-chain points program a position accrues towards, e.g. a partner * protocol's season points. Points have no APY, so they are listed separately * from token rewards. **/ export interface PointsProgram { /** * Stable slug of the program. * * @example `"ethena-sats-s3"` **/ id: string; /** * Display name of the program. * * @example `"Ethena Sats Season 3"` **/ name: string; /** * Points earned per unit of position relative to the program's base rate, or * `null` when the program does not publish one. * * @example `2` for a 2x boost **/ multiplier: number | null; } /** * Rewards in a token, e.g. a liquidity mining program. **/ export interface TokenRewards { kind: "token"; /** * Token the rewards are paid in. **/ token: Token; /** * Extra APR earned by supplying, in basis points. * * @example `120` for +1.2% APR **/ supplyApr?: Bps; /** * Extra APR earned on the borrowed side, in basis points. Present when a * program rebates part of the borrow cost. * * @example `45` for +0.45% APR **/ borrowApr?: Bps; /** * Links with more information about the rewards program. **/ links?: string[]; } /** * Rewards accrued as points rather than tokens. **/ export interface PointRewards { kind: "point"; /** * Programs the position accrues points in. **/ points: PointsProgram[]; } /** * Any reward stream attached to an opportunity. **/ export type Rewards = TokenRewards | PointRewards; /** * A yield figure split into the part the protocol itself generates and the * incentives layered on top. **/ export interface ApyBreakdown { /** * Everything combined, in basis points: the number a UI shows as "APY". * * Absent in `onchain` mode: it folds in the incentives of {@link rewards}, * which only the backend knows. * * @example `842` for 8.42% APY * * @mode offchain **/ totalApy?: Bps; /** * The part generated by the underlying protocol alone, without incentives, * in basis points. Always readable from the chain. * * @example `610` for 6.10% APY **/ organicApy: Bps; /** * Incentives that make up the difference between {@link organicApy} and * {@link totalApy}, plus any points programs that carry no APY at all. * * @mode offchain **/ rewards?: Rewards[]; } /** * Fields both opportunity kinds share. **/ export interface OpportunityBase { /** * Chain the opportunity lives on. **/ chainId: ChainId; /** * Human-readable name for the row. * * @example `"USDC Pool"`, `"wstETH / WETH"` **/ name: string; /** * Curator of the market this opportunity belongs to. **/ curator: Curator; /** * Token that is supplied to the pool and borrowed by credit accounts. All * amounts of the opportunity are denominated in it. * * For RWA markets this is the unwrapped asset, e.g. USDC rather than * dcUSDC (the pool's on-chain underlying). **/ underlyingToken: UnderlyingToken; /** * Tokens a user can transfer from their wallet to deposit into a pool * position or to use when opening a credit account. They are not necessarily * the pool underlying or credit-account collateral tokens. **/ allowedDepositTokens: Token[]; /** * The contract's own pause flag: the pool for a {@link PoolOpportunity}, the * credit facade or the pool it borrows from for a * {@link StrategyOpportunity}. **/ paused: boolean; /** * Whether one of the market's quoted tokens is a real-world-asset token. * Read from a hardcoded per-chain list rather than from the chain. **/ rwa: boolean; /** * Whether the opportunity is being wound down and should no longer be * entered. Read from a hardcoded per-chain list, kept separately for pools * and for strategies, and unrelated to * {@link StrategyOpportunity.expirationDate}. **/ sunset: boolean; } /** * Passive lending into a Gearbox pool. * * Identified by `(chainId, pool)`, see {@link poolOpportunityId}. **/ export interface PoolOpportunity extends OpportunityBase { kind: "pool"; /** * Address of the ERC-4626 pool contract. **/ pool: Address; /** * Size of the pool: deposits plus accrued interest, i.e. * `pool.expectedLiquidity`. Denominated in the underlying rather than in * shares, so it is comparable with {@link totalBorrowedWithInterest}. **/ totalSupply: Amount; /** * Pool available liquidity. Denominated in the underlying. **/ availableLiquidity: Amount; /** * Everything the pool has lent out plus accrued interest: * `pool.expectedLiquidity - pool.availableLiquidity`. Denominated in the * underlying. **/ totalBorrowedWithInterest: Amount; /** * Yield earned by supplying to the pool. * * Its {@link ApyBreakdown.organicApy} is the pool's own supply rate ( * which consists of base interest and quota revenue) * so this group is present in `onchain` mode too, with only that part filled. **/ supplyApy: ApyBreakdown; /** * Average {@link supplyApy} over the trailing seven days. * * Absent in `onchain` mode: calculating it requires historical data. * * @mode offchain **/ supplyApyAvg7D?: ApyBreakdown; /** * Quota configuration of every collateral token of the market. **/ quotaAssets: QuotaAsset[]; } /** * A leveraged position: one credit manager plus the single target collateral * token that manager is configured around. Identified by * `(chainId, creditManager)`, see {@link strategyOpportunityId}. **/ export interface StrategyOpportunity extends OpportunityBase { kind: "strategy"; /** * Address of the credit manager the position is opened in. **/ creditManager: Address; /** * Collateral token the position is built around. **/ targetCollateral: Token; /** * Debt principal this credit manager has borrowed from the pool * (`pool.creditManagerBorrowed(creditManager)`). Denominated in the * underlying. **/ totalBorrowed: Amount; /** * Liquidation threshold of {@link targetCollateral} in this credit manager, * in basis points: the share of the collateral value that counts towards * covering debt. * * @example `9000` for an 86% threshold **/ liquidationThreshold: Bps; /** * Share of a liquidated account's value paid to the liquidator, in basis * points. * * @example `400` for a 4% premium **/ liquidationPremium: Bps; /** * Share of a liquidated account's value taken by the protocol, in basis * points. * * @example `150` for a 1.5% fee **/ liquidationFee: Bps; /** * Moment the credit facade expires, after which positions can no longer be * opened and open ones become liquidatable, or `null` when the facade is not * expirable. A timestamp in the past means it has already expired. **/ expirationDate: Timestamp | null; /** * Yield the collateral itself earns while it sits in the credit account, * before leverage. Comes from external sources rather than from the chain. * * @mode offchain **/ collateralApy?: ApyBreakdown; /** * Average {@link collateralApy} over the trailing seven days. * * @mode offchain **/ collateralApyAvg7D?: ApyBreakdown; /** * Annual cost of the borrowed underlying, in basis points, including the * protocol's interest fee. * * @example `520` for 5.2% APY **/ borrowApy: Bps; /** * Average {@link borrowApy} over the trailing seven days, in basis points. * * Absent in `onchain` mode: calculating it requires historical data. * * @mode offchain **/ borrowApyAvg7D?: Bps; /** * Annual quota cost of {@link targetCollateral}, in basis points, including * the protocol's interest fee: `pqk.quotaRate × (1 + feeInterest)`. Quota * accrues on the quoted amount and carries the same DAO fee as * {@link borrowApy}. * * @example `90` for 0.9% APY **/ quotaRate: Bps; /** * Average {@link quotaRate} over the trailing seven days, in basis points. * * Absent in `onchain` mode: calculating it requires historical data. * * @mode offchain **/ quotaRateAvg7D?: Bps; /** * Size of the strategy: the summed total value of the credit accounts * opened in this credit manager. * * Absent in `onchain` mode. * * @mode offchain **/ totalValue?: Amount; /** * Share of {@link totalValue} that is borrowed, in basis points: * `totalBorrowed / totalValue`. * * Absent in `onchain` mode, because its denominator is, see * {@link totalValue}. * * @example `7500` for 75% utilization * * @mode offchain **/ utilization?: Bps; /** * Free liquidity of the pool the strategy borrows from, denominated in the * underlying. Same value the market's {@link PoolOpportunity} reports. **/ availableLiquidity: Amount; /** * Size of the pool the strategy borrows from, `pool.expectedLiquidity`. * Same value the market's {@link PoolOpportunity} reports. * * @mode onchain **/ totalSupply?: Amount; /** * Percentage of accrued interest in bps taken by the protocol as profit. * * @mode onchain **/ feeInterest?: Bps; /** * Smallest debt a position in this credit manager may hold, denominated in * the underlying (`creditFacade.minDebt`). **/ minDebt: Amount; /** * Cap on the total debt this credit manager may borrow from the pool, shared * by all of its accounts and denominated in the underlying * (`creditManagerDebtParams.limit`). **/ totalDebtLimit: Amount; /** * Largest debt a single new position can take on right now: the tightest of * the credit manager's remaining debt limit, the pool's free liquidity and * the facade's per-account `maxDebt`. Zero while borrowing is frozen * (`maxDebtPerBlockMultiplier == 0`). **/ maxBorrowAmount: Amount; /** * Highest total-value leverage the liquidation threshold allows: * `(1 − 0.05) / (1 − liquidationThreshold)`. The 5% safety margin keeps a * maxed position slightly above HF = 1. * * @example `9.5` at a 90% threshold **/ maxLeverage: Leverage; } /** * A row of the opportunities list. **/ export type Opportunity = PoolOpportunity | StrategyOpportunity; /** * Canonical id of an opportunity: the string used to match a row read from the * chain with the same row served by the backend. **/ export type OpportunityId = string; /** * Builds the canonical id of a pool opportunity. * * @example * ```ts * poolOpportunityId(1, "0xda00...") // "1:0xda00..." * ``` **/ export declare function poolOpportunityId(chainId: ChainId, pool: Address): OpportunityId; /** * Builds the canonical id of a strategy opportunity. * * @example * ```ts * strategyOpportunityId(1, "0x3eb9...") // "1:0x3eb9..." * ``` **/ export declare function strategyOpportunityId(chainId: ChainId, creditManager: Address): OpportunityId; /** * Canonical id of any opportunity, dispatching on {@link Opportunity.kind}. **/ export declare function opportunityId(opportunity: Opportunity): OpportunityId; /** * Optional narrowing of an opportunities list. * * The list is filtered in memory over final values, so there is no paging and * no sorting: a screen sorts what it got. * * Every condition is optional and an omitted one matches any value, so an * empty filter is the same as no filter at all. A condition can also be set to * `"all"` to say the same thing explicitly, which is what a UI whose state has * an "any" option holds, see {@link Filterable}. Conditions combine with AND. **/ export interface OpportunityFilter extends ChainScopedFilter { /** * Keep only pools or only strategies. **/ kind?: Filterable; /** * Keep only opportunities whose {@link OpportunityBase.underlyingToken} is of * this class, which for an RWA market means the class of the token its * wrapper holds. An underlying that is not in the hardcoded table never * matches, so a set filter also drops unclassified rows. **/ underlyingType?: Filterable; /** * Keep only paused opportunities, or only unpaused ones. **/ paused?: Filterable; /** * Keep only opportunities being wound down, or only the ones that are not. **/ sunset?: Filterable; /** * Keep only opportunities that accept RWA collateral, or only the ones that * do not. **/ rwa?: Filterable; } /** * Whether an opportunity satisfies every condition of a filter. * * This is the single definition of what each condition means: every source * builds its rows first and runs them through here, so the chain and the * backend cannot disagree on what a filter selects. * * @param opportunity - Row to test. * @param filter - Conditions to test against. An absent filter matches * anything. **/ export declare function matchesOpportunityFilter(opportunity: Opportunity, filter?: OpportunityFilter): boolean; /** * One point of an interest rate curve. **/ export interface RateCurvePoint { /** * Utilization this point is sampled at, in basis points. * * @example `9000` for 90% utilization **/ utilization: Bps; /** * Rate depositors earn at this utilization, in basis points. * * @example `430` for 4.3% **/ supplyApy: Bps; /** * Base rate borrowers pay at this utilization, in basis points. Excludes the * per-credit-manager interest fee, because the curve belongs to the pool and * every credit manager of a market can charge a different one. * * @example `620` for 6.2% **/ borrowApy: Bps; } /** * The pool's interest rate model, evaluated into chart-ready points so that no * consumer has to reimplement the model. **/ export interface RateCurve { /** * Points ordered by ascending utilization, always including the kinks of the * model so the polyline is exact rather than approximated. **/ points: RateCurvePoint[]; /** * Utilization above which borrowing is forbidden, in basis points, or `null` * when the model has no such cutoff. * * @example `9000` for a cutoff at 90% utilization **/ borrowingLimitUtilization: Bps | null; } /** * Quota configuration of one collateral token: how much of it the market * accepts in total, and what holding it costs. **/ export interface QuotaAsset { /** * Token the quota applies to. **/ token: Token; /** * Annual quota rate paid on the quoted amount, in basis points. * * @example `250` for 2.5% per year **/ quotaRate: Bps; /** * Maximum amount that can be quoted across all credit accounts, denominated * in the market's underlying. **/ limit: Amount; /** * Amount currently quoted, denominated in the market's underlying. **/ used: Amount; /** * TODO: add description * * @mode offchain **/ allocationShare?: Bps; /** * TODO: add description * * @mode offchain **/ allocatedDebt?: Amount; } /** * A price feed and the feeds it is composed of. **/ export interface PriceFeedData { /** * Display name of the feed. * * @example `"CompositePriceFeed wstETH / USD"` **/ name: string; /** * Gearbox price feed contract type. * * @example `"PRICE_FEED::COMPOSITE"`, `"PRICE_FEED::REDSTONE"` **/ type: string; /** * Address of the feed contract. **/ feedAddress: Address; /** * Feeds this feed reads from. Empty for a leaf feed. **/ dependencies: PriceFeedData[]; } /** * Prices and feeds behind a strategy, i.e. everything a liquidation-price chart * needs. **/ export interface PriceFeedSummary { /** * Price of one whole underlying token in USD. * * @example `1.0001` for USDC **/ underlyingPriceInUsd: number; /** * Price of one whole collateral token in USD. * * @example `4210.55` for wstETH **/ collateralPriceInUsd: number; /** * Price of one whole collateral token expressed in the underlying. * * @example `4210.13` for wstETH priced in USDC **/ collateralPriceInUnderlying: number; /** * Main feed of the underlying token. **/ underlyingFeed: PriceFeedData; /** * Main feed of the collateral token. Reserve feeds are not included. **/ collateralFeed: PriceFeedData; } /** * A pool opportunity plus the data only its detail screen needs. **/ export interface PoolOpportunityDetail extends PoolOpportunity { /** * Interest rate curve of the pool. **/ rateCurve: RateCurve; } /** * A strategy opportunity plus the data only its detail screen needs. **/ export interface StrategyOpportunityDetail extends StrategyOpportunity { /** * Interest rate curve of the pool the strategy borrows from. **/ rateCurve: RateCurve; /** * Prices and feeds of the underlying and the target collateral. **/ priceFeeds: PriceFeedSummary; /** * KYC gate of this strategy, independent of any wallet. `null` when the * strategy is not KYC-gated. `undefined` only in `offchain` mode, until the * backend serves it. In `both` mode `kyc` is taken from the chain whenever * that leg succeeded. **/ kyc?: KycRequirement | null; } /** * Detailed view of any opportunity. **/ export type OpportunityDetail = PoolOpportunityDetail | StrategyOpportunityDetail; /** * Identifies a pool opportunity in a detail request. **/ export interface PoolOpportunityKey { chainId: ChainId; pool: Address; } /** * Identifies a strategy opportunity in a detail request. The credit manager * identifies it on its own: each manager has exactly one target collateral. **/ export interface StrategyOpportunityKey { chainId: ChainId; creditManager: Address; } /** * {@link PoolOpportunityKey} tagged with its kind, for requests that accept * both kinds. **/ export interface PoolOpportunityRef extends PoolOpportunityKey { kind: "pool"; } /** * {@link StrategyOpportunityKey} tagged with its kind, for requests that accept * both kinds. **/ export interface StrategyOpportunityRef extends StrategyOpportunityKey { kind: "strategy"; } /** * Identifies any opportunity, for requests that accept both kinds. **/ export type OpportunityKey = PoolOpportunityRef | StrategyOpportunityRef; /** * Protocol-wide aggregate over every opportunity, served by the backend rather * than summed by a consumer: the landing page's headline figures. **/ export interface OpportunityTotals { /** * Total value locked in Gearbox Protocol **/ tvl: number; /** * Total borrowed from pools in Gearbox Protocol **/ totalBorrowed: number; /** * Total supplied to pools in Gearbox Protocol **/ totalSupply: number; } //#endregion