import { randomUUID } from "node:crypto"; import { parseUsdDecimal, formatUsdNanos } from "../reseller/money.js"; import type { SurplusManagerConfig } from "./config.js"; import { SurplusClient, SurplusHttpError, type SurplusDiscoveredModel, type SurplusEarnings, type SurplusOffer, } from "./client.js"; import type { OpenRouterKeyAllowance, OpenRouterKeyClient, } from "./openRouterKey.js"; import { formatMicroUsd, quoteSurplusPrice, } from "./policy.js"; import { eligibleCompetitors, selectSurplusModelCandidates, } from "./selection.js"; import type { SurplusControllerState, SurplusOfferIntent, SurplusStateStore, } from "./state.js"; export type SurplusControllerClient = Pick< SurplusClient, | "listAllOffers" | "discoverModels" | "getMarkets" | "getOrderBook" | "testConnection" | "createOffer" | "updateOffer" | "pauseOffer" | "resumeOffer" | "getEarnings" >; export type OpenRouterAllowanceReader = Pick; export interface SurplusControllerStatus { ok: boolean; phase: SurplusControllerState["phase"] | "error" | "planned" | "suspended"; live: boolean; model: string | null; providerModelId: string | null; offerId: string | null; inputUsdPer1m: string | null; outputUsdPer1m: string | null; competitorId: string | null; remainingAllowanceUsd: string | null; reserveThresholdUsd: string; totalEarnedUsd: string | null; lastCycleAt: string | null; lastSuccessAt: string | null; lastError: string | null; } interface SurplusControllerOptions { config: SurplusManagerConfig; client: SurplusControllerClient; allowance: OpenRouterAllowanceReader; stateStore: SurplusStateStore; now?: () => number; mutationId?: () => string; log?: (message: string) => void; } export class SurplusSellerController { private readonly config: SurplusManagerConfig; private readonly client: SurplusControllerClient; private readonly allowance: OpenRouterAllowanceReader; private readonly stateStore: SurplusStateStore; private readonly now: () => number; private readonly mutationId: () => string; private readonly log: (message: string) => void; private state: SurplusControllerState | null = null; private inFlight: Promise | null = null; private timer: NodeJS.Timeout | null = null; private stopped = false; private status: SurplusControllerStatus; constructor(options: SurplusControllerOptions) { this.config = options.config; this.client = options.client; this.allowance = options.allowance; this.stateStore = options.stateStore; this.now = options.now ?? Date.now; this.mutationId = options.mutationId ?? randomUUID; this.log = options.log ?? (() => undefined); const perOfferCap = parseUsdDecimal(this.config.perOfferCapUsd, "ceil"); const aggregateCap = parseUsdDecimal(this.config.aggregateCapUsd, "floor"); if (perOfferCap > aggregateCap) { throw new Error("Surplus per-offer cap must not exceed the aggregate cap"); } this.status = { ok: false, phase: "selecting", live: this.config.live, model: null, providerModelId: null, offerId: null, inputUsdPer1m: null, outputUsdPer1m: null, competitorId: null, remainingAllowanceUsd: null, reserveThresholdUsd: this.config.reserveUsd, totalEarnedUsd: null, lastCycleAt: null, lastSuccessAt: null, lastError: null, }; } snapshot(): SurplusControllerStatus { return { ...this.status }; } healthy(): boolean { if (this.state?.phase === "completed") return true; if (!this.status.ok || this.status.lastSuccessAt === null) return false; const freshnessLimit = this.config.pollIntervalMs + this.config.requestTimeoutMs + 60_000; return this.now() - Date.parse(this.status.lastSuccessAt) <= freshnessLimit; } async start(): Promise { if (this.state !== null) return; this.state = await this.stateStore.load(); await this.runOnce(); this.schedule(); } async stop(): Promise { this.stopped = true; clearTimeout(this.timer ?? undefined); this.timer = null; if (this.inFlight) await this.inFlight; } async runOnce(): Promise { if (this.inFlight) return this.inFlight; const cycle = this.performCycle(); this.inFlight = cycle; try { await cycle; } finally { this.inFlight = null; } } private schedule(): void { if (this.stopped || this.state?.phase === "completed") return; this.timer = setTimeout(() => { void this.runOnce().finally(() => this.schedule()); }, this.config.pollIntervalMs); this.timer.unref(); } private async performCycle(): Promise { if (this.state === null) this.state = await this.stateStore.load(); const cycleAt = new Date(this.now()).toISOString(); this.status = { ...this.status, lastCycleAt: cycleAt }; if (this.state.phase === "completed") { this.markSuccess("completed", null, null); return; } try { if (this.state.phase === "selecting") await this.selectAndCreate(); else if (this.state.phase === "create_pending") await this.adoptPendingCreate(); else if (this.state.phase === "active") await this.manageActiveOffer(); else if (this.state.phase === "stopping") await this.finishStopping(); else await this.awaitSettlement(); } catch (error) { const stateAtFailure = this.state; let paused = false; if ( this.config.live && stateAtFailure !== null && "offerId" in stateAtFailure ) { try { await this.client.pauseOffer(stateAtFailure.offerId, this.mutationId()); paused = true; } catch { paused = false; } } const detail = this.safeError(error); this.status = { ...this.status, ok: false, phase: "error", lastError: paused ? `${detail}; managed offer paused` : detail, }; this.log(`Surplus cycle failed: ${this.status.lastError}`); } } private async selectAndCreate(): Promise { const offers = await this.client.listAllOffers(); const active = offers.filter((offer) => offer.status === "active"); if (active.length > 0) { await this.pauseOffers(active); this.markSuccess("suspended", null, null); return; } const allowance = await this.allowance.readAllowance(); this.assertAllowance(allowance, parseUsdDecimal(this.config.aggregateCapUsd, "ceil")); const [discovered, markets] = await Promise.all([ this.client.discoverModels( this.config.providerApiKey, this.config.providerBaseUrl, ), this.client.getMarkets(), ]); const candidates = selectSurplusModelCandidates( discovered, markets, this.config.recoveryBps, this.config.undercutBps, ); const ownOfferIds = new Set(offers.map((offer) => offer.id)); let intent: SurplusOfferIntent | null = null; let competitorId: string | null = null; for (const candidate of candidates.slice(0, this.config.maxCandidateOrderBooks)) { const book = await this.client.getOrderBook(candidate.model); const competitors = eligibleCompetitors( book.offers, this.config.sellerWallet, ownOfferIds, ); const quote = quoteSurplusPrice({ upstreamInputMicroUsdPer1m: candidate.upstreamInputMicroUsdPer1m, upstreamOutputMicroUsdPer1m: candidate.upstreamOutputMicroUsdPer1m, recoveryBps: this.config.recoveryBps, undercutBps: this.config.undercutBps, competitors, }); if (!quote.competitive) continue; try { await this.client.testConnection( this.config.providerApiKey, this.config.providerBaseUrl, candidate.model, ); } catch (error) { this.log( `Surplus candidate probe failed model=${candidate.model}: ${this.safeError(error)}`, ); continue; } intent = { model: candidate.model, providerModelId: candidate.providerModelId, inputMicroUsdPer1m: quote.inputMicroUsdPer1m, outputMicroUsdPer1m: quote.outputMicroUsdPer1m, dailyCapUsd: Number(this.config.perOfferCapUsd), idempotencyKey: this.mutationId(), createdAt: new Date(this.now()).toISOString(), baselineTrades24h: 0, }; competitorId = quote.competitorId; break; } if (intent === null) { throw new Error("No supported OpenRouter model has a safe competitive quote"); } if (!this.config.live) { this.markSuccess("planned", allowance, { intent, offerId: null, competitorId, totalEarnedMicroUsd: null, }); return; } const pending: SurplusControllerState = { version: 1, phase: "create_pending", intent, }; await this.stateStore.save(pending); this.state = pending; let createdOfferId: string | null = null; let postCreateActive: SurplusOffer[] = []; try { createdOfferId = await this.client.createOffer({ model: intent.model, apiKey: this.config.providerApiKey, sellerBaseUrl: this.config.providerBaseUrl, inputUsdPer1m: intent.inputMicroUsdPer1m / 1_000_000, outputUsdPer1m: intent.outputMicroUsdPer1m / 1_000_000, dailyCapUsd: intent.dailyCapUsd, payoutAddress: this.config.payoutAddress, idempotencyKey: intent.idempotencyKey, }); const postCreateOffers = await this.client.listAllOffers(); postCreateActive = postCreateOffers.filter( (offer) => offer.status === "active", ); const created = postCreateActive.find( (offer) => offer.id === createdOfferId, ); if ( !created || created.model !== intent.model || postCreateActive.length !== 1 ) { throw new Error( "Surplus create verification did not find exactly one expected active offer", ); } this.assertAggregateCap(postCreateOffers); const activeState: SurplusControllerState = { version: 1, phase: "active", offerId: createdOfferId, intent, highestTrades24h: 0, }; await this.stateStore.save(activeState); this.state = activeState; this.markSuccess("active", allowance, { intent, offerId: createdOfferId, competitorId, totalEarnedMicroUsd: null, }); } catch (error) { if (createdOfferId !== null) { const ids = new Set(postCreateActive.map((offer) => offer.id)); ids.add(createdOfferId); for (const id of ids) { await this.client.pauseOffer(id, this.mutationId()).catch(() => undefined); } } if (error instanceof SurplusHttpError && !error.ambiguousMutation) { const selecting: SurplusControllerState = { version: 1, phase: "selecting", }; await this.stateStore.save(selecting); this.state = selecting; } throw error; } } private async adoptPendingCreate(): Promise { if (this.state?.phase !== "create_pending") return; const pending = this.state; const offers = await this.client.listAllOffers(); const active = offers.filter((offer) => offer.status === "active"); const matches = active .filter((offer) => offer.model === pending.intent.model && normalizeUrl(offer.sellerBaseUrl) === normalizeUrl(this.config.providerBaseUrl) ) .sort((left, right) => left.id.localeCompare(right.id)); if (matches.length === 0) { const inactiveMatch = offers.some((offer) => offer.status === "inactive" && offer.model === pending.intent.model && normalizeUrl(offer.sellerBaseUrl) === normalizeUrl(this.config.providerBaseUrl) ); if (inactiveMatch && active.length === 0) { const selecting: SurplusControllerState = { version: 1, phase: "selecting", }; await this.stateStore.save(selecting); this.state = selecting; this.markSuccess("suspended", null, null); return; } if (active.length > 0) await this.pauseOffers(active); throw new Error( "Create result is ambiguous and no matching offer is visible; refusing another POST", ); } const primary = matches[0]; await this.pauseOffers(active.filter((offer) => offer.id !== primary.id)); const confirmedOffers = await this.client.listAllOffers(); const confirmedActive = confirmedOffers.filter( (offer) => offer.status === "active", ); if (confirmedActive.length !== 1 || confirmedActive[0].id !== primary.id) { await this.pauseOffers(confirmedActive); throw new Error("Adopted Surplus create did not reconcile to one active offer"); } const adopted: SurplusControllerState = { version: 1, phase: "active", offerId: primary.id, intent: pending.intent, highestTrades24h: pending.intent.baselineTrades24h, }; try { this.assertAggregateCap(confirmedOffers); await this.stateStore.save(adopted); } catch (error) { await this.pauseOffers(confirmedActive).catch(() => undefined); throw error; } this.state = adopted; this.markSuccess("active", null, { intent: adopted.intent, offerId: adopted.offerId, competitorId: null, totalEarnedMicroUsd: null, }); } private async manageActiveOffer(): Promise { if (this.state?.phase !== "active") return; const currentState = this.state; const offers = await this.client.listAllOffers(); const activeOffers = offers.filter((offer) => offer.status === "active"); const managed = offers.find((offer) => offer.id === currentState.offerId); if (!managed) { await this.pauseOffers(activeOffers); throw new Error(`Managed Surplus offer is missing: ${currentState.offerId}`); } const otherActive = activeOffers.filter( (offer) => offer.id !== currentState.offerId, ); if (otherActive.length > 0) { await this.pauseOffers(otherActive); this.markSuccess("suspended", null, null); return; } this.assertAggregateCap(offers); const allowance = await this.allowance.readAllowance(); this.assertAllowance( allowance, parseUsdDecimal(this.config.perOfferCapUsd, "ceil"), ); const discovered = await this.client.discoverModels( this.config.providerApiKey, this.config.providerBaseUrl, ); const selected = this.requireSelectedDiscovery(discovered, currentState.intent); const book = await this.client.getOrderBook(currentState.intent.model); const ownBookOffer = book.offers.find((offer) => offer.id === currentState.offerId); if ( ownBookOffer && ownBookOffer.trades24h >= currentState.highestTrades24h + this.config.stopAfterTrades ) { const stopping: SurplusControllerState = { version: 1, phase: "stopping", offerId: currentState.offerId, intent: currentState.intent, highestTrades24h: ownBookOffer.trades24h, tradeObservedAt: new Date(this.now()).toISOString(), pauseIdempotencyKey: this.mutationId(), }; await this.stateStore.save(stopping); this.state = stopping; await this.finishStopping(); return; } const ownIds = new Set(offers.map((offer) => offer.id)); const competitors = eligibleCompetitors( book.offers, this.config.sellerWallet, ownIds, ); const quote = quoteSurplusPrice({ upstreamInputMicroUsdPer1m: Math.ceil(selected.inputUsdPer1m * 1_000_000), upstreamOutputMicroUsdPer1m: Math.ceil(selected.outputUsdPer1m * 1_000_000), recoveryBps: this.config.recoveryBps, undercutBps: this.config.undercutBps, competitors, }); const nextIntent: SurplusOfferIntent = { ...currentState.intent, inputMicroUsdPer1m: quote.inputMicroUsdPer1m, outputMicroUsdPer1m: quote.outputMicroUsdPer1m, }; const priceChanged = managed.inputMicroUsdPer1m !== quote.inputMicroUsdPer1m || managed.outputMicroUsdPer1m !== quote.outputMicroUsdPer1m || managed.capDailyUsd !== Number(this.config.perOfferCapUsd); if (this.config.live && priceChanged) { await this.client.updateOffer(currentState.offerId, { inputUsdPer1m: quote.inputUsdPer1m, outputUsdPer1m: quote.outputUsdPer1m, dailyCapUsd: Number(this.config.perOfferCapUsd), idempotencyKey: this.mutationId(), }); } if (this.config.live && managed.status === "inactive") { await this.client.resumeOffer(currentState.offerId, this.mutationId()); } const activeState: SurplusControllerState = { ...currentState, intent: nextIntent, highestTrades24h: ownBookOffer?.trades24h ?? currentState.highestTrades24h, }; await this.stateStore.save(activeState); this.state = activeState; const earnings = await this.client.getEarnings(); this.markSuccess("active", allowance, { intent: nextIntent, offerId: currentState.offerId, competitorId: quote.competitorId, totalEarnedMicroUsd: earnings.totalEarnedMicroUsd, }); } private async finishStopping(): Promise { if (this.state?.phase !== "stopping") return; const stopping = this.state; const before = await this.client.listAllOffers(); const active = before.filter((offer) => offer.status === "active"); for (const offer of active) { const key = offer.id === stopping.offerId ? stopping.pauseIdempotencyKey : this.mutationId(); await this.client.pauseOffer(offer.id, key); } const after = await this.client.listAllOffers(); if (after.some((offer) => offer.status === "active")) { throw new Error("Surplus proof stop could not confirm all offers inactive"); } const awaiting: SurplusControllerState = { version: 1, phase: "awaiting_settlement", offerId: stopping.offerId, intent: stopping.intent, tradeObservedAt: stopping.tradeObservedAt, }; await this.stateStore.save(awaiting); this.state = awaiting; await this.awaitSettlement(); } private async awaitSettlement(): Promise { if (this.state?.phase !== "awaiting_settlement") return; const awaiting = this.state; const offers = await this.client.listAllOffers(); const active = offers.filter((offer) => offer.status === "active"); if (active.length > 0) { await this.pauseOffers(active); this.markSuccess("suspended", null, null); return; } const earnings = await this.client.getEarnings(); const sale = this.findSettledSale(earnings, awaiting); if (!sale) { this.markSuccess("awaiting_settlement", null, { intent: awaiting.intent, offerId: awaiting.offerId, competitorId: null, totalEarnedMicroUsd: earnings.totalEarnedMicroUsd, }); return; } const completed: SurplusControllerState = { version: 1, phase: "completed", offerId: awaiting.offerId, model: awaiting.intent.model, providerModelId: awaiting.intent.providerModelId, tradeObservedAt: awaiting.tradeObservedAt, completedAt: new Date(this.now()).toISOString(), settlement: { offerId: sale.offerId, createdAt: sale.createdAt ?? awaiting.tradeObservedAt, sellerCostMicroUsd: sale.sellerCostMicroUsd, settlementStatus: sale.settlementStatus, }, }; await this.stateStore.save(completed); this.state = completed; this.markSuccess("completed", null, { intent: awaiting.intent, offerId: awaiting.offerId, competitorId: null, totalEarnedMicroUsd: earnings.totalEarnedMicroUsd, }); } private findSettledSale( earnings: SurplusEarnings, state: Extract, ): SurplusEarnings["recentSales"][number] | null { const tradeObservedAt = Date.parse(state.tradeObservedAt); return earnings.recentSales.find((sale) => { if ( !this.config.settledStatuses.includes( sale.settlementStatus.toLowerCase(), ) ) { return false; } if ( sale.offerId !== state.offerId || sale.createdAt === null || sale.model !== state.intent.model || sale.sellerCostMicroUsd <= 0 ) { return false; } return Date.parse(sale.createdAt) >= tradeObservedAt; }) ?? null; } private requireSelectedDiscovery( discovered: SurplusDiscoveredModel[], intent: SurplusOfferIntent, ): SurplusDiscoveredModel { const selected = discovered.find((model) => model.model === intent.model && model.providerModelId === intent.providerModelId ); if ( !selected || !selected.supported || selected.availabilityStatus !== "available" || selected.modelType !== "text" || selected.priceUnit !== "M" || selected.priceVariable || selected.inputUsdPer1m <= 0 || selected.outputUsdPer1m <= 0 ) { throw new Error(`Selected OpenRouter model is no longer safely sellable: ${intent.model}`); } return selected; } private assertAggregateCap(offers: SurplusOffer[]): void { let activeCap = 0n; for (const offer of offers) { if (offer.status !== "active") continue; if (offer.capDailyUsd === null) { throw new Error(`Active Surplus offer has no daily cap: ${offer.id}`); } const capMicroUsd = offer.capDailyUsd * 1_000_000; if (!Number.isSafeInteger(capMicroUsd)) { throw new Error(`Active Surplus offer cap has excess precision: ${offer.id}`); } activeCap += BigInt(capMicroUsd) * 1_000n; } const aggregateCap = parseUsdDecimal(this.config.aggregateCapUsd, "floor"); if (activeCap > aggregateCap) { throw new Error("Active Surplus offer caps exceed the aggregate cap"); } } private assertAllowance( allowance: OpenRouterKeyAllowance, exposureUsdNanos: bigint, ): void { const reserve = parseUsdDecimal(this.config.reserveUsd, "ceil"); const maxLimit = parseUsdDecimal(this.config.maxProviderLimitUsd, "floor"); if ( allowance.limitUsdNanos > maxLimit || allowance.remainingUsdNanos > allowance.limitUsdNanos ) { throw new Error("OpenRouter key limit exceeds the configured containment limit"); } if (allowance.remainingUsdNanos < reserve + exposureUsdNanos) { throw new Error("OpenRouter allowance cannot cover reserve threshold plus exposure"); } } private async pauseOffers(offers: SurplusOffer[]): Promise { if (!this.config.live) return; for (const offer of offers) { await this.client.pauseOffer(offer.id, this.mutationId()); } } private safeError(error: unknown): string { const detail = error instanceof Error ? error.message : String(error); return detail .replaceAll(this.config.sellerApiKey, "[redacted]") .replaceAll(this.config.providerApiKey, "[redacted]") .replace(/(?:si_seller_|sk-or-v1-)[A-Za-z0-9_-]+/g, "[redacted]") .slice(0, 500); } private markSuccess( phase: SurplusControllerStatus["phase"], allowance: OpenRouterKeyAllowance | null, details: { intent: SurplusOfferIntent; offerId: string | null; competitorId: string | null; totalEarnedMicroUsd: number | null; } | null, ): void { const successAt = new Date(this.now()).toISOString(); const state = this.state; const stateModel = state && "intent" in state ? state.intent.model : state?.phase === "completed" ? state.model : null; const stateProviderModel = state && "intent" in state ? state.intent.providerModelId : state?.phase === "completed" ? state.providerModelId : null; const stateOfferId = state && "offerId" in state ? state.offerId : null; this.status = { ...this.status, ok: true, phase, model: details?.intent.model ?? stateModel, providerModelId: details?.intent.providerModelId ?? stateProviderModel, offerId: details?.offerId ?? stateOfferId, inputUsdPer1m: details ? formatMicroUsd(details.intent.inputMicroUsdPer1m) : this.status.inputUsdPer1m, outputUsdPer1m: details ? formatMicroUsd(details.intent.outputMicroUsdPer1m) : this.status.outputUsdPer1m, competitorId: details?.competitorId ?? null, remainingAllowanceUsd: allowance ? formatUsdNanos(allowance.remainingUsdNanos, 6) : this.status.remainingAllowanceUsd, totalEarnedUsd: details?.totalEarnedMicroUsd === null || details === null ? this.status.totalEarnedUsd : formatMicroUsd(details.totalEarnedMicroUsd), lastSuccessAt: successAt, lastError: null, }; this.log(`Surplus controller phase=${phase} model=${this.status.model ?? "none"}`); } } function normalizeUrl(value: string): string { return value.replace(/\/+$/, "").toLowerCase(); }