Files
orionprotocol-sdk/src/services/OrionAggregator/index.ts
Aleksandr Kraiz b2f3cdf5fb Orion, Orion Unit, Configuration (#40)
* Refactoring

* Better docs

* Bump

* ESLint standard

* Fix

* Bumo

* VerboseOrionUnitConfig to types

* Docs improvements

* Docs improvements. Orion default env
2023-02-08 14:51:58 +04:00

328 lines
9.4 KiB
TypeScript

import BigNumber from 'bignumber.js';
import { z } from 'zod';
import fetchWithValidation from '../../fetchWithValidation';
import swapInfoSchema from './schemas/swapInfoSchema';
import exchangeInfoSchema from './schemas/exchangeInfoSchema';
import cancelOrderSchema from './schemas/cancelOrderSchema';
import orderBenefitsSchema from './schemas/orderBenefitsSchema';
import errorSchema from './schemas/errorSchema';
import placeAtomicSwapSchema from './schemas/placeAtomicSwapSchema';
import { OrionAggregatorWS } from './ws';
import { atomicSwapHistorySchema } from './schemas/atomicSwapHistorySchema';
import { Exchange, SignedCancelOrderRequest, SignedCFDOrder, SignedOrder } from '../../types';
import { pairConfigSchema } from './schemas';
import {
aggregatedOrderbookSchema, exchangeOrderbookSchema, poolReservesSchema,
} from './schemas/aggregatedOrderbookSchema';
import networkCodes from '../../constants/networkCodes';
import toUpperCase from '../../utils/toUpperCase';
import httpToWS from '../../utils/httpToWS';
class OrionAggregator {
private readonly apiUrl: string;
readonly ws: OrionAggregatorWS;
get api() {
return this.apiUrl;
}
constructor(
httpAPIUrl: string,
wsAPIUrl: string,
) {
// const oaUrl = new URL(apiUrl);
// const oaWsProtocol = oaUrl.protocol === 'https:' ? 'wss' : 'ws';
// const orionAggregatorWsUrl = `${oaWsProtocol}://${oaUrl.host + (oaUrl.pathname === '/'
// ? ''
// : oaUrl.pathname)}/v1`;
this.apiUrl = httpAPIUrl;
this.ws = new OrionAggregatorWS(httpToWS(wsAPIUrl));
this.getHistoryAtomicSwaps = this.getHistoryAtomicSwaps.bind(this);
this.getPairConfig = this.getPairConfig.bind(this);
this.getPairConfigs = this.getPairConfigs.bind(this);
this.getPairsList = this.getPairsList.bind(this);
this.getSwapInfo = this.getSwapInfo.bind(this);
this.getTradeProfits = this.getTradeProfits.bind(this);
this.placeAtomicSwap = this.placeAtomicSwap.bind(this);
this.placeOrder = this.placeOrder.bind(this);
this.placeCFDOrder = this.placeCFDOrder.bind(this);
this.cancelOrder = this.cancelOrder.bind(this);
this.checkWhitelisted = this.checkWhitelisted.bind(this);
this.getLockedBalance = this.getLockedBalance.bind(this);
this.getAggregatedOrderbook = this.getAggregatedOrderbook.bind(this);
this.getExchangeOrderbook = this.getExchangeOrderbook.bind(this);
this.getPoolReserves = this.getPoolReserves.bind(this);
}
getPairsList = (market: 'spot' | 'futures') => {
const url = new URL(`${this.apiUrl}/api/v1/pairs/list`);
url.searchParams.append('market', toUpperCase(market));
return fetchWithValidation(
url.toString(),
z.array(z.string()),
);
};
getAggregatedOrderbook = (pair: string, depth = 20) => {
const url = new URL(`${this.apiUrl}/api/v1/orderbook`);
url.searchParams.append('pair', pair);
url.searchParams.append('depth', depth.toString());
return fetchWithValidation(
url.toString(),
aggregatedOrderbookSchema,
undefined,
errorSchema,
);
};
getExchangeOrderbook = (
pair: string,
exchange: Exchange,
depth = 20,
filterByBrokerBalances: boolean | null = null,
) => {
const url = new URL(`${this.apiUrl}/api/v1/orderbook/${exchange}/${pair}`);
url.searchParams.append('pair', pair);
url.searchParams.append('depth', depth.toString());
if (filterByBrokerBalances !== null) {
url.searchParams.append('filterByBrokerBalances', filterByBrokerBalances.toString());
}
return fetchWithValidation(
url.toString(),
exchangeOrderbookSchema,
undefined,
errorSchema,
);
};
getPairConfigs = (market: 'spot' | 'futures') => {
const url = new URL(`${this.apiUrl}/api/v1/pairs/exchangeInfo`);
url.searchParams.append('market', toUpperCase(market));
return fetchWithValidation(
url.toString(),
exchangeInfoSchema,
undefined,
errorSchema,
);
}
getPoolReserves = (
pair: string,
exchange: Exchange,
) => {
const url = new URL(`${this.apiUrl}/api/v1/pools/reserves/${exchange}/${pair}`);
return fetchWithValidation(
url.toString(),
poolReservesSchema,
undefined,
errorSchema,
);
};
getPairConfig = (assetPair: string) => fetchWithValidation(
`${this.apiUrl}/api/v1/pairs/exchangeInfo/${assetPair}`,
pairConfigSchema,
undefined,
errorSchema,
);
checkWhitelisted = (address: string) => fetchWithValidation(
`${this.apiUrl}/api/v1/whitelist/check?address=${address}`,
z.boolean(),
undefined,
errorSchema,
);
placeOrder = (
signedOrder: SignedOrder,
isCreateInternalOrder: boolean,
partnerId?: string,
) => {
const headers = {
'Content-Type': 'application/json',
Accept: 'application/json',
...partnerId && { 'X-Partner-Id': partnerId },
};
return fetchWithValidation(
`${this.apiUrl}/api/v1/order/${isCreateInternalOrder ? 'internal' : ''}`,
z.object({
orderId: z.string(),
placementRequests: z.array(
z.object({
amount: z.number(),
brokerAddress: z.string(),
exchange: z.string(),
}),
).optional(),
}),
{
headers,
method: 'POST',
body: JSON.stringify(signedOrder),
},
errorSchema,
);
};
cancelOrder = (signedCancelOrderRequest: SignedCancelOrderRequest) => fetchWithValidation(
`${this.apiUrl}/api/v1/order`,
cancelOrderSchema,
{
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
...signedCancelOrderRequest,
sender: signedCancelOrderRequest.senderAddress,
}),
},
errorSchema,
);
placeCFDOrder = (
signedOrder: SignedCFDOrder
) => {
const headers = {
'Content-Type': 'application/json',
Accept: 'application/json',
};
return fetchWithValidation(
`${this.apiUrl}/api/v1/order/futures`,
z.object({
orderId: z.string(),
placementRequests: z.array(
z.object({
amount: z.number(),
brokerAddress: z.string(),
exchange: z.string(),
}),
).optional(),
}),
{
headers,
method: 'POST',
body: JSON.stringify(signedOrder),
},
errorSchema,
);
};
getSwapInfo = (
type: 'exactSpend' | 'exactReceive',
assetIn: string,
assetOut: string,
amount: string,
instantSettlement?: boolean,
exchanges?: Exchange[] | 'cex' | 'pools',
) => {
const url = new URL(`${this.apiUrl}/api/v1/swap`);
url.searchParams.append('assetIn', assetIn);
url.searchParams.append('assetOut', assetOut);
if (type === 'exactSpend') {
url.searchParams.append('amountIn', amount);
} else {
url.searchParams.append('amountOut', amount);
}
if (exchanges) {
if (Array.isArray(exchanges)) {
exchanges.forEach((exchange) => {
url.searchParams.append('exchanges', exchange);
});
} else {
url.searchParams.append('exchanges', exchanges);
}
}
if (instantSettlement) {
url.searchParams.append('instantSettlement', 'true');
}
return fetchWithValidation(
url.toString(),
swapInfoSchema,
undefined,
errorSchema,
);
};
getLockedBalance = (address: string, currency: string) => {
const url = new URL(`${this.apiUrl}/api/v1/address/balance/reserved/${currency}`);
url.searchParams.append('address', address);
return fetchWithValidation(
url.toString(),
z.object({
[currency]: z.number(),
}).partial(),
undefined,
errorSchema,
);
};
getTradeProfits = (
symbol: string,
amount: BigNumber,
isBuy: boolean,
) => {
const url = new URL(`${this.apiUrl}/api/v1/orderBenefits`);
url.searchParams.append('symbol', symbol);
url.searchParams.append('amount', amount.toString());
url.searchParams.append('side', isBuy ? 'buy' : 'sell');
return fetchWithValidation(
url.toString(),
orderBenefitsSchema,
undefined,
errorSchema,
);
};
/**
* Placing atomic swap. Placement must take place on the target chain.
* @param secretHash Secret hash
* @param sourceNetworkCode uppercase, e.g. BSC, ETH
* @returns Fetch promise
*/
placeAtomicSwap = (
secretHash: string,
sourceNetworkCode: Uppercase<typeof networkCodes[number]>,
) => fetchWithValidation(
`${this.apiUrl}/api/v1/atomic-swap`,
placeAtomicSwapSchema,
{
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
method: 'POST',
body: JSON.stringify({
secretHash,
sourceNetworkCode,
}),
},
errorSchema,
);
/**
* Get placed atomic swaps. Each atomic swap received from this list has a target chain corresponding to this Orion Aggregator
* @param sender Sender address
* @returns Fetch promise
*/
getHistoryAtomicSwaps = (sender: string, limit = 1000) => {
const url = new URL(`${this.apiUrl}/api/v1/atomic-swap/history/all`);
url.searchParams.append('sender', sender);
url.searchParams.append('limit', limit.toString());
return fetchWithValidation(url.toString(), atomicSwapHistorySchema);
};
}
export * as schemas from './schemas';
export * as ws from './ws';
export { OrionAggregator };