All checks were successful
deploy / deploy (push) Successful in 48s
Proof: Maker competitiveness now persists edge_bps into quote outcome payloads, groups summaries by edge, and shows the edge in the operator dashboard so filled versus not-filled responses can be compared against configured strategy edge. Assumptions: Edge bps remains DB-owned pair strategy config; this change is observational and does not change live pair enablement, notional limits, inventory checks, response policy, or relay submission behavior. Still fake: Venue-native terminal fill ids and fee-complete realized PnL remain unavailable; relay acceptance is still only submission evidence.
193 lines
6.9 KiB
JavaScript
193 lines
6.9 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
|
|
import {
|
|
buildInitialMakerTiming,
|
|
extendMakerTiming,
|
|
quoteAgeMsAt,
|
|
} from '../src/core/maker-timing.mjs';
|
|
import { buildMakerCompetitivenessSummary } from '../src/core/maker-competitiveness.mjs';
|
|
import { classifyRelaySubmissionFailure } from '../src/core/relay-failure-classification.mjs';
|
|
|
|
test('maker timing computes waterfall fields and marks clock skew unavailable', () => {
|
|
const initial = buildInitialMakerTiming({
|
|
quoteReceivedAt: '2026-05-18T10:00:00.000Z',
|
|
quoteNormalizedAt: '2026-05-18T10:00:00.010Z',
|
|
quotePublishedAt: '2026-05-18T10:00:00.020Z',
|
|
});
|
|
const timing = extendMakerTiming(initial, {
|
|
strategy_received_at: '2026-05-18T10:00:00.030Z',
|
|
strategy_decided_at: '2026-05-18T10:00:00.040Z',
|
|
command_published_at: '2026-05-18T10:00:00.050Z',
|
|
executor_received_at: '2026-05-18T10:00:00.075Z',
|
|
relay_result_at: '2026-05-18T10:00:00.140Z',
|
|
outcome_observed_at: '2026-05-18T10:00:02.000Z',
|
|
});
|
|
|
|
assert.equal(timing.quote_to_decision_ms, 40);
|
|
assert.equal(timing.decision_to_command_ms, 10);
|
|
assert.equal(timing.command_to_executor_ms, 25);
|
|
assert.equal(timing.executor_to_relay_result_ms, 65);
|
|
assert.equal(timing.quote_to_relay_result_ms, 140);
|
|
assert.equal(timing.quote_to_outcome_ms, 2000);
|
|
assert.equal(quoteAgeMsAt(timing, '2026-05-18T10:00:00.050Z'), 50);
|
|
|
|
const skewed = extendMakerTiming(initial, {
|
|
strategy_decided_at: '2026-05-18T09:59:59.999Z',
|
|
});
|
|
assert.equal(skewed.quote_to_decision_ms, null);
|
|
assert.equal(skewed.unavailable_reasons.quote_to_decision_ms, 'clock_skew_or_negative_duration');
|
|
});
|
|
|
|
test('relay submission failure classifier preserves specific already-finished category', () => {
|
|
assert.equal(
|
|
classifyRelaySubmissionFailure(new Error('quote not found or already finished')),
|
|
'quote_not_found_or_finished',
|
|
);
|
|
assert.equal(
|
|
classifyRelaySubmissionFailure({ error_message: 'quote not found or already finished' }),
|
|
'quote_not_found_or_finished',
|
|
);
|
|
assert.equal(
|
|
classifyRelaySubmissionFailure(new Error('quote_response timed out')),
|
|
'relay_timeout',
|
|
);
|
|
assert.equal(
|
|
classifyRelaySubmissionFailure(new Error('Socket not connected')),
|
|
'relay_disconnected',
|
|
);
|
|
assert.equal(
|
|
classifyRelaySubmissionFailure(new Error('current_salt unavailable')),
|
|
'salt_unavailable',
|
|
);
|
|
});
|
|
|
|
test('maker competitiveness aggregates pair, direction, request kind, result, failure, age, notional, and outcome', () => {
|
|
const nbtc = 'nep141:nbtc.bridge.near';
|
|
const eure = 'nep141:eure.omft.near';
|
|
const usdc = 'nep141:eth-0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.omft.near';
|
|
const baseTiming = buildInitialMakerTiming({
|
|
quoteReceivedAt: '2026-05-18T10:00:00.000Z',
|
|
});
|
|
const summary = buildMakerCompetitivenessSummary({
|
|
generatedAt: '2026-05-18T10:01:00.000Z',
|
|
lifecycleRows: [
|
|
{
|
|
quote_id: 'quote-eure-ok',
|
|
pair: `${nbtc}->${eure}`,
|
|
direction: 'base_to_quote',
|
|
request_kind: 'exact_in',
|
|
edge_bps: '49',
|
|
notional: '5',
|
|
notional_symbol: 'EURe',
|
|
outcome_status: 'submitted',
|
|
execution_result_at: '2026-05-18T10:00:00.080Z',
|
|
maker_timing: extendMakerTiming(baseTiming, {
|
|
strategy_decided_at: '2026-05-18T10:00:00.010Z',
|
|
command_published_at: '2026-05-18T10:00:00.020Z',
|
|
executor_received_at: '2026-05-18T10:00:00.030Z',
|
|
relay_result_at: '2026-05-18T10:00:00.080Z',
|
|
}),
|
|
execution: {
|
|
status: 'submitted',
|
|
result_code: 'quote_response_ok',
|
|
timing: { current_salt_source: 'cache' },
|
|
},
|
|
},
|
|
{
|
|
quote_id: 'quote-usdc-failed',
|
|
pair: `${nbtc}->${usdc}`,
|
|
direction: 'base_to_quote',
|
|
request_kind: 'exact_in',
|
|
edge_bps: '20',
|
|
notional: '8',
|
|
notional_symbol: 'USDC',
|
|
execution_result_at: '2026-05-18T10:00:00.400Z',
|
|
maker_timing: extendMakerTiming(baseTiming, {
|
|
strategy_decided_at: '2026-05-18T10:00:00.100Z',
|
|
command_published_at: '2026-05-18T10:00:00.150Z',
|
|
executor_received_at: '2026-05-18T10:00:00.250Z',
|
|
relay_result_at: '2026-05-18T10:00:00.400Z',
|
|
}),
|
|
execution: {
|
|
status: 'failed',
|
|
result_code: 'submission_failed',
|
|
failure_category: 'quote_not_found_or_finished',
|
|
error_message: 'quote not found or already finished',
|
|
timing: { current_salt_source: 'cache' },
|
|
},
|
|
},
|
|
{
|
|
quote_id: 'quote-usdc-skip',
|
|
pair: `${nbtc}->${usdc}`,
|
|
direction: 'base_to_quote',
|
|
request_kind: 'exact_in',
|
|
edge_bps: '20',
|
|
notional: '12',
|
|
notional_symbol: 'USDC',
|
|
maker_timing: extendMakerTiming(baseTiming, {
|
|
strategy_decided_at: '2026-05-18T10:00:00.600Z',
|
|
}),
|
|
decision: {
|
|
decision: 'blocked',
|
|
decision_reason: 'maker_quote_too_old',
|
|
response_policy: {
|
|
measured_quote_age_ms: 600,
|
|
max_quote_age_ms: 250,
|
|
},
|
|
},
|
|
},
|
|
],
|
|
});
|
|
|
|
assert.equal(summary.total.count, 3);
|
|
assert.equal(summary.total.accepted_count, 1);
|
|
assert.equal(summary.total.relay_failed_count, 1);
|
|
assert.equal(summary.total.policy_skip_count, 1);
|
|
assert.equal(summary.total.quote_not_found_or_finished_count, 1);
|
|
assert.ok(summary.groups.some((group) => (
|
|
group.pair === `${nbtc}->${usdc}`
|
|
&& group.request_kind === 'exact_in'
|
|
&& group.edge_bps === '20'
|
|
&& group.result_code === 'submission_failed'
|
|
&& group.failure_category === 'quote_not_found_or_finished'
|
|
&& group.quote_age_bucket === '250-500ms'
|
|
&& group.notional_bucket === '5-25 USDC'
|
|
&& group.outcome_status === 'relay_failed'
|
|
)));
|
|
assert.ok(summary.age_buckets.some((bucket) => (
|
|
bucket.pair === `${nbtc}->${usdc}`
|
|
&& bucket.quote_age_bucket === '500-1000ms'
|
|
&& bucket.outcome_status === 'policy_skip'
|
|
)));
|
|
assert.equal(summary.latest_errors[0].error_message, 'quote not found or already finished');
|
|
assert.equal(summary.policy_skips[0].reason_code, 'maker_quote_too_old');
|
|
});
|
|
|
|
test('maker competitiveness keeps edge bps as a grouping dimension', () => {
|
|
const nbtc = 'nep141:nbtc.bridge.near';
|
|
const usdc = 'nep141:usdc.omft.near';
|
|
const base = {
|
|
pair: `${nbtc}->${usdc}`,
|
|
direction: 'base_to_quote',
|
|
request_kind: 'exact_in',
|
|
notional: '8',
|
|
notional_symbol: 'USDC',
|
|
outcome_status: 'not_filled',
|
|
execution: {
|
|
status: 'submitted',
|
|
result_code: 'quote_response_ok',
|
|
},
|
|
};
|
|
|
|
const summary = buildMakerCompetitivenessSummary({
|
|
lifecycleRows: [
|
|
{ ...base, quote_id: 'quote-edge-1', edge_bps: '1' },
|
|
{ ...base, quote_id: 'quote-edge-20', edge_bps: '20' },
|
|
],
|
|
});
|
|
|
|
const edgeGroups = summary.groups.filter((group) => group.pair === `${nbtc}->${usdc}`);
|
|
assert.equal(edgeGroups.length, 2);
|
|
assert.deepEqual(edgeGroups.map((group) => group.edge_bps).sort(), ['1', '20']);
|
|
});
|