kog-fee-gate-tests / tree / test/fee-gate.test.ts · raw (this view has old GitHub links rewritten for the mirror; raw is byte-exact)
/**
 * SEAT5: the listing and the bid are refused without the KOG fee. Every request goes through the harness from
 * loadHarness() (kit lax-registry-harness version 1), so the same file runs against Kognai's production gate or a
 * broken one:  LAX_HARNESS=/path/to/harness.ts npm test
 * Each test checks what was written to the stores, not only the status.
 */
import test from 'node:test';
import assert from 'node:assert/strict';
import { loadHarness } from '../src/load.ts';

const { createHarness } = await loadHarness();
type H = ReturnType<typeof createHarness>;

const listings = (h: H) => [...h.stores.store.agents.values()].filter((r: any) => r.origin === 'outside');
const bidsFor = (h: H, jobId: string) => [...h.stores.bidStore.bids.values()].filter((b: any) => b.job_id === jobId);

/** POST /offers for agent i: first the 402 quote, then the request with the given fee (or a valid one). */
async function offerWith(h: H, i: number, pay?: (q: any) => string | undefined, body?: Record<string, unknown>) {
  const a = h.agents[i];
  const first = await h.handle(h.offerRequest({ agent: a, body }));
  assert.equal(first.status, 402, 'no fee: 402');
  const quote = await h.quoteOf(first);
  const fee = pay ? pay(quote) : h.payKog({ quote });
  return { quote, fee, res: await h.handle(h.offerRequest({ agent: a, body, quote, fee })) };
}
async function bidWith(h: H, i: number, jobId: string, offerId: string, pay?: (q: any) => string | undefined) {
  const a = h.agents[i];
  const first = await h.handle(await h.bidRequest({ agent: a, jobId, offerId }));
  assert.equal(first.status, 402, 'no fee: 402');
  const quote = await h.quoteOf(first);
  const fee = pay ? pay(quote) : h.payKog({ quote });
  return { quote, fee, res: await h.handle(await h.bidRequest({ agent: a, jobId, offerId, quote, fee })) };
}

// ── POST /offers ────────────────────────────────────────────────────────────────────────────────────────────────
test('A1 POST /offers without a KOG fee is refused with 402 and a quote, and nothing is listed', async () => {
  const h = createHarness();
  const res = await h.handle(h.offerRequest({ agent: h.agents[0] }));
  assert.equal(res.status, 402);
  const q = await h.quoteOf(res);
  assert.equal(q.route, 'POST /offers'); assert.equal(q.amount, h.kog.fees.offer); assert.equal(q.mint, h.kog.mint); assert.equal(q.payee, h.kog.payee);
  assert.ok(Date.parse(q.expires_at) > h.clock.now);
  assert.equal(listings(h).length, 0);
  // a quote alone, with no fee, is still refused
  const again = await h.handle(h.offerRequest({ agent: h.agents[0], quote: q }));
  assert.equal(again.status, 402); assert.equal(listings(h).length, 0);
});

test('A2 POST /offers with a short fee is refused (one atomic unit short, and half), and nothing is listed', async () => {
  for (const cut of [1n, BigInt(createHarness().kog.fees.offer) / 2n]) {
    const h = createHarness();
    const { res } = await offerWith(h, 0, (q) => h.payKog({ quote: q, amount: String(BigInt(q.amount) - cut) }));
    assert.equal(res.status, 402, `short by ${cut}`);
    assert.match(((await res.json()) as any).error, /short|refused/i);
    assert.equal(listings(h).length, 0);
  }
});

