import Sinon, { type SinonStub } from 'sinon'; import type { BridgeQuote, BridgeQuoteParams, BridgeTransferStatus, } from '../interfaces/IExternalBridge.js'; /** * Create mock functions for LiFi SDK. */ export function createLiFiSdkMocks() { return { createConfig: Sinon.stub(), getQuote: Sinon.stub(), executeRoute: Sinon.stub(), getStatus: Sinon.stub(), convertQuoteToRoute: Sinon.stub().callsFake((quote: unknown) => { const q = quote as Record & { action?: { fromChainId?: number; toChainId?: number }; }; return { ...q, fromChainId: q.action?.fromChainId ?? 42161, toChainId: q.action?.toChainId ?? 1151111081099710, steps: [], }; }), }; } /** * Configure a mock getQuote to return a successful quote. */ export function mockSuccessfulQuote( stub: SinonStub, overrides?: Partial<{ id: string; tool: string; fromAmount: string; toAmount: string; toAmountMin: string; executionDuration: number; fromChainId: number; toChainId: number; }>, ) { const fromChainId = overrides?.fromChainId ?? 42161; const toChainId = overrides?.toChainId ?? 1151111081099710; const fromAmount = overrides?.fromAmount ?? '10000000000'; const toAmount = overrides?.toAmount ?? '9950000000'; const toAmountMin = overrides?.toAmountMin ?? '9900000000'; stub.resolves({ id: overrides?.id ?? 'quote-123', tool: overrides?.tool ?? 'across', action: { fromAmount, fromChainId, toChainId, }, estimate: { toAmount, toAmountMin, executionDuration: overrides?.executionDuration ?? 300, }, }); } /** * Configure a mock executeRoute to return a successful execution. */ export function mockSuccessfulExecution(stub: SinonStub, txHash: string) { stub.resolves({ steps: [ { execution: { process: [{ txHash }], }, }, ], }); } /** * Configure a mock getStatus to return a specific status. */ export function mockLiFiStatus( stub: SinonStub, status: 'DONE' | 'PENDING' | 'FAILED' | 'NOT_FOUND', overrides?: Partial<{ receivingTxHash: string; amount: string; substatus: string; }>, ) { const responses: Record = { DONE: { status: 'DONE', receiving: { txHash: overrides?.receivingTxHash ?? '0xReceivingTxHash', amount: overrides?.amount ?? '9950000000', }, }, PENDING: { status: 'PENDING', substatus: overrides?.substatus ?? 'WAIT_SOURCE_CONFIRMATIONS', }, FAILED: { status: 'FAILED', substatus: overrides?.substatus ?? 'BRIDGE_CALL_FAILED', }, NOT_FOUND: { status: 'NOT_FOUND', }, }; stub.resolves(responses[status]); } /** * Create a mock BridgeQuote for testing. * The route structure includes all fields read by validateRouteAgainstRequest. */ export function createMockBridgeQuote( overrides?: Partial, ): BridgeQuote { const route = overrides?.route as | { action?: { fromChainId?: number; toChainId?: number } } | undefined; const usesReverseQuote = overrides?.requestParams?.toAmount !== undefined; const defaultRequestParams: BridgeQuoteParams = { fromChain: 42161, toChain: 1399811149, fromToken: '0xCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC', toToken: '0xCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC', toAddress: '0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', fromAddress: '0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', ...(usesReverseQuote ? { toAmount: 9950000000n } : { fromAmount: 10000000000n }), }; const requestParams: BridgeQuoteParams = { ...defaultRequestParams, ...overrides?.requestParams, }; const fromChainId = route?.action?.fromChainId ?? requestParams.fromChain; const toChainId = route?.action?.toChainId ?? requestParams.toChain; const fromAmount = overrides?.fromAmount ?? requestParams.fromAmount ?? 10000000000n; const toAmount = overrides?.toAmount ?? 9950000000n; const toAmountMin = overrides?.toAmountMin ?? 9900000000n; return { id: 'quote-123', tool: 'across', fromAmount, toAmount, toAmountMin, executionDuration: 300, gasCosts: 50000000n, feeCosts: 0n, // Route includes all fields read by validateRouteAgainstRequest for validation compatibility route: { action: { fromChainId, toChainId }, fromChainId, toChainId, fromToken: { address: requestParams.fromToken }, toToken: { address: requestParams.toToken }, fromAddress: requestParams.fromAddress, toAddress: requestParams.toAddress ?? requestParams.fromAddress, fromAmount: fromAmount.toString(), toAmount: toAmount.toString(), }, requestParams, ...overrides, }; } /** * Create a mock BridgeTransferStatus for testing. */ export function createMockBridgeStatus( status: 'pending' | 'complete' | 'failed' | 'not_found', overrides?: Partial<{ substatus: string; receivingTxHash: string; receivedAmount: bigint; error: string; }>, ): BridgeTransferStatus { switch (status) { case 'pending': return { status: 'pending', substatus: overrides?.substatus, }; case 'complete': return { status: 'complete', receivingTxHash: overrides?.receivingTxHash ?? '0xReceivingTxHash', receivedAmount: overrides?.receivedAmount ?? 9950000000n, }; case 'failed': return { status: 'failed', error: overrides?.error, }; case 'not_found': return { status: 'not_found' }; } }