Solard

History

Durable replay, market history, coverage, and event streams.

Neutral replay

history.replay

Reconstruct a normalized event history for one token, including mint/burn/transfer/owner-change/claim records and coverage metadata.

ts
history.replay(
  token: TokenRef,
  options?: ReplayOptions,
): Promise<ReplayHistory>

type ReplayOptions = {
  recipient?: string | PublicKey;
  provider?: "auto" | "solscan" | "rpc";
  maxPages?: number;
  claimMaxPages?: number;
  onProgress?: (progress: TokenEventHistoryProgress) => void;
};
  • ReplayHistory is both iterable and indexable through its items property. Each ReplayItem contains beforeBalance and postBalance maps plus normalized payouts and the underlying canonical event.
  • Coverage is explicit: fromCreation, throughSlot, complete, warnings, and updatedAtMs tell you whether the reconstructed history is suitable for authoritative accounting.
  • recipient narrows creator-reward reconstruction to a reward recipient. provider chooses auto, Solscan, or direct RPC reconstruction.

Returns: ReplayHistory { mint, items, coverage } that also implements Iterable<ReplayItem>.

ts
const history = await slrd.history.replay(token, {
  provider: "auto",
});

if (!history.coverage.complete) {
  console.warn(history.coverage.warnings);
}

for (const item of history) {
  console.log(item.slot, item.trx, item.signature);
}

history.merge

Merge multiple replay histories or item iterables into one deterministically ordered ReplayItem array.

ts
history.merge(histories: readonly (ReplayHistory | Iterable<ReplayItem>)[]): ReplayItem[]

Returns: ReplayItem[].

Market history

history.market

Ensure durable token history coverage and return the token's persisted sparse 1-second market candle series.

ts
history.market(
  token: TokenRef,
  options?: MarketHistoryOptions,
): Promise<MarketHistory>

type MarketHistoryOptions = {
  commitment?: "confirmed" | "finalized";
  pageSize?: number;
  transactionBatchSize?: number;
  transactionConcurrency?: number;
  rpcTimeoutMs?: number;
  rpcRetries?: number;
  retryDelayMs?: number;
  maxSignaturesPerAddress?: number;
  priceSampleMs?: number;
  replace?: boolean;
  backfill?: boolean;
  maxRaydiumPools?: number;
  onProgress?: (progress: TokenHistoryBackfillProgress) => void;
};
  • When backfill is not explicitly false, the core path backfills when stored coverage is missing/incomplete or replace=true.
  • MarketHistory contains mint, quoteMint, TokenHistoryCoverage, and candles1s. Backfill controls RPC paging, transaction hydration concurrency/retries, and price sampling.

Returns: MarketHistory { mint, quoteMint, coverage, candles1s }.

Replay event subscriptions

events(token, options?)

Open an async replay-event subscription for one token.

ts
events(
  token: TokenRef,
  options?: ReplayEventsOptions,
): Promise<ReplayEventSubscription>

type ReplayEventsOptions = ReplayOptions & {
  pollMs?: number;
  signal?: AbortSignal;
};
  • The subscription is AsyncIterable<ReplayItem>, exposes mint and a watermark slot, and has an async close() method.
  • pollMs controls polling cadence and signal allows external cancellation. Provider and replay page controls are inherited from ReplayOptions.

Returns: ReplayEventSubscription.

ts
const stream = await slrd.events(token, { pollMs: 2_000 });
try {
  for await (const item of stream) {
    console.log(item.trx, item.signature);
  }
} finally {
  await stream.close();
}

events.merge

Merge several replay subscriptions into one AsyncIterable stream with a shared close() method.

ts
events.merge(streams: readonly ReplayEventSubscription[]): MergedReplayEventStream

Returns: MergedReplayEventStream.

Replay is for ordered, durable reconstruction. Live subscriptions are for reacting to launches, migrations, and trades.

Replay item shape

ts
type ReplayItem = {
  id: string;
  mint: string;
  signature: string;
  slot: number;
  timestampSec: number | null;
  transactionIndex: number | null;
  instructionIndex: number | null;
  innerInstructionIndex: number | null;
  trx: "mint" | "burn" | "transfer" | "change_owner" | "claim";
  beforeBalance: ReadonlyMap<string, bigint>;
  postBalance: ReadonlyMap<string, bigint>;
  payouts: readonly ReplayPayout[];
  raw: SolardCanonicalEvent;
};