test('A2 POST /offers refuses a fee on another mint, to another payee, failed, expired or never paid', async () => {
  const cases: Array<[string, (h: H, q: any) => string]> = [
    ['wrong mint', (h, q) => h.payKog({ quote: q, mint: 'OtherMint111111111111111111111111111111111' })],
    ['wrong payee', (h, q) => h.payKog({ quote: q, payee: 'OtherPayee11111111111111111111111111111111' })],
    ['failed transaction', (h, q) => h.payKog({ quote: q, ok: false })],
    ['not on chain', () => '5'.repeat(88)],
  ];
  for (const [why, pay] of cases) {
    const h = createHarness();
    const { res } = await offerWith(h, 0, (q) => pay(h, q));
    assert.equal(res.status, 402, why); assert.equal(listings(h).length, 0, why);
  }
  const h = createHarness();
  const first = await h.handle(h.offerRequest({ agent: h.agents[0] }));
  const q = await h.quoteOf(first); const fee = h.payKog({ quote: q });
  h.clock.now += 11 * 60_000; // the quote lasts 10 minutes
  const late = await h.handle(h.offerRequest({ agent: h.agents[0], quote: q, fee }));
  assert.equal(late.status, 402, 'expired quote'); assert.equal(listings(h).length, 0);
});

test('A3 POST /offers with a reused fee is refused with 409, and only the first listing exists', async () => {
  const h = createHarness();
  const { res, fee } = await offerWith(h, 0);
  assert.equal(res.status, 201);
  assert.equal(listings(h).length, 1);
  const q2 = await h.quoteOf(await h.handle(h.offerRequest({ agent: h.agents[1] })));
  const reuse = await h.handle(h.offerRequest({ agent: h.agents[1], quote: q2, fee }));
  assert.equal(reuse.status, 409);
  assert.equal(listings(h).length, 1, 'the reused fee wrote nothing');
  assert.equal((listings(h)[0] as any).owner_address.toLowerCase(), h.agents[0].address.toLowerCase());
});

test('A4 POST /offers with a valid fee lists the agent once; a fee overpaid also counts', async () => {
  const h = createHarness();
  const { res } = await offerWith(h, 0);
  assert.equal(res.status, 201);
  const ls = listings(h);
  assert.equal(ls.length, 1);
  assert.equal((ls[0] as any).owner_address.toLowerCase(), h.agents[0].address.toLowerCase());
  assert.equal((ls[0] as any).agent_did, h.agents[0].did);
  const h2 = createHarness();
  const over = await offerWith(h2, 1, (q) => h2.payKog({ quote: q, amount: String(BigInt(q.amount) + 1n) }));
  assert.equal(over.res.status, 201); assert.equal(listings(h2).length, 1);
});

test('A4 a fee on an offer the registry refuses stays usable for a fixed offer', async () => {
  const h = createHarness();
  const bad = h.offer(h.agents[0], { constitutional_constraints: ['Solidarity Oath'] });
  const { res, quote, fee } = await offerWith(h, 0, undefined, bad);
  assert.ok(res.status >= 400 && res.status < 500 && res.status !== 402 && res.status !== 409, `registry refusal, got ${res.status}`);
  assert.equal(listings(h).length, 0);
  const fixed = await h.handle(h.offerRequest({ agent: h.agents[0], quote, fee }));
  assert.equal(fixed.status, 201); assert.equal(listings(h).length, 1);
});

// ── POST /jobs/<id>/bids ────────────────────────────────────────────────────────────────────────────────────────
test('A1 POST /jobs/<id>/bids without a KOG fee is refused with 402 and a bid quote, and no bid is stored', async () => {
  const h = createHarness(); const jobId = h.seedJob(); const offerId = h.seedListing(h.agents[1]);
  const res = await h.handle(await h.bidRequest({ agent: h.agents[1], jobId, offerId }));
  assert.equal(res.status, 402);
  const q = await h.quoteOf(res);
  assert.equal(q.route, `POST /jobs/${jobId}/bids`); assert.equal(q.amount, h.kog.fees.bid);
  assert.equal(bidsFor(h, jobId).length, 0);
});

