Skip to content
markpaper

src/ops/status.ts

v0.1.0 · 2.4 KB

Download file
import { type BindingExpect, headerProblems, signerIdentityProblems } from '../binding/check.js';
import { describeCapabilities, type TraderHeader, traderRestrictions } from '../onchain/header.js';
import type { ExchangeStatus } from '../rest/client.js';
import type { SidecarHealthView } from '../signer/health.js';

export function exchangeProblems(e: ExchangeStatus): string[] {
  const p: string[] = [];
  if (!e.active || e.runningState !== 'active')
    p.push(`Exchange not active: runningState=${e.runningState}, active=${e.active}`);
  if (!e.withdrawalsAvailable) p.push('Withdrawals unavailable');
  return p;
}
export function solLow(h: SidecarHealthView | null, minSolLamports: bigint): boolean | null {
  if (minSolLamports < 0n) throw new TypeError('SOL threshold must be nonnegative');
  return h?.solLamports !== null && h?.solLamports !== undefined ? h.solLamports < minSolLamports : null;
}
export function evaluateAccountStatus(opts: {
  health: SidecarHealthView | null;
  header: TraderHeader | null;
  exchange: ExchangeStatus | null;
  expect: BindingExpect;
  minSolLamports: bigint;
}) {
  const p = [
    ...(opts.health ? signerIdentityProblems(opts.health, opts.expect) : []),
    ...(opts.header ? headerProblems(opts.header, opts.expect) : []),
  ];
  return {
    verdict: p.length ? 'lost' : opts.health && opts.header ? 'ok' : 'unknown',
    bindingProblems: p,
    restrictions: opts.header ? traderRestrictions(describeCapabilities(opts.header.flags)) : [],
    solLow: solLow(opts.health, opts.minSolLamports),
    exchangeProblems: opts.exchange ? exchangeProblems(opts.exchange) : [],
    signerReadonly: opts.health?.readonly ?? null,
    startupHeld: opts.health ? (opts.health.inflight ?? 0) > 0 || (opts.health.stale ?? 0) > 0 : null,
  };
}
export function createStartupHold() {
  let held: { inflight: number; stale: number } | null = null;
  return {
    note(inflight: number, stale: number) {
      if (!Number.isSafeInteger(inflight) || !Number.isSafeInteger(stale) || inflight < 0 || stale < 0)
        throw new TypeError('Invalid signer counts');
      held = inflight > 0 || stale > 0 ? { inflight, stale } : null;
    },
    placementsHeld: () => held !== null,
    allows(operation: 'place' | 'cancel' | 'fullClose') {
      return held === null || operation !== 'place';
    },
    reason() {
      return held ? `Unresolved signer intents: inflight=${held.inflight}, stale=${held.stale}` : null;
    },
  };
}
All files