src/ops/status.ts
v0.1.0 · 2.4 KB
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;
},
};
}