import test from 'node:test'; import assert from 'node:assert/strict'; import { KeyPair } from 'near-api-js'; import { createIntentRequestController } from '../src/core/intent-request-controller.mjs'; import { applySlippageBps, buildSolverQuoteRequest, computeBtcReceiveUnitsFromEure, normalizeSolverQuotes, parseDecimalToUnits, selectBestSolverQuote, } from '../src/core/intent-requests.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 buildConfig() { return { tradingBtc: BTC, tradingEure: EURE, nearIntentsAccountId: 'unrip.test.near', nearVerifierContract: 'intents.near', intentRequestDefaultAmountEure: 5, intentRequestMaxAmountEure: 5, intentRequestDefaultSlippageBps: 200, intentRequestMaxSlippageBps: 200, intentRequestMinDeadlineMs: 60_000, intentRequestQuoteTimeoutMs: 10_000, intentRequestPublishTimeoutMs: 10_000, intentRequestStatusTimeoutMs: 10_000, intentRequestInventoryMaxAgeMs: 30_000, intentRequestPriceMaxAgeMs: 30_000, executorResponseTimeoutMs: 10_000, }; } function buildStore({ inventoryUnits = '5000000000000000000', nowIso = '2026-04-12T10:00:00.000Z', inventorySyncedAt = nowIso, priceObservedAt = nowIso, } = {}) { const preflights = []; const submissions = []; return { preflights, submissions, async loadLatestInventorySnapshot() { return { ingested_at: nowIso, payload: { synced_at: inventorySyncedAt, spendable: { [EURE.assetId]: inventoryUnits, [BTC.assetId]: '1000', }, pending_inbound: { [EURE.assetId]: '100000000000000000000', }, }, }; }, async loadLatestMarketPrice() { return { ingested_at: nowIso, payload: { observed_at: priceObservedAt, eure_per_btc: '50000', }, }; }, async insertPreflight(payload) { preflights.push(payload); }, async findPreflight({ requestId, idempotencyKey }) { return preflights.find((entry) => ( (requestId && entry.request_id === requestId) || (idempotencyKey && entry.idempotency_key === idempotencyKey) )) || null; }, async findSubmissionByRequest({ requestId }) { return [...submissions].reverse().find((entry) => entry.request_id === requestId) || null; }, async insertSubmissionResult(payload) { submissions.push(payload); }, async refreshOutcomes() { return []; }, }; } function buildRelay() { return { quoteCalls: 0, publishCalls: 0, async quote() { this.quoteCalls += 1; return [{ quote_hash: 'quote-hash-1', amount_out: '10000', expiration_time: '2026-04-12T10:01:00.000Z', }]; }, async publishIntent() { this.publishCalls += 1; return { status: 'OK', intent_hash: 'intent-hash-1' }; }, async getStatus() { return { status: 'PENDING' }; }, }; } function buildController({ store = buildStore(), relay = buildRelay(), armed = true, verifierRegistered = true, withMakerSuppressed = async (operation) => operation(), getTradingConfig = null, } = {}) { return { store, relay, controller: createIntentRequestController({ config: buildConfig(), store, relayRpcClient: relay, verifierClient: { async isPublicKeyRegistered() { return verifierRegistered; }, async currentSalt() { return '252812b3'; }, }, signer: KeyPair.fromRandom('ed25519'), isArmed: () => armed, isPaused: () => false, getTradingConfig, withMakerSuppressed, now: () => Date.parse('2026-04-12T10:00:00.000Z'), uuid: (() => { let next = 1; return () => `id-${next++}`; })(), }), }; } function buildPair({ sourceAsset, destinationAsset, source, routeId, canTrade = true, blockReason = null, }) { const pairId = `${sourceAsset.assetId}->${destinationAsset.assetId}`; return { key: pairId, pairId, takerEnabled: true, canTrade, blockReason, assetIn: sourceAsset, assetOut: destinationAsset, strategyConfig: { configId: `${pairId}:v1`, version: 1, requestDefaultNotional: '5', requestMaxNotional: null, slippageBps: 200, requestMaxSlippageBps: null, minDeadlineMs: 60_000, priceMaxAgeMs: 30_000, inventoryMaxAgeMs: 30_000, }, priceRoute: source ? { routeId, source, baseAssetId: BTC.assetId, quoteAssetId: sourceAsset.assetId === BTC.assetId ? destinationAsset.assetId : sourceAsset.assetId, } : null, }; } test('EURe decimal parsing, BTC expected receive, and slippage math are exact enough for request limits', () => { const sourceUnits = parseDecimalToUnits('5', EURE.decimals, { field: 'amount_eure' }); const expectedBtc = computeBtcReceiveUnitsFromEure({ eureUnits: sourceUnits, eurPerBtc: '50000', eureDecimals: EURE.decimals, btcDecimals: BTC.decimals, }); assert.equal(sourceUnits, '5000000000000000000'); assert.equal(expectedBtc, '10000'); assert.equal(applySlippageBps(expectedBtc, 200), '9800'); }); test('solver quote normalization selects the best quote above explicit min receive', () => { const quotes = normalizeSolverQuotes({ quotes: [ { quote_hash: 'low', amount_out: '9700' }, { quote_hash: 'best', amount_out: '10050' }, { quote_hash: 'ok', amount_out: '9900' }, ], }); const selected = selectBestSolverQuote(quotes, { minDestinationAmountUnits: '9800' }); assert.equal(selected.quote_hash, 'best'); assert.deepEqual(buildSolverQuoteRequest({ sourceAssetId: EURE.assetId, destinationAssetId: BTC.assetId, sourceAmountUnits: '5000000000000000000', minDeadlineMs: 60_000, }), { defuse_asset_identifier_in: EURE.assetId, defuse_asset_identifier_out: BTC.assetId, exact_amount_in: '5000000000000000000', min_deadline_ms: 60000, }); }); test('preflight is side-effect-free and does not publish a live intent', async () => { const { controller, relay } = buildController(); const preflight = await controller.preflight({ amount_eure: '5', slippage_bps: 200 }); assert.equal(preflight.state, 'draft'); assert.equal(preflight.live_submit_capable, true); assert.equal(preflight.reason_code, 'quote_available'); assert.equal(relay.quoteCalls, 1); assert.equal(relay.publishCalls, 0); }); test('DB null request limits allow operator-chosen amount and slippage', async () => { const store = buildStore({ inventoryUnits: '6000000000000000000' }); const relay = buildRelay(); relay.quote = async function quote() { this.quoteCalls += 1; return [{ quote_hash: 'uncapped-quote-hash', amount_out: '12000', expiration_time: '2026-04-12T10:01:00.000Z', }]; }; const pairId = `${EURE.assetId}->${BTC.assetId}`; const pair = { key: pairId, pairId, takerEnabled: true, canTrade: true, assetIn: EURE, assetOut: BTC, strategyConfig: { requestDefaultNotional: '5', requestMaxNotional: null, slippageBps: 200, requestMaxSlippageBps: null, minDeadlineMs: 60_000, priceMaxAgeMs: 30_000, inventoryMaxAgeMs: 30_000, }, priceRoute: { source: 'btc_eur_reference', }, }; const { controller } = buildController({ store, relay, getTradingConfig: async () => ({ ok: true, tradingEure: EURE, tradingBtc: BTC, pairByKey: new Map([[pairId, pair]]), defaultTakerPair: pair, }), }); const preflight = await controller.preflight({ amount_eure: '6', slippage_bps: 250 }); assert.equal(preflight.state, 'draft'); assert.equal(preflight.reason_code, 'quote_available'); assert.equal(preflight.request_max_notional, null); assert.equal(preflight.request_max_slippage_bps, null); assert.equal(preflight.slippage_bps, 250); assert.equal(preflight.live_submit_capable, true); assert.equal(relay.quoteCalls, 1); }); test('nBTC/USDC preflight accepts pair_id and source_amount without EURe price fields', async () => { const nowIso = '2026-04-12T10:00:00.000Z'; const store = buildStore({ nowIso }); store.loadLatestInventorySnapshot = async () => ({ ingested_at: nowIso, payload: { synced_at: nowIso, spendable: { [USDC.assetId]: '10000000', [BTC.assetId]: '0', }, pending_inbound: {}, }, }); store.loadLatestMarketPrice = async ({ priceRouteId } = {}) => ({ ingested_at: nowIso, payload: { observed_at: nowIso, price_id: 'price-usdc-1', price_route_id: priceRouteId, usdc_per_btc: '50000', }, }); const relay = buildRelay(); relay.quote = async function quote(request) { this.quoteCalls += 1; assert.equal(request.defuse_asset_identifier_in, USDC.assetId); assert.equal(request.defuse_asset_identifier_out, BTC.assetId); assert.equal(request.exact_amount_in, '10000000'); return [{ quote_hash: 'usdc-quote-hash', amount_out: '20000', expiration_time: '2026-04-12T10:01:00.000Z', }]; }; const pair = buildPair({ sourceAsset: USDC, destinationAsset: BTC, source: 'btc_usdc_reference', routeId: 'btc-usdc-route', }); const { controller } = buildController({ store, relay, getTradingConfig: async () => ({ ok: true, tradingEure: EURE, tradingBtc: BTC, pairByKey: new Map([[pair.key, pair]]), pairById: new Map([[pair.pairId, pair]]), defaultTakerPair: pair, }), }); const preflight = await controller.preflight({ pair_id: pair.pairId, source_amount: '10', slippage_bps: 200, }); assert.equal(preflight.state, 'draft'); assert.equal(preflight.reason_code, 'quote_available'); assert.equal(preflight.amount_eure, null); assert.equal(preflight.source_asset_id, USDC.assetId); assert.equal(preflight.destination_asset_id, BTC.assetId); assert.equal(preflight.expected_destination_amount_units, '20000'); assert.equal(preflight.min_destination_amount_units, '19600'); assert.equal(preflight.notional, '10'); assert.equal(preflight.notional_symbol, 'USDC'); assert.equal(preflight.reference_price_id, 'price-usdc-1'); assert.equal(relay.quoteCalls, 1); }); test('nBTC/USDC preflight blocks missing route before solver quote', async () => { const relay = buildRelay(); const pair = buildPair({ sourceAsset: USDC, destinationAsset: BTC, source: null, routeId: null, canTrade: false, blockReason: 'price_route_missing', }); const { controller } = buildController({ relay, getTradingConfig: async () => ({ ok: true, tradingEure: EURE, tradingBtc: BTC, pairByKey: new Map([[pair.key, pair]]), pairById: new Map([[pair.pairId, pair]]), defaultTakerPair: pair, }), }); const preflight = await controller.preflight({ pair_id: pair.pairId, source_amount: '10' }); assert.equal(preflight.state, 'blocked'); assert.equal(preflight.reason_code, 'price_route_missing'); assert.equal(relay.quoteCalls, 0); }); test('nBTC/USDC preflight blocks insufficient source inventory with source-specific reason', async () => { const nowIso = '2026-04-12T10:00:00.000Z'; const store = buildStore({ nowIso }); store.loadLatestInventorySnapshot = async () => ({ ingested_at: nowIso, payload: { synced_at: nowIso, spendable: { [USDC.assetId]: '1', }, pending_inbound: {}, }, }); store.loadLatestMarketPrice = async ({ priceRouteId } = {}) => ({ ingested_at: nowIso, payload: { observed_at: nowIso, price_id: 'price-usdc-2', price_route_id: priceRouteId, usdc_per_btc: '50000', }, }); const relay = buildRelay(); const pair = buildPair({ sourceAsset: USDC, destinationAsset: BTC, source: 'btc_usdc_reference', routeId: 'btc-usdc-route', }); const { controller } = buildController({ store, relay, getTradingConfig: async () => ({ ok: true, tradingEure: EURE, tradingBtc: BTC, pairByKey: new Map([[pair.key, pair]]), pairById: new Map([[pair.pairId, pair]]), defaultTakerPair: pair, }), }); const preflight = await controller.preflight({ pair_id: pair.pairId, source_amount: '10' }); assert.equal(preflight.state, 'blocked'); assert.equal(preflight.reason_code, 'insufficient_spendable_usdc'); assert.equal(relay.quoteCalls, 0); }); test('pair-native preflight treats explicit zero source_amount as invalid instead of using default', async () => { const relay = buildRelay(); const pair = buildPair({ sourceAsset: USDC, destinationAsset: BTC, source: 'btc_usdc_reference', routeId: 'btc-usdc-route', }); const { controller } = buildController({ relay, getTradingConfig: async () => ({ ok: true, tradingEure: EURE, tradingBtc: BTC, pairByKey: new Map([[pair.key, pair]]), pairById: new Map([[pair.pairId, pair]]), defaultTakerPair: pair, }), }); const preflight = await controller.preflight({ pair_id: pair.pairId, source_amount: 0 }); assert.equal(preflight.state, 'blocked'); assert.equal(preflight.reason_code, 'invalid_source_amount'); assert.equal(preflight.source_amount, '0'); assert.equal(relay.quoteCalls, 0); }); test('insufficient spendable EURe blocks before solver quote or signing', async () => { const store = buildStore({ inventoryUnits: '0' }); const relay = buildRelay(); const { controller } = buildController({ store, relay }); const preflight = await controller.preflight({ amount_eure: '5', slippage_bps: 200 }); assert.equal(preflight.state, 'blocked'); assert.equal(preflight.reason_code, 'insufficient_spendable_eure'); assert.equal(preflight.inventory_snapshot.pending_inbound[EURE.assetId], '100000000000000000000'); assert.equal(relay.quoteCalls, 0); assert.equal(relay.publishCalls, 0); }); test('duplicate request submit returns stored result and never publishes twice', async () => { const { controller, store, relay } = buildController(); const preflight = await controller.preflight({ amount_eure: '5', slippage_bps: 200 }); const first = await controller.submit({ request_id: preflight.request_id }); const second = await controller.submit({ request_id: preflight.request_id }); assert.equal(first.submission_result.status, 'accepted_by_relay'); assert.equal(second.duplicate, true); assert.equal(relay.publishCalls, 1); assert.equal(store.submissions.filter((entry) => entry.status === 'submit_requested').length, 1); assert.equal(store.submissions.filter((entry) => entry.status === 'accepted_by_relay').length, 1); }); test('executor disarmed blocks request submission without calling relay publish', async () => { const { controller, relay } = buildController({ armed: false }); const preflight = await controller.preflight({ amount_eure: '5', slippage_bps: 200 }); const result = await controller.submit({ request_id: preflight.request_id }); assert.equal(result.submission_result.status, 'blocked'); assert.equal(result.submission_result.result_code, 'executor_disarmed'); assert.equal(relay.publishCalls, 0); }); test('stale reference price blocks request preflight before solver quote', async () => { const store = buildStore({ priceObservedAt: '2026-04-12T09:59:00.000Z' }); const relay = buildRelay(); const { controller } = buildController({ store, relay }); const preflight = await controller.preflight({ amount_eure: '5', slippage_bps: 200 }); assert.equal(preflight.state, 'blocked'); assert.equal(preflight.reason_code, 'stale_reference_price'); assert.equal(relay.quoteCalls, 0); assert.equal(relay.publishCalls, 0); }); test('unregistered signer blocks request preflight before solver quote or signing', async () => { const relay = buildRelay(); const { controller } = buildController({ relay, verifierRegistered: false }); const preflight = await controller.preflight({ amount_eure: '5', slippage_bps: 200 }); assert.equal(preflight.state, 'blocked'); assert.equal(preflight.reason_code, 'signer_not_registered'); assert.equal(relay.quoteCalls, 0); assert.equal(relay.publishCalls, 0); }); test('relay publish failure records submit_requested first and never reports completion', async () => { const relay = buildRelay(); relay.publishIntent = async function publishIntent() { this.publishCalls += 1; throw new Error('relay publish unavailable'); }; const { controller, store } = buildController({ relay }); const preflight = await controller.preflight({ amount_eure: '5', slippage_bps: 200 }); const result = await controller.submit({ request_id: preflight.request_id }); assert.equal(result.submission_result.status, 'failed'); assert.equal(result.submission_result.result_code, 'publish_intent_failed'); assert.equal(result.submission_result.result_text, 'relay publish unavailable'); assert.equal(relay.publishCalls, 1); assert.equal(store.submissions[0].status, 'submit_requested'); assert.equal(store.submissions[1].status, 'failed'); assert.notEqual(result.submission_result.status, 'completed'); }); test('preflight suppresses maker responses while collecting solver quotes', async () => { let suppressed = false; let wrapperCalls = 0; const relay = buildRelay(); relay.quote = async function quote() { this.quoteCalls += 1; assert.equal(suppressed, true); return [{ quote_hash: 'external-quote-hash', amount_out: '10000', expiration_time: '2026-04-12T10:01:00.000Z', }]; }; const { controller } = buildController({ relay, withMakerSuppressed: async (operation, context) => { wrapperCalls += 1; assert.match(context.requestId, /^id-/); suppressed = true; try { return await operation(); } finally { suppressed = false; } }, }); const preflight = await controller.preflight({ amount_eure: '5', slippage_bps: 200 }); assert.equal(preflight.state, 'draft'); assert.equal(preflight.selected_quote.quote_hash, 'external-quote-hash'); assert.equal(wrapperCalls, 1); assert.equal(suppressed, false); }); test('refreshOutcomes refreshes relay status before recomputing settlement truth', async () => { const { controller, store, relay } = buildController(); const preflight = await controller.preflight({ amount_eure: '5', slippage_bps: 200 }); await controller.submit({ request_id: preflight.request_id }); const accepted = store.submissions.find((entry) => entry.status === 'accepted_by_relay'); store.loadSubmissionsForStatusRefresh = async () => [accepted]; store.refreshOutcomes = async () => [{ request_id: preflight.request_id, outcome_status: 'failed' }]; relay.getStatus = async () => ({ intent_hash: accepted.intent_hash, status: 'SETTLED', data: { hash: 'settlement-tx-hash' }, }); const refreshed = await controller.refreshOutcomes(); const statusRefresh = store.submissions.at(-1); assert.equal(refreshed.refreshed_statuses.length, 1); assert.equal(refreshed.outcomes[0].outcome_status, 'failed'); assert.equal(statusRefresh.status, 'accepted_by_relay'); assert.equal(statusRefresh.result_code, 'relay_status_refreshed'); assert.equal(statusRefresh.relay_status, 'SETTLED'); assert.equal(statusRefresh.relay_status_response.data.hash, 'settlement-tx-hash'); assert.equal(statusRefresh.submitted_at, accepted.submitted_at); assert.ok(statusRefresh.status_checked_at); });