import test from 'node:test'; import assert from 'node:assert/strict'; import { deriveQuoteOutcomeRecords } from '../src/core/quote-outcomes.mjs'; const BTC = { assetId: 'nep141:btc.omft.near', symbol: 'BTC', decimals: 8, }; const EURE = { assetId: 'nep141:eure.omft.near', symbol: 'EURe', decimals: 18, }; function submittedResult(quoteId, observedAt = '2026-04-02T18:13:30.000Z') { return { observed_at: observedAt, payload: { quote_id: quoteId, command_id: `cmd-${quoteId}`, decision_id: `decision-${quoteId}`, status: 'submitted', result_code: 'quote_response_ok', }, }; } function exactOutCommand(quoteId) { return { observed_at: '2026-04-02T18:13:29.000Z', payload: { quote_id: quoteId, command_id: `cmd-${quoteId}`, decision_id: `decision-${quoteId}`, pair: `${BTC.assetId}->${EURE.assetId}`, direction: 'eure_to_btc', request_kind: 'exact_out', asset_in: BTC.assetId, asset_out: EURE.assetId, amount_out: '21000021200021200022', quote_output: { amount_in: '37014', }, min_deadline_ms: 60000, }, }; } function inventorySnapshot(observedAt, spendable) { return { observed_at: observedAt, payload: { inventory_id: `inventory-${observedAt}`, synced_at: observedAt, spendable, }, }; } test('quote outcome completes only when exact submitted quote delta is observed', () => { const [outcome] = deriveQuoteOutcomeRecords({ submissions: [submittedResult('quote-settled')], commands: [exactOutCommand('quote-settled')], inventorySnapshots: [ inventorySnapshot('2026-04-02T18:13:00.000Z', { [BTC.assetId]: '0', [EURE.assetId]: '100000000000000000000', }), inventorySnapshot('2026-04-02T18:13:33.000Z', { [BTC.assetId]: '37014', [EURE.assetId]: '78999978799978799978', }), ], btcAsset: BTC, eureAsset: EURE, now: '2026-04-02T18:14:00.000Z', }); assert.equal(outcome.outcome_status, 'completed'); assert.equal(outcome.attribution_status, 'heuristic_match'); assert.equal(outcome.attributed_inventory_delta.delta_units[BTC.assetId], '37014'); assert.equal(outcome.attributed_inventory_delta.delta_units[EURE.assetId], '-21000021200021200022'); }); test('submitted quote without settlement stays submitted before the deadline window expires', () => { const [outcome] = deriveQuoteOutcomeRecords({ submissions: [submittedResult('quote-submitted', '2026-04-02T18:13:30.000Z')], commands: [exactOutCommand('quote-submitted')], inventorySnapshots: [ inventorySnapshot('2026-04-02T18:13:00.000Z', { [BTC.assetId]: '0', [EURE.assetId]: '100000000000000000000', }), ], btcAsset: BTC, eureAsset: EURE, now: '2026-04-02T18:13:45.000Z', }); assert.equal(outcome.outcome_status, 'submitted'); assert.equal(outcome.attribution_status, 'unattributed'); assert.equal(outcome.attributed_inventory_delta, null); }); test('submitted quote without settlement becomes not filled only after deadline and later inventory evidence', () => { const [outcome] = deriveQuoteOutcomeRecords({ submissions: [submittedResult('quote-not-filled', '2026-04-02T18:13:30.000Z')], commands: [exactOutCommand('quote-not-filled')], inventorySnapshots: [ inventorySnapshot('2026-04-02T18:13:00.000Z', { [BTC.assetId]: '0', [EURE.assetId]: '100000000000000000000', }), inventorySnapshot('2026-04-02T18:15:40.000Z', { [BTC.assetId]: '0', [EURE.assetId]: '100000000000000000000', }), ], btcAsset: BTC, eureAsset: EURE, now: '2026-04-02T18:15:40.000Z', }); assert.equal(outcome.outcome_status, 'not_filled'); assert.equal(outcome.outcome_reason, 'deadline_elapsed_without_settlement'); assert.equal(outcome.outcome_observed_at, '2026-04-02T18:15:40.000Z'); assert.equal(outcome.payload.evidence.latest_inventory_observed_at, '2026-04-02T18:15:40.000Z'); assert.equal(outcome.attributed_inventory_delta, null); }); test('older unrelated inventory movement does not block later no-fill expiry', () => { const [outcome] = deriveQuoteOutcomeRecords({ submissions: [submittedResult('quote-after-old-move', '2026-04-02T18:20:00.000Z')], commands: [exactOutCommand('quote-after-old-move')], inventorySnapshots: [ inventorySnapshot('2026-04-02T18:13:00.000Z', { [BTC.assetId]: '0', [EURE.assetId]: '100000000000000000000', }), inventorySnapshot('2026-04-02T18:13:33.000Z', { [BTC.assetId]: '1', [EURE.assetId]: '99999999999999999999', }), inventorySnapshot('2026-04-02T18:22:00.000Z', { [BTC.assetId]: '1', [EURE.assetId]: '99999999999999999999', }), ], btcAsset: BTC, eureAsset: EURE, now: '2026-04-02T18:22:00.000Z', }); assert.equal(outcome.outcome_status, 'not_filled'); assert.equal(outcome.outcome_reason, 'deadline_elapsed_without_settlement'); assert.equal(outcome.payload.evidence.latest_inventory_observed_at, '2026-04-02T18:22:00.000Z'); }); test('ambiguous inventory movement is not counted as completed settlement', () => { const outcomes = deriveQuoteOutcomeRecords({ submissions: [ submittedResult('quote-a', '2026-04-02T18:13:30.000Z'), submittedResult('quote-b', '2026-04-02T18:13:31.000Z'), ], commands: [ exactOutCommand('quote-a'), exactOutCommand('quote-b'), ], inventorySnapshots: [ inventorySnapshot('2026-04-02T18:13:00.000Z', { [BTC.assetId]: '0', [EURE.assetId]: '100000000000000000000', }), inventorySnapshot('2026-04-02T18:13:33.000Z', { [BTC.assetId]: '37014', [EURE.assetId]: '78999978799978799978', }), ], btcAsset: BTC, eureAsset: EURE, now: '2026-04-02T18:14:00.000Z', }); assert.deepEqual( outcomes.map((entry) => entry.outcome_status), ['awaiting_outcome', 'awaiting_outcome'], ); assert.deepEqual( outcomes.map((entry) => entry.attribution_status), ['ambiguous', 'ambiguous'], ); });