@yoroi/swap
Version:
The Swap package of Yoroi SDK
205 lines (204 loc) • 5.75 kB
JavaScript
;
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