Some checks failed
deploy / deploy (push) Failing after 43s
Proof: Pair-native trade semantics and multi-asset outcome truth; strategy, request preflight, outcome attribution, valuation visibility, dashboard labels, alerts, and ops watch paths now use DB pair/asset/route metadata with nBTC/EURe compatibility and nBTC/USDC regressions covered. Assumptions: Postgres asset, pair, strategy config, and price route rows remain canonical; supported reference adapters remain BTC/EUR and BTC/USDC; deployment is push-driven through the existing Forgejo workflow. Still fake: Arbitrary multi-hop valuation, new execution venues, fee-complete realized PnL, venue-native terminal fill ingestion, and autonomous optimization remain unbuilt.
292 lines
9 KiB
JavaScript
292 lines
9 KiB
JavaScript
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,
|
|
};
|
|
const USDC = {
|
|
assetId: 'nep141:usdc.omft.near',
|
|
symbol: 'USDC',
|
|
decimals: 6,
|
|
};
|
|
|
|
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'],
|
|
);
|
|
});
|
|
|
|
test('BTC/USDC maker command completes from pair-native expected deltas', () => {
|
|
const quoteId = 'quote-usdc-settled';
|
|
const [outcome] = deriveQuoteOutcomeRecords({
|
|
submissions: [submittedResult(quoteId)],
|
|
commands: [{
|
|
observed_at: '2026-04-02T18:13:29.000Z',
|
|
payload: {
|
|
quote_id: quoteId,
|
|
command_id: `cmd-${quoteId}`,
|
|
decision_id: `decision-${quoteId}`,
|
|
pair: `${BTC.assetId}->${USDC.assetId}`,
|
|
direction: 'base_to_quote',
|
|
request_kind: 'exact_in',
|
|
asset_in: BTC.assetId,
|
|
asset_out: USDC.assetId,
|
|
amount_in: '10000',
|
|
quote_output: { amount_out: '7960800' },
|
|
expected_inventory_delta_units: {
|
|
[BTC.assetId]: '10000',
|
|
[USDC.assetId]: '-7960800',
|
|
},
|
|
notional: '8',
|
|
notional_asset_id: USDC.assetId,
|
|
notional_symbol: 'USDC',
|
|
min_deadline_ms: 60000,
|
|
},
|
|
}],
|
|
inventorySnapshots: [
|
|
inventorySnapshot('2026-04-02T18:13:00.000Z', {
|
|
[BTC.assetId]: '0',
|
|
[USDC.assetId]: '10000000',
|
|
[EURE.assetId]: '1',
|
|
}),
|
|
inventorySnapshot('2026-04-02T18:13:33.000Z', {
|
|
[BTC.assetId]: '10000',
|
|
[USDC.assetId]: '2039200',
|
|
[EURE.assetId]: '1',
|
|
}),
|
|
],
|
|
btcAsset: BTC,
|
|
eureAsset: EURE,
|
|
now: '2026-04-02T18:14:00.000Z',
|
|
});
|
|
|
|
assert.equal(outcome.outcome_status, 'completed');
|
|
assert.equal(outcome.payload.notional_symbol, 'USDC');
|
|
assert.equal(outcome.attributed_inventory_delta.delta_units[USDC.assetId], '-7960800');
|
|
});
|
|
|
|
test('unrelated active-asset movement does not create false maker completion', () => {
|
|
const quoteId = 'quote-usdc-extra-move';
|
|
const [outcome] = deriveQuoteOutcomeRecords({
|
|
submissions: [submittedResult(quoteId)],
|
|
commands: [{
|
|
observed_at: '2026-04-02T18:13:29.000Z',
|
|
payload: {
|
|
quote_id: quoteId,
|
|
command_id: `cmd-${quoteId}`,
|
|
decision_id: `decision-${quoteId}`,
|
|
pair: `${BTC.assetId}->${USDC.assetId}`,
|
|
request_kind: 'exact_in',
|
|
asset_in: BTC.assetId,
|
|
asset_out: USDC.assetId,
|
|
amount_in: '10000',
|
|
quote_output: { amount_out: '7960800' },
|
|
expected_inventory_delta_units: {
|
|
[BTC.assetId]: '10000',
|
|
[USDC.assetId]: '-7960800',
|
|
},
|
|
min_deadline_ms: 60000,
|
|
},
|
|
}],
|
|
inventorySnapshots: [
|
|
inventorySnapshot('2026-04-02T18:13:00.000Z', {
|
|
[BTC.assetId]: '0',
|
|
[USDC.assetId]: '10000000',
|
|
[EURE.assetId]: '1',
|
|
}),
|
|
inventorySnapshot('2026-04-02T18:13:33.000Z', {
|
|
[BTC.assetId]: '10000',
|
|
[USDC.assetId]: '2039200',
|
|
[EURE.assetId]: '2',
|
|
}),
|
|
],
|
|
btcAsset: BTC,
|
|
eureAsset: EURE,
|
|
now: '2026-04-02T18:14:00.000Z',
|
|
});
|
|
|
|
assert.equal(outcome.outcome_status, 'submitted');
|
|
assert.equal(outcome.attribution_status, 'unattributed');
|
|
});
|