diff --git a/src/atomex/atomex.ts b/src/atomex/atomex.ts index 7ff6f58b..e5bd8f7f 100644 --- a/src/atomex/atomex.ts +++ b/src/atomex/atomex.ts @@ -9,7 +9,7 @@ import type { AtomexContext } from './atomexContext'; import { isNormalizedSwapPreviewParameters, normalizeSwapPreviewParameters } from './helpers'; import { NewSwapRequest, SwapOperationCompleteStage, AtomexOptions, - AtomexBlockchainNetworkOptions, SwapPreview, SwapPreviewParameters, NormalizedSwapPreviewParameters, SwapPreviewFee + AtomexBlockchainNetworkOptions, SwapPreview, SwapPreviewParameters, NormalizedSwapPreviewParameters, SwapPreviewFee, SwapPreviewError } from './models/index'; export class Atomex implements AtomexService { @@ -97,9 +97,6 @@ export class Atomex implements AtomexService { throw new Error(`No available liquidity for the "${normalizedSwapPreviewParameters.exchangeSymbol.name}" symbol`); const actualOrderPreview = await this.exchangeManager.getOrderPreview(normalizedSwapPreviewParameters); - if (!actualOrderPreview) - throw new Error(`It's no possible to calculate the order preview for the "${normalizedSwapPreviewParameters.exchangeSymbol.name}" symbol`); - const fees = await this.calculateSwapPreviewFees( fromCurrencyInfo, fromNativeCurrencyInfo, @@ -148,15 +145,24 @@ export class Atomex implements AtomexService { }); } + const errors: Array> = []; + if (!actualOrderPreview) + errors.push({ id: 'not-enough-liquidity' }); + return { type: normalizedSwapPreviewParameters.type, from: { currencyId: normalizedSwapPreviewParameters.from, address: fromAddress, - actual: { - amount: actualOrderPreview.from.amount, - price: actualOrderPreview.from.price, - }, + actual: actualOrderPreview + ? { + amount: actualOrderPreview.from.amount, + price: actualOrderPreview.from.price, + } + : { + amount: normalizedSwapPreviewParameters.isFromAmount ? normalizedSwapPreviewParameters.amount : new BigNumber(0), + price: new BigNumber(0) + }, available: { amount: availableLiquidity.from.amount, price: availableLiquidity.from.price @@ -169,10 +175,15 @@ export class Atomex implements AtomexService { to: { currencyId: normalizedSwapPreviewParameters.to, address: toAddress, - actual: { - amount: actualOrderPreview.to.amount, - price: actualOrderPreview.to.price, - }, + actual: actualOrderPreview + ? { + amount: actualOrderPreview.to.amount, + price: actualOrderPreview.to.price, + } + : { + amount: !normalizedSwapPreviewParameters.isFromAmount ? normalizedSwapPreviewParameters.amount : new BigNumber(0), + price: new BigNumber(0) + }, available: { amount: availableLiquidity.to.amount, price: availableLiquidity.to.price @@ -185,7 +196,7 @@ export class Atomex implements AtomexService { symbol: normalizedSwapPreviewParameters.exchangeSymbol.name, side: normalizedSwapPreviewParameters.side, fees, - errors: [], + errors, warnings: [] }; } @@ -307,7 +318,7 @@ export class Atomex implements AtomexService { makerFee, { name: useWatchTower ? 'redeem-reward' : 'redeem-fee', - currencyId: toCurrencyInfo.currency.id, + currencyId: useWatchTower ? toCurrencyInfo.currency.id : toNativeCurrencyInfo.currency.id, estimated: toRedeemOrRewardForRedeem.estimated, max: toRedeemOrRewardForRedeem.max } diff --git a/src/atomex/models/swapPreview.ts b/src/atomex/models/swapPreview.ts index b7096a4d..394face6 100644 --- a/src/atomex/models/swapPreview.ts +++ b/src/atomex/models/swapPreview.ts @@ -32,7 +32,7 @@ export interface SwapPreviewCurrencyData { export interface SwapPreviewError { readonly id: string - readonly data: TErrorData; + readonly data?: TErrorData; } export interface SwapPreviewWarning { diff --git a/tests/atomex/swapPreview.test.ts b/tests/atomex/swapPreview.test.ts index 82886a5f..99ed5ca1 100644 --- a/tests/atomex/swapPreview.test.ts +++ b/tests/atomex/swapPreview.test.ts @@ -47,7 +47,7 @@ describe('Atomex | Swap Preview', () => { }); test.each(swapPreviewWithoutAccountTestCases)( - 'getting swap preview without account: %s', + 'getting swap preview without account: %s\n\tSwap Preview Parameters: %j', async (_, swapPreviewParameters, expectedSwapPreview, environment) => { mockedAtomexContext.services.exchangeService.getSymbols.mockResolvedValue(environment.symbols); mockedAtomexContext.services.exchangeService.getOrderBook.mockImplementation(symbol => { diff --git a/tests/atomex/testCases/swapPreviewWithoutAccountTestCases.ts b/tests/atomex/testCases/swapPreviewWithoutAccountTestCases.ts index 985d0e4a..299848eb 100644 --- a/tests/atomex/testCases/swapPreviewWithoutAccountTestCases.ts +++ b/tests/atomex/testCases/swapPreviewWithoutAccountTestCases.ts @@ -361,7 +361,357 @@ const swapPreviewWithoutAccountTestCases: ReadonlyArray<[ ], atomexProtocolFees: validAtomexProtocolV1Fees[0], } - ] + ], + [ + 'Swap XTZ -> ETH with disabled watch tower mode', + { + type: 'SolidFillOrKill', + amount: new BigNumber(123), + from: 'XTZ', + to: 'ETH', + useWatchTower: false + }, + { + type: 'SolidFillOrKill', + side: 'Sell', + symbol: 'XTZ/ETH', + from: { + currencyId: 'XTZ', + actual: { + amount: new BigNumber('123'), + price: new BigNumber('0.000948468'), + }, + available: { + amount: new BigNumber('300'), + price: new BigNumber('0.000948468') + } + }, + to: { + currencyId: 'ETH', + actual: { + amount: new BigNumber('0.116661564'), + price: new BigNumber('1054.331827747'), + }, + available: { + amount: new BigNumber('0.2845404'), + price: new BigNumber('1054.331827747') + }, + }, + fees: { + success: [ + { + name: 'payment-fee', + currencyId: 'XTZ', + estimated: new BigNumber('0.0743'), + max: new BigNumber('0.1') + }, + { + name: 'maker-fee', + currencyId: 'XTZ', + estimated: new BigNumber('5.419531'), + max: new BigNumber('9.27491') + }, + { + name: 'redeem-fee', + currencyId: 'ETH', + estimated: new BigNumber('0.0023'), + max: new BigNumber('0.003') + } + ], + refund: [ + { + name: 'payment-fee', + currencyId: 'XTZ', + estimated: new BigNumber('0.0743'), + max: new BigNumber('0.1') + }, + { + name: 'maker-fee', + currencyId: 'XTZ', + estimated: new BigNumber('5.419531'), + max: new BigNumber('9.27491') + }, + { + name: 'refund-fee', + currencyId: 'XTZ', + estimated: new BigNumber('0.03'), + max: new BigNumber('0.04') + } + ] + }, + errors: [], + warnings: [] + }, + { + symbols: validExchangeSymbols, + orderBooks: [validOrderBooks['XTZ/ETH'][0]], + atomexProtocolFees: validAtomexProtocolV1Fees[0], + } + ], + [ + 'Swap ETH -> XTZ_USDT with disabled watch tower mode', + { + type: 'SolidFillOrKill', + amount: new BigNumber(0.37), + from: 'ETH', + to: 'USDT_XTZ', + useWatchTower: false + }, + { + type: 'SolidFillOrKill', + side: 'Sell', + symbol: 'ETH/USDT_XTZ', + from: { + currencyId: 'ETH', + actual: { + amount: new BigNumber('0.37'), + price: new BigNumber('1603.468672'), + }, + available: { + amount: new BigNumber('1'), + price: new BigNumber('1603.468672') + } + }, + to: { + currencyId: 'USDT_XTZ', + actual: { + amount: new BigNumber('593.283408'), + price: new BigNumber('0.000623647'), + }, + available: { + amount: new BigNumber('1603.468672'), + price: new BigNumber('0.000623647') + }, + }, + fees: { + success: [ + { + name: 'payment-fee', + currencyId: 'ETH', + estimated: new BigNumber('0.00525'), + max: new BigNumber('0.009') + }, + { + name: 'maker-fee', + currencyId: 'ETH', + estimated: new BigNumber('0.002398925'), + max: new BigNumber('0.0031233') + }, + { + name: 'redeem-fee', + currencyId: 'XTZ', + estimated: new BigNumber('0.08'), + max: new BigNumber('0.1') + } + ], + refund: [ + { + name: 'payment-fee', + currencyId: 'ETH', + estimated: new BigNumber('0.00525'), + max: new BigNumber('0.009') + }, + { + name: 'maker-fee', + currencyId: 'ETH', + estimated: new BigNumber('0.002398925'), + max: new BigNumber('0.0031233') + }, + { + name: 'refund-fee', + currencyId: 'ETH', + estimated: new BigNumber('0.0017'), + max: new BigNumber('0.002') + } + ] + }, + errors: [], + warnings: [] + }, + { + symbols: validExchangeSymbols, + orderBooks: [ + validOrderBooks['ETH/USDT_XTZ'][0], + validOrderBooks['XTZ/ETH'][0], + ], + atomexProtocolFees: validAtomexProtocolV1Fees[0], + } + ], + [ + 'Swap XTZ -> ETH with more amount than liquidity', + { + type: 'SolidFillOrKill', + amount: new BigNumber(301.12345678), + from: 'XTZ', + to: 'ETH', + }, + { + type: 'SolidFillOrKill', + side: 'Sell', + symbol: 'XTZ/ETH', + from: { + currencyId: 'XTZ', + actual: { + amount: new BigNumber('301.12345678'), + price: new BigNumber(0), + }, + available: { + amount: new BigNumber('300'), + price: new BigNumber('0.000948468') + } + }, + to: { + currencyId: 'ETH', + actual: { + amount: new BigNumber(0), + price: new BigNumber(0), + }, + available: { + amount: new BigNumber('0.2845404'), + price: new BigNumber('1054.331827747') + }, + }, + fees: { + success: [ + { + name: 'payment-fee', + currencyId: 'XTZ', + estimated: new BigNumber('0.0743'), + max: new BigNumber('0.1') + }, + { + name: 'maker-fee', + currencyId: 'XTZ', + estimated: new BigNumber('5.419531'), + max: new BigNumber('9.27491') + }, + { + name: 'redeem-reward', + currencyId: 'ETH', + estimated: new BigNumber('0.0035'), + max: new BigNumber('0.0035') + } + ], + refund: [ + { + name: 'payment-fee', + currencyId: 'XTZ', + estimated: new BigNumber('0.0743'), + max: new BigNumber('0.1') + }, + { + name: 'maker-fee', + currencyId: 'XTZ', + estimated: new BigNumber('5.419531'), + max: new BigNumber('9.27491') + }, + { + name: 'refund-fee', + currencyId: 'XTZ', + estimated: new BigNumber('0.03'), + max: new BigNumber('0.04') + } + ] + }, + errors: [{ + id: 'not-enough-liquidity' + }], + warnings: [] + }, + { + symbols: validExchangeSymbols, + orderBooks: [validOrderBooks['XTZ/ETH'][0]], + atomexProtocolFees: validAtomexProtocolV1Fees[0], + } + ], + [ + 'Swap XTZ -> ETH with more amount than liquidity', + { + type: 'SolidFillOrKill', + amount: new BigNumber(1), + from: 'XTZ', + to: 'ETH', + isFromAmount: false + }, + { + type: 'SolidFillOrKill', + side: 'Sell', + symbol: 'XTZ/ETH', + from: { + currencyId: 'XTZ', + actual: { + amount: new BigNumber(0), + price: new BigNumber(0), + }, + available: { + amount: new BigNumber('300'), + price: new BigNumber('0.000948468') + } + }, + to: { + currencyId: 'ETH', + actual: { + amount: new BigNumber(1), + price: new BigNumber(0), + }, + available: { + amount: new BigNumber('0.2845404'), + price: new BigNumber('1054.331827747') + }, + }, + fees: { + success: [ + { + name: 'payment-fee', + currencyId: 'XTZ', + estimated: new BigNumber('0.0743'), + max: new BigNumber('0.1') + }, + { + name: 'maker-fee', + currencyId: 'XTZ', + estimated: new BigNumber('5.419531'), + max: new BigNumber('9.27491') + }, + { + name: 'redeem-reward', + currencyId: 'ETH', + estimated: new BigNumber('0.0035'), + max: new BigNumber('0.0035') + } + ], + refund: [ + { + name: 'payment-fee', + currencyId: 'XTZ', + estimated: new BigNumber('0.0743'), + max: new BigNumber('0.1') + }, + { + name: 'maker-fee', + currencyId: 'XTZ', + estimated: new BigNumber('5.419531'), + max: new BigNumber('9.27491') + }, + { + name: 'refund-fee', + currencyId: 'XTZ', + estimated: new BigNumber('0.03'), + max: new BigNumber('0.04') + } + ] + }, + errors: [{ + id: 'not-enough-liquidity' + }], + warnings: [] + }, + { + symbols: validExchangeSymbols, + orderBooks: [validOrderBooks['XTZ/ETH'][0]], + atomexProtocolFees: validAtomexProtocolV1Fees[0], + } + ], ]; export default swapPreviewWithoutAccountTestCases;