test('A2 POST /jobs/<id>/bids with a short fee is refused, and no bid is stored', async () => {
  const h = createHarness(); const jobId = h.seedJob(); const offerId = h.seedListing(h.agents[1]);
  const { res } = await bidWith(h, 1, jobId, offerId, (q) => h.payKog({ quote: q, amount: String(BigInt(q.amount) - 1n) }));
  assert.equal(res.status, 402); assert.equal(bidsFor(h, jobId).length, 0);
  // the listing fee is larger than the bid fee: paying the bid amount on an offer quote is short
  const { res: r2 } = await offerWith(h, 2, (q) => h.payKog({ quote: q, amount: h.kog.fees.bid }));
  assert.equal(r2.status, 402);
});

test('A2 a bid quote cannot pay for another job, and an offer quote cannot pay for a bid', async () => {
  const h = createHarness(); const j1 = h.seedJob(); const j2 = h.seedJob(); const offerId = h.seedListing(h.agents[1]);
  const q1 = await h.quoteOf(await h.handle(await h.bidRequest({ agent: h.agents[1], jobId: j1, offerId })));
  const fee = h.payKog({ quote: q1 });
  const cross = await h.handle(await h.bidRequest({ agent: h.agents[1], jobId: j2, offerId, quote: q1, fee }));
  assert.equal(cross.status, 402); assert.equal(bidsFor(h, j2).length, 0);
  const oq = await h.quoteOf(await h.handle(h.offerRequest({ agent: h.agents[0] })));
  const ofee = h.payKog({ quote: oq });
  const r = await h.handle(await h.bidRequest({ agent: h.agents[1], jobId: j1, offerId, quote: oq, fee: ofee }));
  assert.equal(r.status, 402); assert.equal(bidsFor(h, j1).length, 0);
});

test('A3 POST /jobs/<id>/bids with a reused fee is refused with 409: on another job and on another route', async () => {
  const h = createHarness(); const j1 = h.seedJob(); const j2 = h.seedJob(); const offerId = h.seedListing(h.agents[1]);
  const { res, fee } = await bidWith(h, 1, j1, offerId);
  assert.equal(res.status, 201); assert.equal(bidsFor(h, j1).length, 1);
  const q2 = await h.quoteOf(await h.handle(await h.bidRequest({ agent: h.agents[1], jobId: j2, offerId })));
  const reuse = await h.handle(await h.bidRequest({ agent: h.agents[1], jobId: j2, offerId, quote: q2, fee }));
  assert.equal(reuse.status, 409); assert.equal(bidsFor(h, j2).length, 0);
  const oq = await h.quoteOf(await h.handle(h.offerRequest({ agent: h.agents[2] })));
  const asOffer = await h.handle(h.offerRequest({ agent: h.agents[2], quote: oq, fee }));
  assert.equal(asOffer.status, 409); assert.equal(listings(h).length, 1, 'only the seeded listing');
});

test('A4 POST /jobs/<id>/bids with a valid fee stores exactly one bid for the listing', async () => {
  const h = createHarness(); const jobId = h.seedJob(); const offerId = h.seedListing(h.agents[1]);
  const { res } = await bidWith(h, 1, jobId, offerId);
  assert.equal(res.status, 201);
  const bs = bidsFor(h, jobId);
  assert.equal(bs.length, 1);
  assert.equal((bs[0] as any).offer_id ?? (bs[0] as any).listing_id, offerId);
});

test('A4 both routes are gated: every request with no fee on either route answers 402', async () => {
  const h = createHarness(); const jobId = h.seedJob(); const offerId = h.seedListing(h.agents[0]);
  assert.equal((await h.handle(h.offerRequest({ agent: h.agents[2] }))).status, 402);
  assert.equal((await h.handle(await h.bidRequest({ agent: h.agents[0], jobId, offerId }))).status, 402);
  assert.equal(listings(h).length, 1); assert.equal(bidsFor(h, jobId).length, 0);
});

agentgate-source: code mirror on Cloudflare Pages. All repos