UNPKG

@yoroi/swap

Version:
205 lines (204 loc) 5.75 kB
"use strict"; import { fetchData, isLeft, isNonNullable, isRight } from '@yoroi/common'; import { Api, Chain } from '@yoroi/types'; import { freeze } from 'immer'; import { DexhunterProtocols, transformersMaker } from './transformers'; export const dexhunterApiMaker = config => { const { address, partner, network, isPrimaryToken, request = fetchData } = config; if (network !== Chain.Network.Mainnet) return new Proxy({}, { get() { return () => Promise.resolve(freeze({ tag: 'left', error: { status: -3, message: 'Dexhunter api only works on mainnet' } }, true)); } }); const baseUrl = baseUrls[network]; const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json', ...(partner && { 'X-Partner-Id': partner }) }; const transformers = transformersMaker(config); return freeze({ async tokens() { const response = await request({ method: 'get', url: `${baseUrl}${apiPaths.tokens}`, headers }); if (isLeft(response)) return parseDhError(response); return freeze({ tag: 'right', value: { status: response.value.status, data: transformers.tokens.response(response.value.data) } }, true); }, async orders() { const response = await request({ method: 'get', url: `${baseUrl}${apiPaths.orders({ address })}`, headers }); if (isLeft(response)) return parseDhError(response); return freeze({ tag: 'right', value: { status: response.value.status, data: transformers.orders.response(response.value.data).sort(({ lastUpdate: A, placedAt: A2 }, { lastUpdate: B, placedAt: B2 }) => (B ?? B2 ?? 0) - (A ?? A2 ?? 0)) } }, true); }, async limitOptions({ tokenIn, tokenOut }) { const estimateResponse = await this.estimate({ tokenIn, tokenOut, slippage: 0, amountIn: 50 }); if (isLeft(estimateResponse)) return parseDhError(estimateResponse); const wantedPrice = estimateResponse.value.data.netPrice; const defaultProtocol = estimateResponse.value.data.splits[0]?.protocol; if (defaultProtocol === undefined) return freeze({ tag: 'left', error: { status: -3, message: 'Invalid state', responseData: null } }, true); const options = (await Promise.all(DexhunterProtocols.map(protocol => this.estimate({ tokenIn, tokenOut, slippage: 0, amountIn: 50, wantedPrice, protocol })))).filter(isRight).map(res => { const split = res.value.data.splits[0]; if (split === undefined) return null; const { protocol, initialPrice, batcherFee } = split; return { protocol, initialPrice, batcherFee }; }).filter(isNonNullable); return freeze({ tag: 'right', value: { status: Api.HttpStatusCode.Ok, data: { defaultProtocol, wantedPrice, options } } }, true); }, async estimate(body) { const kind = body.wantedPrice !== undefined ? 'limitEstimate' : body.amountOut !== undefined ? 'reverseEstimate' : 'estimate'; const response = await request({ method: 'post', url: `${baseUrl}${apiPaths[kind]}`, headers, data: transformers[kind].request(body) }); if (isLeft(response)) return parseDhError(response); return freeze({ tag: 'right', value: { status: response.value.status, data: transformers[kind].response(response.value.data, isPrimaryToken(body.tokenIn)) } }, true); }, async create(body) { const kind = body.wantedPrice !== undefined ? 'limitBuild' : 'build'; const response = await request({ method: 'post', url: `${baseUrl}${apiPaths[kind]}`, headers, data: transformers[kind].request(body) }); if (isLeft(response)) return parseDhError(response); return freeze({ tag: 'right', value: { status: response.value.status, data: transformers[kind].response(response.value.data, isPrimaryToken(body.tokenIn)) } }, true); }, async cancel(body) { const response = await request({ method: 'post', url: `${baseUrl}${apiPaths.cancel}`, headers, data: transformers.cancel.request(body) }); if (isLeft(response)) return parseDhError(response); return freeze({ tag: 'right', value: { status: response.value.status, data: transformers.cancel.response(response.value.data) } }, true); } }, true); }; const parseDhError = ({ tag, error }) => freeze({ tag, error: { ...error, message: JSON.stringify(error.responseData ?? 'Dexhunter API error', null, 2).replace(/^"/, '').replace(/"$/, '') } }, true); const baseUrls = freeze({ [Chain.Network.Mainnet]: 'https://api-us.dexhunterv3.app' }); const apiPaths = freeze({ tokens: '/swap/tokens', orders: ({ address }) => `/swap/orders/${address}`, cancel: '/swap/cancel', estimate: '/swap/estimate', limitBuild: '/swap/limit/build', limitEstimate: '/swap/limit/estimate', reverseEstimate: '/swap/reverseEstimate', build: '/swap/build' }, true); //# sourceMappingURL=api-maker.js.map