unrip/test/intent-request-outcomes.test.mjs
philipp f34f27065a
All checks were successful
deploy / deploy (push) Successful in 33s
Implement NEAR Intents request creation flow
Proof: Adds repo-owned EURe-to-BTC request preflight, signing, gated live submission, durable request/result/outcome persistence, dashboard request lifecycle rows, and tests proving submitted/relay accepted are not completed without inventory movement.

Assumptions: The NEAR Intents solver relay quote, publish_intent, and get_status JSON-RPC methods accept signed raw_ed25519 token_diff payloads with quote_hashes; live validation remains bounded to 5 EUR per attempt, at most five attempts, and 200 bps slippage.

Still fake: Venue-native terminal fill linkage and fee-complete realized PnL are still unavailable; request completion is attributed from durable inventory deltas unless the venue later exposes a linked settlement id.
2026-04-12 18:43:40 +02:00

161 lines
4.9 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { deriveIntentRequestOutcomeRecords } from '../src/core/intent-request-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 preflight(overrides = {}) {
return {
request_id: 'request-1',
idempotency_key: 'idem-1',
state: 'draft',
reason_code: 'quote_available',
source_asset_id: EURE.assetId,
destination_asset_id: BTC.assetId,
source_amount_units: '5000000000000000000',
min_destination_amount_units: '9800',
quoted_destination_amount_units: '10000',
selected_quote: {
quote_hash: 'quote-hash-1',
amount_out: '10000',
},
min_deadline_ms: 60000,
deadline_at: '2026-04-12T10:01:00.000Z',
created_at: '2026-04-12T10:00:00.000Z',
...overrides,
};
}
function submission(overrides = {}) {
return {
request_id: 'request-1',
idempotency_key: 'idem-1',
submission_id: 'submission-1',
status: 'accepted_by_relay',
result_code: 'publish_intent_accepted',
quote_hash: 'quote-hash-1',
intent_hash: 'intent-hash-1',
destination_amount_units: '10000',
submitted_at: '2026-04-12T10:00:10.000Z',
relay_status: 'PENDING',
...overrides,
};
}
function outcomes({ preflights = [preflight()], submissions = [], inventorySnapshots = [], now = '2026-04-12T10:00:30.000Z' } = {}) {
return deriveIntentRequestOutcomeRecords({
preflights,
submissions,
inventorySnapshots,
btcAsset: BTC,
eureAsset: EURE,
now: Date.parse(now),
});
}
test('request submitted or relay accepted does not become completed without inventory delta', () => {
const [record] = outcomes({
submissions: [submission({ relay_status: 'SETTLED' })],
inventorySnapshots: [
{
observed_at: '2026-04-12T10:00:00.000Z',
spendable: {
[EURE.assetId]: '5000000000000000000',
[BTC.assetId]: '0',
},
},
{
observed_at: '2026-04-12T10:00:20.000Z',
spendable: {
[EURE.assetId]: '5000000000000000000',
[BTC.assetId]: '0',
},
},
],
});
assert.equal(record.submission_status, 'accepted_by_relay');
assert.equal(record.relay_status, 'SETTLED');
assert.equal(record.outcome_status, 'awaiting_settlement');
assert.equal(record.outcome_reason, 'relay_settled_but_inventory_delta_missing');
assert.equal(record.attribution_status, 'unattributed');
assert.equal(record.attributed_inventory_delta, null);
assert.notEqual(record.outcome_status, 'completed');
});
test('completed request requires exact EURe decrease and BTC increase after submission', () => {
const [record] = outcomes({
submissions: [submission()],
inventorySnapshots: [
{
inventory_id: 'inventory-before',
observed_at: '2026-04-12T10:00:00.000Z',
spendable: {
[EURE.assetId]: '5000000000000000000',
[BTC.assetId]: '0',
},
},
{
inventory_id: 'inventory-after',
observed_at: '2026-04-12T10:00:15.000Z',
spendable: {
[EURE.assetId]: '0',
[BTC.assetId]: '10000',
},
},
],
});
assert.equal(record.outcome_status, 'completed');
assert.equal(record.outcome_source, 'intent_inventory_spendable_delta');
assert.equal(record.outcome_reason, 'matched_inventory_delta');
assert.equal(record.attribution_status, 'heuristic_match');
assert.equal(record.attributed_inventory_delta.inventory_id, 'inventory-after');
assert.deepEqual(record.attributed_inventory_delta.delta_units, {
[BTC.assetId]: '10000',
[EURE.assetId]: '-5000000000000000000',
});
});
test('accepted request becomes not filled only after deadline grace and fresh inventory evidence', () => {
const [record] = outcomes({
submissions: [submission()],
inventorySnapshots: [
{
observed_at: '2026-04-12T10:02:01.000Z',
spendable: {
[EURE.assetId]: '5000000000000000000',
[BTC.assetId]: '0',
},
},
],
now: '2026-04-12T10:02:01.000Z',
});
assert.equal(record.outcome_status, 'not_filled');
assert.equal(record.outcome_reason, 'deadline_elapsed_without_settlement');
assert.equal(record.attribution_status, 'unattributed');
assert.equal(record.attributed_inventory_delta, null);
});
test('blocked preflight remains blocked and is distinct from request rejection or completion', () => {
const [record] = outcomes({
preflights: [preflight({ state: 'blocked', reason_code: 'insufficient_spendable_eure' })],
});
assert.equal(record.outcome_status, 'blocked');
assert.equal(record.outcome_reason, 'insufficient_spendable_eure');
assert.equal(record.submission_status, null);
assert.notEqual(record.outcome_status, 'completed');
assert.notEqual(record.outcome_status, 'rejected');
});