Exchanges / more error messages

This commit is contained in:
Aleksandr Kraiz
2022-07-04 19:07:32 +04:00
parent 620e4a5ef7
commit 48ae67c1a8
14 changed files with 91 additions and 28 deletions

18
package-lock.json generated
View File

@@ -1,18 +1,18 @@
{
"name": "@orionprotocol/sdk",
"version": "0.12.4",
"version": "0.12.12",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@orionprotocol/sdk",
"version": "0.12.4",
"version": "0.12.12",
"license": "ISC",
"dependencies": {
"@ethersproject/abstract-signer": "^5.6.0",
"@ethersproject/providers": "^5.6.2",
"@lukeed/csprng": "^1.0.1",
"@orionprotocol/contracts": "0.0.8",
"@orionprotocol/contracts": "0.0.9",
"bignumber.js": "^9.0.2",
"buffer": "^6.0.3",
"crypto-browserify": "^3.12.0",
@@ -2485,9 +2485,9 @@
}
},
"node_modules/@orionprotocol/contracts": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/@orionprotocol/contracts/-/contracts-0.0.8.tgz",
"integrity": "sha512-dgfowYXTf2nu/o9wcQbnLZg+kF7mJusP62unGSxhRKjquVrF1qids+lpSyjvbA9KT/XYKbXg61tXOZ9pOdrBTw=="
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/@orionprotocol/contracts/-/contracts-0.0.9.tgz",
"integrity": "sha512-mMnds/0clCcGDr7+LW6SyTKzrxm1o6Hkksi6m6XBeIXkMGjnfMTApoC3b+/sniHuXTgplkb08ecSyz6VPgII2g=="
},
"node_modules/@sinonjs/commons": {
"version": "1.8.3",
@@ -12131,9 +12131,9 @@
}
},
"@orionprotocol/contracts": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/@orionprotocol/contracts/-/contracts-0.0.8.tgz",
"integrity": "sha512-dgfowYXTf2nu/o9wcQbnLZg+kF7mJusP62unGSxhRKjquVrF1qids+lpSyjvbA9KT/XYKbXg61tXOZ9pOdrBTw=="
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/@orionprotocol/contracts/-/contracts-0.0.9.tgz",
"integrity": "sha512-mMnds/0clCcGDr7+LW6SyTKzrxm1o6Hkksi6m6XBeIXkMGjnfMTApoC3b+/sniHuXTgplkb08ecSyz6VPgII2g=="
},
"@sinonjs/commons": {
"version": "1.8.3",

View File

@@ -1,6 +1,6 @@
{
"name": "@orionprotocol/sdk",
"version": "0.12.12",
"version": "0.12.13",
"description": "Orion Protocol SDK",
"main": "./lib/esm/index.js",
"module": "./lib/esm/index.js",
@@ -60,7 +60,7 @@
"@ethersproject/abstract-signer": "^5.6.0",
"@ethersproject/providers": "^5.6.2",
"@lukeed/csprng": "^1.0.1",
"@orionprotocol/contracts": "0.0.8",
"@orionprotocol/contracts": "0.0.9",
"bignumber.js": "^9.0.2",
"buffer": "^6.0.3",
"crypto-browserify": "^3.12.0",

View File

@@ -94,6 +94,7 @@ export default async function getSwapMarketFeeInfo({
}
const [baseAssetName] = swapInfo.orderInfo.assetPair.split('-');
if (baseAssetName === undefined) throw new Error('Base asset name is undefined');
const baseAssetAddress = assetToAddress[baseAssetName];
if (!baseAssetAddress) throw new Error(`No asset address for ${baseAssetName}`);

View File

@@ -86,6 +86,8 @@ export default async function swapMarket({
const feeAssets = await simpleFetch(orionBlockchain.getTokensFee)();
const pricesInOrn = await simpleFetch(orionBlockchain.getPrices)();
const gasPriceWei = await simpleFetch(orionBlockchain.getGasPriceWei)();
const { factories } = await simpleFetch(orionBlockchain.getPoolsConfig)();
const poolExchangesList = factories !== undefined ? Object.keys(factories) : [];
const gasPriceGwei = ethers.utils.formatUnits(gasPriceWei, 'gwei').toString();
@@ -125,6 +127,12 @@ export default async function swapMarket({
options?.poolOnly ? ['ORION_POOL'] : undefined,
);
const { exchanges: swapExchanges } = swapInfo;
const firstSwapExchange = swapExchanges?.[0];
if (swapExchanges) options?.logger?.(`Swap exchanges: ${swapExchanges.join(', ')}`);
if (swapInfo.orderInfo !== null && options?.poolOnly === true && options.poolOnly !== swapInfo.isThroughPoolOptimal) {
throw new Error(`Unexpected Orion Aggregator response. Please, contact support. Report swap request id: ${swapInfo.id}`);
}
@@ -139,16 +147,49 @@ export default async function swapMarket({
if (swapInfo.orderInfo === null) throw new Error(swapInfo.executionInfo);
const [baseAssetName, quoteAssetName] = swapInfo.orderInfo.assetPair.split('-');
if (baseAssetName === undefined) throw new Error('Base asset name is undefined');
if (quoteAssetName === undefined) throw new Error('Quote asset name is undefined');
const pairConfig = await simpleFetch(orionAggregator.getPairConfig)(`${baseAssetName}-${quoteAssetName}`);
if (!pairConfig) throw new Error(`Pair config ${baseAssetName}-${quoteAssetName} not found`);
const qtyPrecisionBN = new BigNumber(pairConfig.qtyPrecision);
const qtyDecimalPlaces = amountBN.dp();
if (qtyPrecisionBN.lt(qtyDecimalPlaces)) throw new Error(`Actual amount decimal places (${qtyDecimalPlaces}) is greater than max allowed decimal places (${qtyPrecisionBN.toString()}) on pair ${baseAssetName}-${quoteAssetName}`);
const percent = new BigNumber(slippagePercent).div(100);
let isThroughPoolOptimal: boolean;
if (options?.developer?.route !== undefined) {
isThroughPoolOptimal = options.developer.route === 'pool';
} else if (options?.poolOnly) isThroughPoolOptimal = true;
else isThroughPoolOptimal = swapInfo.isThroughPoolOptimal;
options?.logger?.('Swap is through pool (because route forced to pool)');
} else if (options?.poolOnly) {
options?.logger?.('Swap is through pool (because "poolOnly" option is true)');
isThroughPoolOptimal = true;
} else if (
swapExchanges !== undefined
&& poolExchangesList.length > 0
&& swapExchanges.length === 1
&& firstSwapExchange
&& poolExchangesList.some((poolExchange) => poolExchange === firstSwapExchange)
) {
options?.logger?.(`Swap is through pool [via ${firstSwapExchange}] (detected by "exchanges" field)`);
isThroughPoolOptimal = true;
} else {
if (swapInfo.isThroughPoolOptimal) options?.logger?.('Swap is through pool (detected by "isThroughPoolOptimal" field)');
isThroughPoolOptimal = swapInfo.isThroughPoolOptimal;
}
if (isThroughPoolOptimal) {
options?.logger?.('Swap through pool');
let factoryAddress: string | undefined;
if (factories && firstSwapExchange) {
factoryAddress = factories?.[firstSwapExchange];
if (factoryAddress) options?.logger?.(`Factory address is ${factoryAddress}. Exchange is ${firstSwapExchange}`);
}
const pathAddresses = swapInfo.path.map((name) => {
const assetAddress = assetToAddress?.[name];
if (!assetAddress) throw new Error(`No asset address for ${name}`);
@@ -189,7 +230,7 @@ export default async function swapMarket({
const unsignedSwapThroughOrionPoolTx = await exchangeContract.populateTransaction.swapThroughOrionPool(
amountSpendBlockchainParam,
amountReceiveBlockchainParam,
pathAddresses,
factoryAddress ? [factoryAddress, ...pathAddresses] : pathAddresses,
type === 'exactSpend',
);
@@ -244,6 +285,7 @@ export default async function swapMarket({
options?.logger?.('Signing transaction...');
const swapThroughOrionPoolTxResponse = await signer.sendTransaction(unsignedSwapThroughOrionPoolTx);
options?.logger?.(`Transaction sent. Tx hash: ${swapThroughOrionPoolTxResponse.hash}`);
return {
through: 'orion_pool',
txHash: swapThroughOrionPoolTxResponse.hash,
@@ -263,10 +305,6 @@ export default async function swapMarket({
.multipliedBy(slippageMultiplier)
.toString();
const [baseAssetName, quoteAssetName] = swapInfo.orderInfo.assetPair.split('-');
const pairConfig = await simpleFetch(orionAggregator.getPairConfig)(`${baseAssetName}-${quoteAssetName}`);
if (!pairConfig) throw new Error(`Pair config ${baseAssetName}-${quoteAssetName} not found`);
const baseAssetAddress = assetToAddress[baseAssetName];
if (!baseAssetAddress) throw new Error(`No asset address for ${baseAssetName}`);
const quoteAssetAddress = assetToAddress[quoteAssetName];
@@ -361,6 +399,8 @@ export default async function swapMarket({
if (!orderIsOk) throw new Error('Order is not valid');
const { orderId } = await simpleFetch(orionAggregator.placeOrder)(signedOrder, false);
options?.logger?.(`Order placed. Order id: ${orderId}`);
return {
through: 'aggregator',
id: orderId,

View File

@@ -41,6 +41,8 @@ export default class FarmingManager {
if (amountBN.lte(0)) throw new Error('Amount must be greater than 0');
if (!poolName.includes('-')) throw new Error('Pool name must be in the format of "assetA-AssetB"');
const [assetA, assetB] = poolName.split('-');
if (assetA === undefined) throw new Error('Asset A undefined');
if (assetB === undefined) throw new Error('Asset B undefined');
if (amountAsset !== assetA && amountAsset !== assetB) throw new Error('Amount asset must be either assetA or assetB');
const {
@@ -219,6 +221,8 @@ export default class FarmingManager {
}: RemoveAllLiquidityParams) {
if (!poolName.includes('-')) throw new Error('Pool name must be in the format of "assetA-AssetB"');
const [assetA, assetB] = poolName.split('-');
if (assetA === undefined) throw new Error('Asset A is not defined');
if (assetB === undefined) throw new Error('Asset B is not defined');
const {
assetToAddress,

View File

@@ -74,6 +74,7 @@ export default class OrionUnit {
} else {
const envInfo = envs[env];
const envNetworks = envInfo?.networks;
if (envNetworks === undefined) throw new Error('Env networks is undefined (constructor)');
if (isValidChainId(chain)) chainId = chain;
else {
@@ -94,7 +95,9 @@ export default class OrionUnit {
: `Chains not found for chain name '${chain}' in env '${env}'.`,
);
}
[chainId] = targetChains;
const firstTargetChain = targetChains[0];
if (firstTargetChain === undefined) throw new Error('First target chain is undefined');
chainId = firstTargetChain;
}
if (!(chainId in envNetworks)) {
@@ -145,6 +148,8 @@ export default class OrionUnit {
const envInfo = envs[this.env];
const envNetworks = envInfo?.networks;
if (envNetworks === undefined) throw new Error('Env networks is undefined (siblings)');
const siblingsNetworks = Object
.keys(envNetworks)
.filter(isValidChainId)

View File

@@ -1,6 +1,6 @@
import BigNumber from 'bignumber.js';
BigNumber.config({ EXPONENTIAL_AT: 1e9 });
BigNumber.config({ EXPONENTIAL_AT: 1e+9 });
export * as config from './config';
export { default as OrionUnit } from './OrionUnit';

View File

@@ -15,6 +15,7 @@ const swapInfoBase = z.object({
amount: z.number(),
safePrice: z.number(),
}).nullable(),
exchanges: z.array(z.string()).optional(),
price: z.number().nullable(), // spending asset price
minAmountOut: z.number(),
minAmountIn: z.number(),

View File

@@ -329,6 +329,7 @@ class OrionAggregatorWS {
minAmounOut: json.mao,
minAmounIn: json.ma,
path: json.ps,
exchanges: json.e,
poolOptimal: json.po,
...json.oi && {
orderInfo: {
@@ -399,13 +400,13 @@ class OrionAggregatorWS {
break;
case MessageType.ASSET_PAIRS_CONFIG_UPDATE: {
const pairs = json;
let priceUpdates: Partial<Record<string, AssetPairUpdate>> = {};
const priceUpdates: Partial<Record<string, AssetPairUpdate>> = {};
pairs.u.forEach(([pairName, minQty, pricePrecision]) => {
priceUpdates[pairName] = {
minQty,
pricePrecision,
}
};
});
this.subscriptions[
@@ -425,7 +426,7 @@ class OrionAggregatorWS {
prev[asset] = {
tradable, reserved, contract, wallet, allowance,
}
};
return prev;
}, {})
@@ -437,7 +438,7 @@ class OrionAggregatorWS {
const fullOrder = mapFullOrder(o);
prev.push(fullOrder);
return prev;
}, [])
: undefined;
@@ -475,10 +476,10 @@ class OrionAggregatorWS {
}
break;
case MessageType.BROKER_TRADABLE_ATOMIC_SWAP_ASSETS_BALANCE_UPDATE: {
let brokerBalances: Partial<Record<string, number>> = {};
const brokerBalances: Partial<Record<string, number>> = {};
json.bb.forEach(([asset, balance]) => {
brokerBalances[asset] = balance
brokerBalances[asset] = balance;
});
this.subscriptions[

View File

@@ -13,7 +13,7 @@ const swapInfoSchemaBase = baseMessageSchema.extend({
mao: z.number(), // min amount out
ps: z.string().array(), // path
po: z.boolean(), // is swap through pool optimal
e: z.string().array().optional(), // Exchanges
p: z.number().optional(), // price
mp: z.number().optional(), // market price
oi: z.object({ // info about order equivalent to this swap

View File

@@ -1,3 +1,4 @@
import { ethers } from 'ethers';
import { z } from 'zod';
import { makePartial } from '../../../utils';
@@ -7,6 +8,12 @@ const poolsConfigSchema = z.object({
governanceAddress: z.string(),
routerAddress: z.string(),
votingAddress: z.string(),
factories: z.record(
z.string(),
z.string().refine(ethers.utils.isAddress, 'Factory should be an address'),
)
.transform(makePartial)
.optional(),
pools: z.record(
z.string(),
z.object({

View File

@@ -112,6 +112,7 @@ export type SwapInfoBase = {
minAmounOut: number,
path: string[],
exchanges?: string[],
poolOptimal: boolean,
price?: number,

View File

@@ -6,6 +6,8 @@ export default function isNetworkCodeInEnvironment(networkCode: string, env: str
}
const envInfo = envs[env];
const envNetworks = envInfo?.networks;
if (envNetworks === undefined) throw new Error('Env networks is undefined (isNetworkCodeInEnvironment)');
return Object.values(chains)
.some((chain) => chain.code.toLowerCase() === networkCode.toLowerCase()
&& chain.chainId in envNetworks);

View File

@@ -100,6 +100,7 @@
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"noUncheckedIndexedAccess": true,
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}