fix: keep Surplus seller active after proof

This commit is contained in:
david
2026-08-28 09:25:02 +02:00
parent 3393748972
commit 41820b11bb
4 changed files with 34 additions and 7 deletions

View File

@@ -155,7 +155,7 @@ SURPLUS_UNDERCUT_BPS=10
SURPLUS_MAX_CANDIDATE_ORDER_BOOKS=10 SURPLUS_MAX_CANDIDATE_ORDER_BOOKS=10
SURPLUS_REPRICE_INTERVAL_MS=300000 SURPLUS_REPRICE_INTERVAL_MS=300000
SURPLUS_REQUEST_TIMEOUT_MS=120000 SURPLUS_REQUEST_TIMEOUT_MS=120000
SURPLUS_STOP_AFTER_SETTLED_REQUESTS=1 # 0 keeps selling. 1 pauses after the first trade or one offer-cap of spend.
# Leave empty until a live earnings record establishes the terminal status. SURPLUS_STOP_AFTER_SETTLED_REQUESTS=0
SURPLUS_SETTLED_STATUSES= SURPLUS_SETTLED_STATUSES=confirmed
SURPLUS_STATE_PATH=/var/lib/surplus-manager/state.json SURPLUS_STATE_PATH=/var/lib/surplus-manager/state.json

View File

@@ -120,9 +120,9 @@ export function loadSurplusManagerConfig(
300_000, 300_000,
), ),
stopAfterTrades: boundedInteger( stopAfterTrades: boundedInteger(
env.SURPLUS_STOP_AFTER_SETTLED_REQUESTS ?? "1", env.SURPLUS_STOP_AFTER_SETTLED_REQUESTS ?? "0",
"SURPLUS_STOP_AFTER_SETTLED_REQUESTS", "SURPLUS_STOP_AFTER_SETTLED_REQUESTS",
1, 0,
1, 1,
), ),
settledStatuses: statusList( settledStatuses: statusList(

View File

@@ -453,7 +453,7 @@ export class SurplusSellerController {
? baselineAllowance - allowance.remainingUsdNanos ? baselineAllowance - allowance.remainingUsdNanos
: 0n; : 0n;
const spendCap = parseUsdDecimal(this.config.perOfferCapUsd, "ceil"); const spendCap = parseUsdDecimal(this.config.perOfferCapUsd, "ceil");
if (providerSpend >= spendCap) { if (this.config.stopAfterTrades > 0 && providerSpend >= spendCap) {
const stopping: SurplusControllerState = { const stopping: SurplusControllerState = {
version: 1, version: 1,
phase: "stopping", phase: "stopping",
@@ -476,6 +476,7 @@ export class SurplusSellerController {
const book = await this.client.getOrderBook(currentState.intent.model); const book = await this.client.getOrderBook(currentState.intent.model);
const ownBookOffer = book.offers.find((offer) => offer.id === currentState.offerId); const ownBookOffer = book.offers.find((offer) => offer.id === currentState.offerId);
if ( if (
this.config.stopAfterTrades > 0 &&
ownBookOffer && ownBookOffer &&
ownBookOffer.trades24h >= ownBookOffer.trades24h >=
currentState.highestTrades24h + this.config.stopAfterTrades currentState.highestTrades24h + this.config.stopAfterTrades

View File

@@ -211,10 +211,11 @@ function controller(
allowance: { readAllowance(): Promise<OpenRouterKeyAllowance> } = { allowance: { readAllowance(): Promise<OpenRouterKeyAllowance> } = {
readAllowance: async () => ALLOWANCE, readAllowance: async () => ALLOWANCE,
}, },
managerConfig: SurplusManagerConfig = config(),
): SurplusSellerController { ): SurplusSellerController {
let mutation = 0; let mutation = 0;
return new SurplusSellerController({ return new SurplusSellerController({
config: config(), config: managerConfig,
client, client,
allowance, allowance,
stateStore: store, stateStore: store,
@@ -283,6 +284,31 @@ describe("SurplusSellerController", () => {
expect(store.state.phase).toBe("awaiting_settlement"); expect(store.state.phase).toBe("awaiting_settlement");
}); });
it("keeps selling in continuous mode after trades and provider spend", async () => {
const client = new FakeSurplusClient();
const store = new MemoryStateStore();
let remaining = 20_000_000_000n;
const activeController = controller(
client,
store,
{
readAllowance: async () => ({
...ALLOWANCE,
remainingUsdNanos: remaining,
}),
},
{ ...config(), stopAfterTrades: 0 },
);
await activeController.runOnce();
client.trades24h = 1;
remaining = 18_700_000_000n;
await activeController.runOnce();
expect(client.offer?.status).toBe("active");
expect(store.state.phase).toBe("active");
});
it("adopts and resumes an inactive offer after an ambiguous create", async () => { it("adopts and resumes an inactive offer after an ambiguous create", async () => {
const client = new FakeSurplusClient(); const client = new FakeSurplusClient();
client.offer = { client.offer = {