import { EIP712OrderValues, Market, OrderAppendix, PerpBalance, PerpMarket, ProductEngineType, SignatureParams, SpotBalance, SpotMarket, Subaccount, } from '@nadohq/shared'; import BigNumber from 'bignumber.js'; import { Address, Hex } from 'viem'; import { CandlestickPeriod } from './CandlestickPeriod'; import { IndexerEventType } from './IndexerEventType'; import { IndexerLeaderboardRankType } from './IndexerLeaderboardType'; import { NadoTx, NadoWithdrawCollateralTx, NadoWithdrawCollateralV2Tx, } from './NadoTx'; import { IndexerServerCashIncentivesWalletStatus, IndexerServerFastWithdrawalSignatureParams, IndexerServerListSubaccountsParams, IndexerServerTriggerTypeFilter, } from './serverTypes'; /** * Base types */ export type IndexerSpotBalance = Omit; export type IndexerPerpBalance = Omit; export interface IndexerEventSpotStateSnapshot { type: ProductEngineType.SPOT; preBalance: IndexerSpotBalance; postBalance: IndexerSpotBalance; market: SpotMarket; } export interface IndexerEventPerpStateSnapshot { type: ProductEngineType.PERP; preBalance: IndexerPerpBalance; postBalance: IndexerPerpBalance; market: PerpMarket; } export type IndexerEventBalanceStateSnapshot = | IndexerEventSpotStateSnapshot | IndexerEventPerpStateSnapshot; export interface IndexerBalanceTrackedVars { netInterestUnrealized: BigNumber; netInterestCumulative: BigNumber; netFundingUnrealized: BigNumber; netFundingCumulative: BigNumber; netEntryUnrealized: BigNumber; netEntryCumulative: BigNumber; quoteVolumeCumulative: BigNumber; cumulativeTradeCount: BigNumber; } export interface IndexerEvent< TStateType extends IndexerEventBalanceStateSnapshot = IndexerEventBalanceStateSnapshot, > { subaccount: string; isolated: boolean; // The product ID associated with the isolated perp market. This is only used when productId === QUOTE_PRODUCT_ID and isolated === true isolatedProductId: number | null; productId: number; submissionIndex: string; eventType: IndexerEventType; state: TStateType; trackedVars: IndexerBalanceTrackedVars; } export interface IndexerEventWithTx< TStateType extends IndexerEventBalanceStateSnapshot = IndexerEventBalanceStateSnapshot, > extends IndexerEvent { timestamp: BigNumber; tx: NadoTx; } /** * List subaccounts */ export type ListIndexerSubaccountsParams = IndexerServerListSubaccountsParams; export type ListIndexerSubaccountsResponse = ({ hexId: string; // Unix timestamp in seconds createdAt: number; isolated: boolean; } & Subaccount)[]; /** * Subaccount snapshots */ export interface GetIndexerMultiSubaccountSnapshotsParams { subaccounts: Subaccount[]; // A series of timestamps for which to return a summary of each subaccount timestamps: number[]; // If not given, will return both isolated & non-iso balances isolated?: boolean; } export type IndexerSnapshotBalance< TStateType extends IndexerEventBalanceStateSnapshot = IndexerEventBalanceStateSnapshot, > = IndexerEvent; export interface IndexerSubaccountSnapshot { timestamp: BigNumber; balances: IndexerSnapshotBalance[]; } export interface GetIndexerMultiSubaccountSnapshotsResponse { // Utility for retrieving a subaccount's hex ID, in the same order as the request params subaccountHexIds: string[]; // Map of subaccount hex -> timestamp requested -> summary for that time snapshots: Record>; } /** * Perp prices */ export interface GetIndexerPerpPricesParams { productId: number; } export interface IndexerPerpPrices { productId: number; indexPrice: BigNumber; markPrice: BigNumber; // Seconds updateTime: BigNumber; } export type GetIndexerPerpPricesResponse = IndexerPerpPrices; export interface GetIndexerMultiProductPerpPricesParams { productIds: number[]; } // Map of productId -> IndexerPerpPrices export type GetIndexerMultiProductPerpPricesResponse = Record< number, IndexerPerpPrices >; /** * Oracle prices */ export interface GetIndexerOraclePricesParams { productIds: number[]; } export interface IndexerOraclePrice { productId: number; oraclePrice: BigNumber; // Seconds updateTime: BigNumber; } export type GetIndexerOraclePricesResponse = IndexerOraclePrice[]; /** * Funding rates */ export interface GetIndexerFundingRateParams { productId: number; } export interface IndexerFundingRate { productId: number; fundingRate: BigNumber; // Seconds updateTime: BigNumber; } export type GetIndexerFundingRateResponse = IndexerFundingRate; export interface GetIndexerMultiProductFundingRatesParams { productIds: number[]; } // Map of productId -> IndexerFundingRate export type GetIndexerMultiProductFundingRatesResponse = Record< number, IndexerFundingRate >; /** * Funding rate history */ export interface GetIndexerFundingRateHistoryParams { productId: number; /** * Unix epoch in seconds, inclusive lower bound. Only rates with `timestamp >= startTimeInclusive` * are returned, paging forward from that time. When omitted, the most recent `limit` rates are returned. */ startTimeInclusive?: number; /** * Unix epoch in seconds, inclusive upper bound. Only rates with `timestamp <= endTimeInclusive` * are returned. Defaults to the current time. */ endTimeInclusive?: number; /** Max number of rates to return. Defaults to 100, max 1000. */ limit?: number; } export interface IndexerFundingRateHistoryEntry { productId: number; // Seconds timestamp: BigNumber; /** * Realized hourly funding rate at this tick, where 1 = 100%. * Multiply by 24 for the daily equivalent. */ fundingRateFrac: BigNumber; } /** * Entries are always ordered ascending by `timestamp`. To paginate forward, * pass the last entry's `timestamp + 1` as the next request's `startTimeInclusive`. */ export type GetIndexerFundingRateHistoryResponse = IndexerFundingRateHistoryEntry[]; /** * Portfolio */ export interface GetIndexerPortfolioParams { /** * Cross-margin subaccount to query. Its value aggregates the cross-margin * account plus every isolated child; isolated subaccounts are rejected. */ subaccount: Subaccount; } export type IndexerPortfolioPeriod = | 'day' | 'week' | 'month' | 'allTime' | 'perpDay' | 'perpWeek' | 'perpMonth' | 'perpAllTime'; export interface IndexerPortfolioPoint { // Unix seconds timestamp: BigNumber; // USDT0-denominated, except on `marketCountHistory`, where it is an integer count. value: BigNumber; } /** * All five series are aligned: same timestamps, same length. They share the same * baseline — the first snapshot at or after the timeframe start — so every series * except `accountValueHistory` begins at `0` and accumulates from there. */ export interface IndexerPortfolioHistory { // Mark-to-market account value at each timestamp, USDT0-denominated. accountValueHistory: IndexerPortfolioPoint[]; /** * Trading PnL over the timeframe, baseline-subtracted so the first visible * point is `0`. Capital flows (deposits/withdrawals/transfers) are netted out. */ pnlHistory: IndexerPortfolioPoint[]; /** * Cumulative traded quote volume within the timeframe up to each timestamp, * USDT0-denominated. */ volumeHistory: IndexerPortfolioPoint[]; /** * Average trade size within the timeframe up to each timestamp — the * timeframe's quote volume divided by its trade count, or `0` when no trades * have occurred yet. A trade is a single fill, so an order matched against * multiple resting orders counts once per fill. */ tradeSizeHistory: IndexerPortfolioPoint[]; /** * Number of distinct markets traded within the timeframe up to each * timestamp. Only markets with at least one fill inside the timeframe count. */ marketCountHistory: IndexerPortfolioPoint[]; } export type GetIndexerPortfolioResponse = Record< IndexerPortfolioPeriod, IndexerPortfolioHistory >; /** * Portfolio Calendar */ export interface GetIndexerPortfolioCalendarParams { /** * Cross-margin subaccount to query. Its value aggregates the cross-margin * account plus every isolated child; isolated subaccounts are rejected. */ subaccount: Subaccount; /** First day of the range, unix seconds, UTC midnight (divisible by 86400). */ startTime: number; /** Last day of the range, unix seconds, UTC midnight, inclusive. The range is capped at 500 days. */ endTime: number; } export interface IndexerPortfolioCalendarDay { // UTC midnight of the day, unix seconds. date: BigNumber; /** * The scope's trading PnL for the day (USDT0): change in mark-to-market value * over the day with capital flows (deposits/withdrawals/transfers) netted out. */ pnl: BigNumber; // The scope's traded quote volume (USDT0) during the day. volume: BigNumber; /** * Number of fills of the scope during the day. A trade is a single fill — an * order matched against multiple resting orders counts once per fill. */ tradeCount: BigNumber; // Markets of the scope with at least one fill during the day, ascending. Empty when nothing was traded. productIds: number[]; } /** * Both scopes cover the same set of days, ascending. Days before the * subaccount's first recorded activity return zeroed entries with an empty * `productIds`; days after the latest available data are omitted. */ export interface GetIndexerPortfolioCalendarResponse { spot: IndexerPortfolioCalendarDay[]; perp: IndexerPortfolioCalendarDay[]; } /** * Candlesticks */ export interface GetIndexerCandlesticksParams { productId: number; period: CandlestickPeriod; // Seconds maxTimeInclusive?: number; limit: number; } // Semi-Tradingview compatible bars export interface Candlestick { // In SECONDS, for TV compat, this needs to be in millis time: BigNumber; open: BigNumber; high: BigNumber; low: BigNumber; close: BigNumber; volume: BigNumber; } export type GetIndexerCandlesticksResponse = Candlestick[]; export type GetIndexerEdgeCandlesticksResponse = GetIndexerCandlesticksResponse; export type GetIndexerEdgeCandlesticksParams = GetIndexerCandlesticksParams; /** * Product snapshots */ export interface GetIndexerProductSnapshotsParams { // Max submission index, inclusive startCursor?: string; productId: number; maxTimestampInclusive?: number; limit: number; } export interface IndexerProductSnapshot extends Market { submissionIndex: string; } export type GetIndexerProductSnapshotsResponse = IndexerProductSnapshot[]; export interface GetIndexerMultiProductSnapshotsParams { productIds: number[]; maxTimestampInclusive?: number[]; } // Map of timestamp -> (productId -> IndexerProductSnapshot) export type GetIndexerMultiProductSnapshotsResponse = Record< string, Record >; export interface IndexerSnapshotsIntervalParams { /** Currently accepts all integers, in seconds */ granularity: number; /** * Optional upper bound for snapshot timestamps (in seconds). * Without this, snapshots will default to align with last UTC midnight, * which can make "Last 24h" metrics inaccurate. */ maxTimeInclusive?: number; limit: number; } /** * Market snapshots */ export interface GetIndexerMarketSnapshotsParams extends IndexerSnapshotsIntervalParams { // Defaults to all productIds?: number[]; } export interface IndexerMarketSnapshot { timestamp: BigNumber; cumulativeUsers: BigNumber; dailyActiveUsers: BigNumber; tvl: BigNumber; cumulativeVolumes: Record; cumulativeTakerFees: Record; cumulativeSequencerFees: Record; cumulativeMakerFees: Record; cumulativeTrades: Record; cumulativeLiquidationAmounts: Record; openInterestsQuote: Record; totalDeposits: Record; totalBorrows: Record; fundingRates: Record; depositRates: Record; borrowRates: Record; cumulativeTradeSizes: Record; cumulativeInflows: Record; cumulativeOutflows: Record; oraclePrices: Record; } export type GetIndexerMarketSnapshotsResponse = IndexerMarketSnapshot[]; export type GetIndexerEdgeMarketSnapshotsParams = IndexerSnapshotsIntervalParams; // Map of chain id -> IndexerMarketSnapshot[] export type GetIndexerEdgeMarketSnapshotResponse = Record< number, IndexerMarketSnapshot[] >; /** * Events */ // There can be multiple events per tx, this allows a limit depending on usecase export type GetIndexerEventsLimitType = 'events' | 'txs'; export interface GetIndexerEventsParams { // Max submission index, inclusive startCursor?: string; subaccounts?: Subaccount[]; productIds?: number[]; // If not given, will return both isolated & non-iso events isolated?: boolean; eventTypes?: IndexerEventType[]; maxTimestampInclusive?: number; // Descending order for idx (time), defaults to true desc?: boolean; limit?: { type: GetIndexerEventsLimitType; value: number; }; } export type GetIndexerEventsResponse = IndexerEventWithTx[]; /** * Historical orders */ export interface GetIndexerOrdersParams { // Max submission index, inclusive startCursor?: string; subaccounts?: Subaccount[]; minTimestampInclusive?: number; maxTimestampInclusive?: number; limit?: number; productIds?: number[]; triggerTypes?: IndexerServerTriggerTypeFilter[]; // If not given, will return both isolated & non-iso orders isolated?: boolean; digests?: string[]; } export interface IndexerOrder { digest: string; subaccount: string; productId: number; submissionIndex: string; lastFillSubmissionIndex: string; amount: BigNumber; price: BigNumber; expiration: number; // Order metadata from appendix appendix: OrderAppendix; nonce: BigNumber; isolated: boolean; // Derived from the nonce recvTimeSeconds: number; // Fill amounts baseFilled: BigNumber; // Includes fee quoteFilled: BigNumber; // Includes sequencer fee totalFee: BigNumber; builderFee: BigNumber; realizedPnl: BigNumber; // Signed closed amount (positive for longs, negative for shorts) closedAmount: BigNumber; // Cumulative realized entry price for the closed amount on an order closedNetEntry: BigNumber; // Total isolated margin on the position before the close. Only present for isolated margin orders; null for cross-margin orders preCloseMargin: BigNumber | null; // Unix timestamp (seconds) of the first fill on the order firstFillTimestamp: BigNumber; // Unix timestamp (seconds) of the last fill on the order lastFillTimestamp: BigNumber; /** Balances before the order was filled */ preBalances: IndexerMatchEventBalances; /** Balances after the order was filled */ postBalances: IndexerMatchEventBalances; } export type GetIndexerOrdersResponse = IndexerOrder[]; /** * Match events */ export interface GetIndexerMatchEventsParams { // When not given, will return all maker events subaccounts?: Subaccount[]; productIds?: number[]; // If not given, will return both isolated & non-iso events isolated?: boolean; maxTimestampInclusive?: number; limit: number; // Max submission index, inclusive startCursor?: string; } // There are 2 balance states per match event if the match is in a spot market, but only one if the match is in a perp market export interface IndexerMatchEventBalances { base: IndexerSpotBalance | IndexerPerpBalance; quote?: IndexerSpotBalance; } export interface IndexerMatchEvent extends Subaccount { productId: number; digest: string; isolated: boolean; order: EIP712OrderValues; baseFilled: BigNumber; quoteFilled: BigNumber; // Includes sequencer fee totalFee: BigNumber; sequencerFee: BigNumber; builderFee: BigNumber; cumulativeBaseFilled: BigNumber; cumulativeQuoteFilled: BigNumber; cumulativeFee: BigNumber; submissionIndex: string; timestamp: BigNumber; isTaker: boolean; // Tracked vars for the balance BEFORE this match event occurred preEventTrackedVars: Pick< IndexerBalanceTrackedVars, 'netEntryCumulative' | 'netEntryUnrealized' >; preBalances: IndexerMatchEventBalances; postBalances: IndexerMatchEventBalances; tx: NadoTx; realizedPnl: BigNumber; // Signed closed amount (positive for longs, negative for shorts) closedAmount: BigNumber; // Realized entry price for the closed amount on this match (x18). Represents the total quote value at which the closed portion of the position was originally entered. closedNetEntry: BigNumber; // Margin allocated to the closed amount on this match (x18). Only present for isolated margin orders; null for cross-margin orders. margin: BigNumber | null; } export type GetIndexerMatchEventsResponse = IndexerMatchEvent[]; /** * Position history */ /** * Params for querying a subaccount's historical positions. All parameters except * `subaccount` are optional filters. */ export interface GetIndexerPositionsParams { /** * Subaccount to query. Isolated positions are also returned under the parent * subaccount, so always query with the parent. */ subaccount: Subaccount; /** When provided, only return positions of the specified product. */ productId?: number; /** `true`: only isolated positions, `false`: only cross positions. Omit for both. */ isolated?: boolean; /** `true`: only positions that are still open, `false`: only closed positions. Omit for both. */ open?: boolean; /** * Max `openId`, inclusive. To paginate, pass the last returned position's * `openId - 1` as the next request's `startCursor`. */ startCursor?: string; /** Max number of positions to return. Defaults to 100, max 500. */ limit?: number; } /** * A historical position for a subaccount in a product. A position opens when the balance * goes from zero to non-zero or flips direction, and closes when the balance returns to * zero or flips again. All amount fields are absolute values; the side of the position is * given by `direction`. */ export interface IndexerPosition { /** Subaccount hex ID associated with the position. */ subaccount: string; productId: number; isolated: boolean; /** Direction of the position. `true` for long, `false` for short. */ direction: boolean; /** `submissionIndex` of the transaction that opened the position. */ openId: string; /** `submissionIndex` of the transaction that closed the position; `-1` if still open. */ closeId: string; /** `submissionIndex` of the last transaction that updated the position. */ submissionIndex: string; /** Current size of the position; `0` once the position is closed. */ amount: BigNumber; /** Peak size reached by the position. */ maxAmount: BigNumber; /** Total amount opened on this position. */ totalOpenAmount: BigNumber; /** Total amount closed on this position. */ totalCloseAmount: BigNumber; /** Volume-weighted average entry price of the position. */ averageEntryPrice: BigNumber; /** Volume-weighted average exit price of the position. */ averageExitPrice: BigNumber; /** Total amount closed by liquidations on this position. */ liquidatedAmount: BigNumber; /** * Peak leverage reached by the isolated position; `0` for cross positions. * Set to `i128::MAX` (decimal adjusted) when the position's equity is below zero. */ maxIsolatedLeverage: BigNumber; /** Total fees paid on fills that increased the position. */ openFee: BigNumber; /** Total fees paid on fills that decreased the position. */ closeFee: BigNumber; /** Realized PnL for this position. */ realizedPnl: BigNumber; /** Unix epoch in seconds of when the position was opened. */ openTimestamp: BigNumber; /** Unix epoch in seconds of when the position was last updated. */ updateTimestamp: BigNumber; /** The transaction type that opened the position, e.g. `match_orders`. */ openReason: IndexerEventType; /** The transaction type that closed the position; `null` if still open. */ closeReason: IndexerEventType | null; /** Net funding payment on this position. Only for perp positions. */ netFundingPayment: BigNumber; /** Net interest payment on this position. Only for spot positions. */ netInterestPayment: BigNumber; /** Digest of the order that opened the position; `null` if not opened by a match. */ openDigest: string | null; /** Digest of the order that closed the position; `null` if not closed by a match or still open. */ closeDigest: string | null; netEntryUnrealized: BigNumber; } /** * Response for the positions query. */ export interface GetIndexerPositionsResponse { /** Positions in descending order by `openId`. */ positions: IndexerPosition[]; /** * Events (with their transactions) at each position's boundaries: open and close, or * open and latest update while still open. Join them to positions via * `openId` / `closeId` / `submissionIndex`. */ events: IndexerEventWithTx[]; } /** * Quote price */ export interface GetIndexerQuotePriceResponse { price: BigNumber; } /** * Linked Signer */ export interface GetIndexerLinkedSignerParams { subaccount: Subaccount; } export interface GetIndexerLinkedSignerResponse { totalTxLimit: BigNumber; remainingTxs: BigNumber; // If remainingTxs is 0, this is the time until the next link signer tx can be sent waitTimeUntilNextTx: BigNumber; // If zero address, none is configured signer: string; } /** * Interest / funding payments */ export interface GetIndexerInterestFundingPaymentsParams { subaccount: Subaccount; productIds: number[]; maxTimestampInclusive?: number; limit: number; // Max submission index, inclusive startCursor?: string; } export interface IndexerProductPayment { productId: number; submissionIndex: string; timestamp: BigNumber; paymentAmount: BigNumber; // For spots: previous spot balance at the moment of payment (exclusive of `paymentAmount`). // For perps: previous perp balance at the moment of payment + amount of perps locked in LPs (exclusive of `paymentAmount`). balanceAmount: BigNumber; // Represents the annually interest rate for spots and annually funding rate for perps. annualPaymentRate: BigNumber; oraclePrice: BigNumber; isolated: boolean; // The product ID associated with the isolated perp market. This is only used when product_id === QUOTE_PRODUCT_ID and isolated === true isolatedProductId: number | null; } export interface GetIndexerInterestFundingPaymentsResponse { interestPayments: IndexerProductPayment[]; fundingPayments: IndexerProductPayment[]; nextCursor: string | null; } /** * Referral code */ export interface GetIndexerReferralCodeParams { subaccount: Subaccount; } export interface GetIndexerReferralCodeResponse { referralCode: string | null; } /** * Maker stats */ export interface GetIndexerMakerStatisticsParams { productId: number; epoch: number; interval: number; } export interface IndexerMakerSnapshot { timestamp: BigNumber; makerFee: BigNumber; uptime: BigNumber; sumQMin: BigNumber; qScore: BigNumber; makerShare: BigNumber; expectedMakerReward: BigNumber; } export interface IndexerMaker { address: string; snapshots: IndexerMakerSnapshot[]; } export interface GetIndexerMakerStatisticsResponse { rewardCoefficient: BigNumber; makers: IndexerMaker[]; } /** * Leaderboards */ export interface GetIndexerLeaderboardParams { contestId: number; /** * The ranking metric to query by. * Optional for single-track contests (auto-selects the only track). * Required for multi-track contests — omitting it returns an error. */ rankType?: IndexerLeaderboardRankType; // Min rank inclusive startCursor?: string; limit?: number; /** Sort order. Defaults to `'DESC'`. */ order?: 'ASC' | 'DESC'; } export interface IndexerSocialAccountInfo { provider: 'twitter'; username: string; displayName: string; profileImageUrl: string; } export interface IndexerLeaderboardTrackPosition { value: BigNumber; rank: BigNumber; qualificationStatus: | 'qualified' | 'insufficient_account_value' | 'insufficient_volume' | 'insufficient_account_value_and_volume'; } export interface IndexerLeaderboardParticipant { subaccount: Subaccount; contestId: number; // Float indicating the ending account value at the time the snapshot was taken i.e: at updateTime accountValue: BigNumber; // Seconds updateTime: BigNumber; tracks: Partial< Record >; socialAccounts: IndexerSocialAccountInfo[]; } export interface GetIndexerLeaderboardResponse { participants: IndexerLeaderboardParticipant[]; } export interface GetIndexerLeaderboardParticipantParams { contestIds: number[]; subaccount: Subaccount; } export interface GetIndexerLeaderboardParticipantResponse { // If the subaccount is not eligible for a given contest, it would not be included in the response. // contestId -> IndexerLeaderboardParticipant participant: Record; } export interface GetIndexerLeaderboardRegistrationsParams { subaccount: Subaccount; /** Filter by contest IDs. Omit to return all. */ contestIds?: number[]; /** Filter by contest active status. `true` = active only, `false` = inactive only, omit for all. */ active?: boolean; } export interface RegisterLeaderboardParams extends Subaccount, SignatureParams { contestIds: number[]; /** In millis, defaults to 90s in the future. */ recvTime?: BigNumber; } export interface IndexerLeaderboardRegistration { subaccount: Subaccount; contestId: number; // Seconds updateTime: BigNumber; } export interface GetIndexerLeaderboardRegistrationsResponse { registrations: IndexerLeaderboardRegistration[]; } export type RegisterLeaderboardResponse = GetIndexerLeaderboardRegistrationsResponse; export interface GetIndexerLeaderboardContestsParams { /** Filter by contest IDs. Omit to return all. */ contestIds?: number[]; /** Filter by contest active status. `true` = active only, `false` = inactive only, omit for all. */ active?: boolean; } export interface IndexerLeaderboardContestTrack { trackId: number; rankType: IndexerLeaderboardRankType; sortOrder: 'ASC' | 'DESC'; // Float indicating the min value required to qualify for this track e.g: 250.0 accountValueThreshold: BigNumber; // Float indicating the min volume required to qualify for this track e.g: 1000.0 volumeThreshold: BigNumber; } export interface IndexerLeaderboardContest { contestId: number; // Start time in seconds startTime: BigNumber; // End time in seconds endTime: BigNumber; // Last updated time in seconds lastUpdated: BigNumber; totalParticipants: BigNumber; // For market-specific contests, only the volume from these products will be counted. requiredProductIds: number[]; active: boolean; title: string; description: string; tracks: IndexerLeaderboardContestTrack[]; } export interface GetIndexerLeaderboardContestsResponse { contests: IndexerLeaderboardContest[]; } /** * Social Accounts */ export interface ConnectSocialAccountParams extends Subaccount, SignatureParams { provider: 'twitter'; /** In millis, defaults to 90s in the future. */ recvTime?: BigNumber; } export interface ConnectSocialAccountResponse { url: string; } export interface ListIndexerSocialAccountsParams { address: Address; } export interface ListIndexerSocialAccountsResponse { accounts: IndexerSocialAccountInfo[]; } export type RevokeSocialAccountParams = ConnectSocialAccountParams; export type RevokeSocialAccountResponse = ListIndexerSocialAccountsResponse; export type GetIndexerFastWithdrawalSignatureParams = IndexerServerFastWithdrawalSignatureParams; export interface GetIndexerFastWithdrawalSignatureResponse { idx: bigint; tx: NadoWithdrawCollateralTx['withdraw_collateral']; // Present only for `WithdrawCollateralV2` withdrawals. txV2?: NadoWithdrawCollateralV2Tx['withdraw_collateral_v2']; txBytes: Hex; signatures: Hex[]; } /** * NLP */ export type GetIndexerNlpSnapshotsParams = IndexerSnapshotsIntervalParams; export interface IndexerNlpSnapshot { submissionIndex: string; timestamp: BigNumber; // Total volume traded by the NLP, in terms of the primary quote cumulativeVolume: BigNumber; cumulativeTrades: BigNumber; cumulativeMintAmountQuote: BigNumber; cumulativeBurnAmountQuote: BigNumber; cumulativePnl: BigNumber; tvl: BigNumber; oraclePrice: BigNumber; depositors: BigNumber; } export interface GetIndexerNlpSnapshotsResponse { snapshots: IndexerNlpSnapshot[]; } export interface GetIndexerBacklogResponse { // Total number of transactions stored in the indexer DB totalTxs: BigNumber; // Current nSubmissions value from the chain (i.e., number of processed txs) totalSubmissions: BigNumber; // Number of unprocessed transactions (totalTxs - totalSubmissions) backlogSize: BigNumber; // UNIX timestamp (in seconds) of when the data was last updated updatedAt: BigNumber; // Estimated time in seconds (float) to clear the entire backlog (null if unavailable) backlogEtaInSeconds: BigNumber | null; // Current submission rate in transactions per second (float) (null if unavailable) txsPerSecond: BigNumber | null; } export interface GetIndexerSubaccountDDAParams { subaccount: Subaccount; } export interface GetIndexerSubaccountDDAResponse { address: Address; } /** * Private Alpha Choice */ export interface GetIndexerPrivateAlphaChoiceParams { address: Address; } export interface GetIndexerPrivateAlphaChoiceResponse { points: BigNumber; feeRefund: BigNumber; nftEligibility: boolean; } /** * Nado Points */ export interface GetIndexerPointsParams { address: Address; } export interface IndexerPointsEpoch { epoch: number; description: string; /** Unix timestamp in seconds */ startTime: BigNumber; /** Unix timestamp in seconds */ endTime: BigNumber; totalPoints: BigNumber; points: BigNumber; rank: number; tier: number; } export interface IndexerAllTimePoints { points: BigNumber; rank: number; tier: number; } export interface GetIndexerPointsResponse { pointsPerEpoch: IndexerPointsEpoch[]; allTimePoints: IndexerAllTimePoints; } /** * Nado XPoints (Nado x xStocks points program) */ export interface GetIndexerXPointsParams { address: Address; } export interface IndexerXPointsQuest { /** Quest identifier, e.g. `ProtocolDepositBoost` or `ProtocolTieredVolumeBoost` */ questType: string; points: BigNumber; } export interface IndexerXPointsEpoch { epoch: number; description: string; startTime: BigNumber; endTime: BigNumber; totalPoints: BigNumber; rank: number; quests: IndexerXPointsQuest[]; } export interface IndexerXPointsAllTime { totalPoints: BigNumber; rank: number; quests: IndexerXPointsQuest[]; } export interface GetIndexerXPointsResponse { pointsPerEpoch: IndexerXPointsEpoch[]; allTimePoints: IndexerXPointsAllTime; } /** * Cash Incentives (platform volume and unlocked rewards) */ export interface GetIndexerCashIncentivesParams { address: Address; } export interface IndexerCashIncentivesEventMetadata { eventId: number; description: string; /** Unix timestamp in seconds */ epochStart: BigNumber; /** Unix timestamp in seconds */ epochEnd: BigNumber; maxVolume: BigNumber; maxReward: BigNumber; minVolume: BigNumber; minReward: BigNumber; } export interface IndexerCashIncentivesEventPlatform { platformVolume: BigNumber; unlockedReward: BigNumber; } /** * `wallet.claim` variant carrying the data needed to build an Airdrop contract `claim` call. */ export interface IndexerCashIncentivesClaimableClaim { /** Discriminant marking this claim as ready to submit onchain. */ status: 'claimable'; /** Airdrop contract holding the reward. */ airdropAddress: Address; /** * Reward event identifier within the airdrop contract. This is not the same as * {@link IndexerCashIncentivesEventMetadata.eventId}, which identifies the Cash Incentives campaign. */ week: number; /** * Cumulative claimable amount in raw token units, as committed to by the merkle root. Pass this to * the contract unchanged; use {@link IndexerCashIncentivesEventWallet.reward} for display, since * the reward token's decimals are not part of the response. */ totalAmount: BigNumber; /** Merkle proof for this wallet's reward. */ proof: Hex[]; } /** * `wallet.claim` variant for events with nothing to claim, which carries only the status. */ export interface IndexerCashIncentivesUnclaimableClaim { /** Why there is nothing to claim yet. */ status: Exclude; } /** * Always present, tagged on `status`. Only the `claimable` variant carries proof data, so narrow on * `status === 'claimable'` before reading it. See * {@link IndexerServerCashIncentivesWalletStatus} for the meaning of each status. */ export type IndexerCashIncentivesWalletClaim = | IndexerCashIncentivesClaimableClaim | IndexerCashIncentivesUnclaimableClaim; export interface IndexerCashIncentivesEventWallet { /** * Reward for this wallet as a decimal token amount, already converted from the x18 value the * indexer returns. Populated before the reward becomes claimable. */ reward: BigNumber; /** Claim state for this event, always present and tagged on `status`. */ claim: IndexerCashIncentivesWalletClaim; } export interface IndexerCashIncentivesEvent { metadata: IndexerCashIncentivesEventMetadata; platform: IndexerCashIncentivesEventPlatform; wallet: IndexerCashIncentivesEventWallet; } export interface IndexerCashIncentivesWalletSummary { totalReward: BigNumber; claimableReward: BigNumber; } export interface GetIndexerCashIncentivesResponse { events: IndexerCashIncentivesEvent[]; walletSummary: IndexerCashIncentivesWalletSummary; } /** * V2 Tickers */ /** * Market type for ticker filtering */ export type TickerMarketType = 'spot' | 'perp'; /** * Parameters for querying v2 tickers endpoint */ export interface GetIndexerV2TickersParams { /** * Filter tickers by market type (spot or perp) * @example 'spot' * @example 'perp' */ market?: TickerMarketType; /** * Whether to include edge products * @default false */ edge?: boolean; } /** * Individual ticker data from v2 endpoint */ export interface IndexerV2TickerResponse { /** Unique product identifier */ productId: number; /** Unique ticker identifier */ tickerId: string; /** Base currency symbol */ baseCurrency: string; /** Quote currency symbol */ quoteCurrency: string; /** Last traded price */ lastPrice: number; /** 24h trading volume in base currency */ baseVolume: number; /** 24h trading volume in quote currency */ quoteVolume: number; /** 24h price change percentage */ priceChangePercent24h: number; } /** * Response from v2 tickers endpoint * Maps ticker IDs to their respective ticker data */ export type GetIndexerV2TickersResponse = Record< string, IndexerV2TickerResponse >; /** * Parameters for querying v2 symbols endpoint */ export interface GetIndexerV2SymbolsParams { /** * Filter by product type * @example 'spot' * @example 'perp' */ productType?: 'spot' | 'perp'; /** * Comma-separated list of product IDs to filter by * @example '2,4,42' */ productIds?: string; } /** * Market hours information for a product */ export interface IndexerV2MarketHours { /** Whether the market is currently in its regular trading session */ isOpen: boolean; /** Why the market is closed: "weekend" or "holiday". Null when open. */ reason: string | null; /** ISO 8601 UTC timestamp of the next session close. Null when closed. */ nextClose: string | null; /** ISO 8601 UTC timestamp of the next session open. Null when no upcoming open. */ nextOpen: string | null; } export type IndexerV2TradingStatus = // Normal trading, all order types accepted | 'live' // Only post-only orders accepted (taker orders rejected) | 'post_only' // Only reduce-only orders accepted; used when a market is being delisted | 'reduce_only' // No new positions can be opened; only orders that reduce existing positions are accepted. Used during periods of low activity (e.g. weekends, holidays) | 'soft_reduce_only' // No orders accepted | 'not_tradable'; /** * Individual symbol data from v2 endpoint */ export interface IndexerV2Symbol { /** Product type: "spot" or "perp" */ type: string; /** Unique product identifier */ productId: number; /** Trading symbol (e.g., "BTC-PERP", "WETH") */ symbol: string; /** Minimum price increment */ priceIncrement: BigNumber; /** Minimum order size increment (base denominated) */ sizeIncrement: string; /** Minimum order size (USDT0 denominated) */ minSize: string; /** Default maker fee rate (negative = rebate) */ makerFeeRate: BigNumber; /** Default taker fee rate */ takerFeeRate: BigNumber; /** Initial margin weight for long positions */ longWeightInitial: BigNumber; /** Maintenance margin weight for long positions */ longWeightMaintenance: BigNumber; /** Maximum open interest cap. Null if uncapped. */ maxOpenInterest: BigNumber | null; /** * Exchange rate for xStocks. Null if not applicable. */ exchangeRate: BigNumber | null; /** Current trading status */ tradingStatus: IndexerV2TradingStatus; /** Whether the market only accepts isolated margin orders */ isolatedOnly: boolean; /** Market hours information. Null for 24/7 markets. */ marketHours: IndexerV2MarketHours | null; /** * Boost tier for products with rewards boosts. Null for non-boosted products. * 0 = none, 1 = taker 4x / maker 4x, 2 = taker 3x / maker 4x */ boostType: number | null; /** Taker rewards multiplier. Null for non-boosted products. */ takerMultiplier: number | null; /** Maker rewards multiplier. Null for non-boosted products. */ makerMultiplier: number | null; } /** * Response from v2 symbols endpoint * Maps symbols to their respective data */ export type GetIndexerV2SymbolsResponse = Record;