From e4d523e220527517bf798d959957c4c739d745b8 Mon Sep 17 00:00:00 2001 From: Kirill Litvinov Date: Mon, 31 Jul 2023 22:49:32 +0300 Subject: [PATCH 01/17] prices with quote asset --- package.json | 4 ++-- src/Unit/Exchange/getSwapInfo.ts | 20 +++++++++---------- src/Unit/Exchange/swapLimit.ts | 20 +++++++++---------- src/Unit/Exchange/swapMarket.ts | 20 +++++++++---------- src/services/BlockchainService/index.ts | 9 +++++---- .../BlockchainService/schemas/index.ts | 1 + .../schemas/pricesWithQuoteAssetSchema.ts | 7 +++++++ 7 files changed, 45 insertions(+), 36 deletions(-) create mode 100644 src/services/BlockchainService/schemas/pricesWithQuoteAssetSchema.ts diff --git a/package.json b/package.json index 336812e..8fdfd98 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.19.40", + "version": "0.19.41-rc1", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", @@ -108,4 +108,4 @@ "overrides": { "tsconfig-paths": "^4.0.0" } -} \ No newline at end of file +} diff --git a/src/Unit/Exchange/getSwapInfo.ts b/src/Unit/Exchange/getSwapInfo.ts index 08108d1..4926723 100644 --- a/src/Unit/Exchange/getSwapInfo.ts +++ b/src/Unit/Exchange/getSwapInfo.ts @@ -46,7 +46,7 @@ export default async function getSwapInfo({ const nativeCryptocurrencyName = getNativeCryptocurrencyName(assetToAddress); const feeAssets = await simpleFetch(blockchainService.getTokensFee)(); - const pricesInOrn = await simpleFetch(blockchainService.getPrices)(); + const allPrices = await simpleFetch(blockchainService.getPricesWithQuoteAsset)(); const gasPriceWei = await simpleFetch(blockchainService.getGasPriceWei)(); const gasPriceGwei = ethers.utils.formatUnits(gasPriceWei, 'gwei').toString(); @@ -121,12 +121,12 @@ export default async function getSwapInfo({ if (baseAssetAddress === undefined) throw new Error(`No asset address for ${baseAssetName}`); // Fee calculation - const baseAssetPriceInOrn = pricesInOrn[baseAssetAddress]; - if (baseAssetPriceInOrn === undefined) throw new Error(`Base asset price ${baseAssetName} in ORN not found`); - const baseCurrencyPriceInOrn = pricesInOrn[ethers.constants.AddressZero]; - if (baseCurrencyPriceInOrn === undefined) throw new Error('Base currency price in ORN not found'); - const feeAssetPriceInOrn = pricesInOrn[feeAssetAddress]; - if (feeAssetPriceInOrn === undefined) throw new Error(`Fee asset price ${feeAsset} in ORN not found`); + const baseAssetPriceInQuoteAsset = allPrices.prices[baseAssetAddress]; + if (baseAssetPriceInQuoteAsset === undefined) throw new Error(`Base asset price ${baseAssetName} in ${allPrices.quoteAsset} not found`); + const baseCurrencyPriceInQuoteAsset = allPrices.prices[ethers.constants.AddressZero]; + if (baseCurrencyPriceInQuoteAsset === undefined) throw new Error(`Base currency price in ${allPrices.quoteAsset} not found`); + const feeAssetPriceInQuoteAsset = allPrices.prices[feeAssetAddress]; + if (feeAssetPriceInQuoteAsset === undefined) throw new Error(`Fee asset price ${feeAsset} in ${allPrices.quoteAsset} not found`); const feePercent = feeAssets[feeAsset]; if (feePercent === undefined) throw new Error(`Fee asset ${feeAsset} not available`); @@ -135,9 +135,9 @@ export default async function getSwapInfo({ networkFeeInFeeAsset, } = calculateFeeInFeeAsset( swapInfo.orderInfo.amount, - feeAssetPriceInOrn, - baseAssetPriceInOrn, - baseCurrencyPriceInOrn, + feeAssetPriceInQuoteAsset, + baseAssetPriceInQuoteAsset, + baseCurrencyPriceInQuoteAsset, gasPriceGwei, feePercent, ); diff --git a/src/Unit/Exchange/swapLimit.ts b/src/Unit/Exchange/swapLimit.ts index a3520eb..dc48625 100644 --- a/src/Unit/Exchange/swapLimit.ts +++ b/src/Unit/Exchange/swapLimit.ts @@ -90,7 +90,7 @@ export default async function swapLimit({ const exchangeContract = Exchange__factory.connect(exchangeContractAddress, provider); const feeAssets = await simpleFetch(blockchainService.getTokensFee)(); - const pricesInOrn = await simpleFetch(blockchainService.getPrices)(); + const allPrices = await simpleFetch(blockchainService.getPricesWithQuoteAsset)(); const gasPriceWei = await simpleFetch(blockchainService.getGasPriceWei)(); const { factories } = await simpleFetch(blockchainService.getPoolsConfig)(); const poolExchangesList = factories !== undefined ? Object.keys(factories) : []; @@ -372,20 +372,20 @@ export default async function swapLimit({ }); // Fee calculation - const baseAssetPriceInOrn = pricesInOrn[baseAssetAddress]; - if (baseAssetPriceInOrn === undefined) throw new Error(`Base asset price ${baseAssetName} in ORN not found`); - const baseCurrencyPriceInOrn = pricesInOrn[ethers.constants.AddressZero]; - if (baseCurrencyPriceInOrn === undefined) throw new Error('Base currency price in ORN not found'); - const feeAssetPriceInOrn = pricesInOrn[feeAssetAddress]; - if (feeAssetPriceInOrn === undefined) throw new Error(`Fee asset price ${feeAsset} in ORN not found`); + const baseAssetPriceInQuoteAsset = allPrices.prices[baseAssetAddress]; + if (baseAssetPriceInQuoteAsset === undefined) throw new Error(`Base asset price ${baseAssetName} in ${allPrices.quoteAsset} not found`); + const baseCurrencyPriceInQuoteAsset = allPrices.prices[ethers.constants.AddressZero]; + if (baseCurrencyPriceInQuoteAsset === undefined) throw new Error(`Base currency price in ${allPrices.quoteAsset} not found`); + const feeAssetPriceInQuoteAsset = allPrices.prices[feeAssetAddress]; + if (feeAssetPriceInQuoteAsset === undefined) throw new Error(`Fee asset price ${feeAsset} in ${allPrices.quoteAsset} not found`); const feePercent = feeAssets[feeAsset]; if (feePercent === undefined) throw new Error(`Fee asset ${feeAsset} not available`); const { serviceFeeInFeeAsset, networkFeeInFeeAsset, totalFeeInFeeAsset } = calculateFeeInFeeAsset( swapInfo.orderInfo.amount, - feeAssetPriceInOrn, - baseAssetPriceInOrn, - baseCurrencyPriceInOrn, + feeAssetPriceInQuoteAsset, + baseAssetPriceInQuoteAsset, + baseCurrencyPriceInQuoteAsset, gasPriceGwei, feePercent, ); diff --git a/src/Unit/Exchange/swapMarket.ts b/src/Unit/Exchange/swapMarket.ts index c90d22d..245c859 100644 --- a/src/Unit/Exchange/swapMarket.ts +++ b/src/Unit/Exchange/swapMarket.ts @@ -75,7 +75,7 @@ export default async function swapMarket({ const exchangeContract = Exchange__factory.connect(exchangeContractAddress, provider); const feeAssets = await simpleFetch(blockchainService.getTokensFee)(); - const pricesInOrn = await simpleFetch(blockchainService.getPrices)(); + const allPrices = await simpleFetch(blockchainService.getPricesWithQuoteAsset)(); const gasPriceWei = await simpleFetch(blockchainService.getGasPriceWei)(); const { factories } = await simpleFetch(blockchainService.getPoolsConfig)(); const poolExchangesList = factories !== undefined ? Object.keys(factories) : []; @@ -330,20 +330,20 @@ export default async function swapMarket({ }); // Fee calculation - const baseAssetPriceInOrn = pricesInOrn[baseAssetAddress]; - if (baseAssetPriceInOrn === undefined) throw new Error(`Base asset price ${baseAssetName} in ORN not found`); - const baseCurrencyPriceInOrn = pricesInOrn[ethers.constants.AddressZero]; - if (baseCurrencyPriceInOrn === undefined) throw new Error('Base currency price in ORN not found'); - const feeAssetPriceInOrn = pricesInOrn[feeAssetAddress]; - if (feeAssetPriceInOrn === undefined) throw new Error(`Fee asset price ${feeAsset} in ORN not found`); + const baseAssetPriceInQuoteAsset = allPrices.prices[baseAssetAddress]; + if (baseAssetPriceInQuoteAsset === undefined) throw new Error(`Base asset price ${baseAssetName} in ${allPrices.quoteAsset}not found`); + const baseCurrencyPriceInQuoteAsset = allPrices.prices[ethers.constants.AddressZero]; + if (baseCurrencyPriceInQuoteAsset === undefined) throw new Error(`Base currency price in ${allPrices.quoteAsset} not found`); + const feeAssetPriceInQuoteAsset = allPrices.prices[feeAssetAddress]; + if (feeAssetPriceInQuoteAsset === undefined) throw new Error(`Fee asset price ${feeAsset} in ${allPrices.quoteAsset} not found`); const feePercent = feeAssets[feeAsset]; if (feePercent === undefined) throw new Error(`Fee asset ${feeAsset} not available`); const { serviceFeeInFeeAsset, networkFeeInFeeAsset, totalFeeInFeeAsset } = calculateFeeInFeeAsset( swapInfo.orderInfo.amount, - feeAssetPriceInOrn, - baseAssetPriceInOrn, - baseCurrencyPriceInOrn, + feeAssetPriceInQuoteAsset, + baseAssetPriceInQuoteAsset, + baseCurrencyPriceInQuoteAsset, gasPriceGwei, feePercent, ); diff --git a/src/services/BlockchainService/index.ts b/src/services/BlockchainService/index.ts index c4b6e5b..6e7bd19 100644 --- a/src/services/BlockchainService/index.ts +++ b/src/services/BlockchainService/index.ts @@ -13,6 +13,7 @@ import { governancePoolsSchema, governancePoolSchema, governanceChainsInfoSchema, + pricesWithQuoteAssetSchema, } from './schemas/index.js'; import type redeemOrderSchema from '../Aggregator/schemas/redeemOrderSchema.js'; import { sourceAtomicHistorySchema, targetAtomicHistorySchema } from './schemas/atomicHistorySchema.js'; @@ -81,7 +82,7 @@ class BlockchainService { this.getUserVotes = this.getUserVotes.bind(this); this.getUserEarned = this.getUserEarned.bind(this); this.getHistory = this.getHistory.bind(this); - this.getPrices = this.getPrices.bind(this); + this.getPricesWithQuoteAsset = this.getPricesWithQuoteAsset.bind(this); this.getTokensFee = this.getTokensFee.bind(this); this.getGasPriceWei = this.getGasPriceWei.bind(this); this.checkFreeRedeemAvailable = this.checkFreeRedeemAvailable.bind(this); @@ -206,9 +207,9 @@ class BlockchainService { { headers: this.basicAuthHeaders } ); - getPrices = () => fetchWithValidation( - `${this.apiUrl}/api/prices`, - z.record(z.string()).transform(makePartial), + getPricesWithQuoteAsset = () => fetchWithValidation( + `http://localhost:57303/prices.json`, + pricesWithQuoteAssetSchema, { headers: this.basicAuthHeaders } ); diff --git a/src/services/BlockchainService/schemas/index.ts b/src/services/BlockchainService/schemas/index.ts index 5da72eb..ee8a122 100644 --- a/src/services/BlockchainService/schemas/index.ts +++ b/src/services/BlockchainService/schemas/index.ts @@ -16,3 +16,4 @@ export { default as governanceContractsSchema } from './governanceContractsSchem export { default as governancePoolsSchema } from './governancePoolsSchema.js'; export { default as governancePoolSchema } from './governancePoolSchema.js'; export { default as governanceChainsInfoSchema } from './governanceChainsInfoSchema.js'; +export { pricesWithQuoteAssetSchema } from './pricesWithQuoteAssetSchema.js'; diff --git a/src/services/BlockchainService/schemas/pricesWithQuoteAssetSchema.ts b/src/services/BlockchainService/schemas/pricesWithQuoteAssetSchema.ts new file mode 100644 index 0000000..e91cb19 --- /dev/null +++ b/src/services/BlockchainService/schemas/pricesWithQuoteAssetSchema.ts @@ -0,0 +1,7 @@ +import { z } from 'zod'; +import { makePartial } from '../../../utils/index.js'; + +export const pricesWithQuoteAssetSchema = z.object({ + quoteAsset: z.string(), + prices: z.record(z.string()).transform(makePartial) +}); From 16d2039b9475cd0cb17f12e3a782e37d11c82bca Mon Sep 17 00:00:00 2001 From: Kirill Litvinov Date: Mon, 31 Jul 2023 23:02:42 +0300 Subject: [PATCH 02/17] fix --- src/services/BlockchainService/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/BlockchainService/index.ts b/src/services/BlockchainService/index.ts index e2b091c..c71ccef 100644 --- a/src/services/BlockchainService/index.ts +++ b/src/services/BlockchainService/index.ts @@ -216,7 +216,7 @@ class BlockchainService { ); getPricesWithQuoteAsset = () => fetchWithValidation( - `http://localhost:57303/prices.json`, + `${this.apiUrl}/api/prices`, pricesWithQuoteAssetSchema, { headers: this.basicAuthHeaders } ); From b32957f5289058ff448139eab447a313724a41f2 Mon Sep 17 00:00:00 2001 From: Kirill Litvinov Date: Mon, 31 Jul 2023 23:04:04 +0300 Subject: [PATCH 03/17] bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2526764..3f5c8b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.19.42-rc1", + "version": "0.19.42-rc2", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", From 7eebb2bb9e125582bb465ab770a3a0028219eba8 Mon Sep 17 00:00:00 2001 From: Kirill Litvinov Date: Tue, 1 Aug 2023 16:19:52 +0300 Subject: [PATCH 04/17] fee calculation --- package.json | 2 +- src/Unit/Exchange/getSwapInfo.ts | 2 ++ src/Unit/Exchange/swapLimit.ts | 2 ++ src/Unit/Exchange/swapMarket.ts | 2 ++ src/utils/calculateFeeInFeeAsset.ts | 23 +++++++++++++++------- src/utils/calculateNetworkFeeInFeeAsset.ts | 14 ++++++------- src/utils/calculateServiceFeeInFeeAsset.ts | 9 +++++---- 7 files changed, 34 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 3f5c8b4..8387e0e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.19.42-rc2", + "version": "0.19.42-rc3", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", diff --git a/src/Unit/Exchange/getSwapInfo.ts b/src/Unit/Exchange/getSwapInfo.ts index 4926723..4689f20 100644 --- a/src/Unit/Exchange/getSwapInfo.ts +++ b/src/Unit/Exchange/getSwapInfo.ts @@ -140,6 +140,8 @@ export default async function getSwapInfo({ baseCurrencyPriceInQuoteAsset, gasPriceGwei, feePercent, + feeAssetAddress, + allPrices.prices, ); return { diff --git a/src/Unit/Exchange/swapLimit.ts b/src/Unit/Exchange/swapLimit.ts index dc48625..a821401 100644 --- a/src/Unit/Exchange/swapLimit.ts +++ b/src/Unit/Exchange/swapLimit.ts @@ -388,6 +388,8 @@ export default async function swapLimit({ baseCurrencyPriceInQuoteAsset, gasPriceGwei, feePercent, + feeAsset, + allPrices.prices, ); if (feeAsset === assetOut) { diff --git a/src/Unit/Exchange/swapMarket.ts b/src/Unit/Exchange/swapMarket.ts index 245c859..45d061a 100644 --- a/src/Unit/Exchange/swapMarket.ts +++ b/src/Unit/Exchange/swapMarket.ts @@ -346,6 +346,8 @@ export default async function swapMarket({ baseCurrencyPriceInQuoteAsset, gasPriceGwei, feePercent, + feeAsset, + allPrices.prices, ); if (feeAsset === assetOut) { diff --git a/src/utils/calculateFeeInFeeAsset.ts b/src/utils/calculateFeeInFeeAsset.ts index e4a6da9..c93e4ab 100644 --- a/src/utils/calculateFeeInFeeAsset.ts +++ b/src/utils/calculateFeeInFeeAsset.ts @@ -5,23 +5,32 @@ import calculateServiceFeeInFeeAsset from './calculateServiceFeeInFeeAsset.js'; const calculateFeeInFeeAsset = ( amount: BigNumber.Value, - feeAssetPriceInServiceToken: BigNumber.Value, - baseAssetPriceInServiceToken: BigNumber.Value, - baseCurrencyPriceInServiceToken: BigNumber.Value, + feeAssetPrice: BigNumber.Value, + baseAssetPrice: BigNumber.Value, + baseCurrencyPrice: BigNumber.Value, gasPriceGwei: BigNumber.Value, feePercent: BigNumber.Value, + feeAsset: string, + assetPrices: Partial>, ) => { + const feeAssetPriceInQuoteAsset = assetPrices[feeAsset]; + if (feeAssetPriceInQuoteAsset === undefined) throw Error('feeAssetPriceInQuoteAsset is undefined'); + + const feeAssetPriceInQuoteAssetBN = new BigNumber(feeAssetPriceInQuoteAsset); + const serviceFeeInFeeAsset = calculateServiceFeeInFeeAsset( amount, - feeAssetPriceInServiceToken, - baseAssetPriceInServiceToken, + feeAssetPrice, + baseAssetPrice, feePercent, + feeAssetPriceInQuoteAssetBN ); const networkFeeInFeeAsset = calculateNetworkFeeInFeeAsset( gasPriceGwei, FILL_ORDERS_GAS_LIMIT, - baseCurrencyPriceInServiceToken, - feeAssetPriceInServiceToken, + baseCurrencyPrice, + feeAssetPrice, + feeAssetPriceInQuoteAssetBN ); return { diff --git a/src/utils/calculateNetworkFeeInFeeAsset.ts b/src/utils/calculateNetworkFeeInFeeAsset.ts index 23b611c..07ddc81 100644 --- a/src/utils/calculateNetworkFeeInFeeAsset.ts +++ b/src/utils/calculateNetworkFeeInFeeAsset.ts @@ -4,17 +4,15 @@ import calculateNetworkFee from './calculateNetworkFee.js'; const calculateNetworkFeeInFeeAsset = ( gasPriceGwei: BigNumber.Value, gasLimit: BigNumber.Value, - baseCurrencyPriceInServiceToken: BigNumber.Value, - feeAssetPriceInServiceToken: BigNumber.Value, + baseCurrencyPrice: BigNumber.Value, + feeAssetPrice: BigNumber.Value, + feeAssetPriceInQuoteAsset: BigNumber.Value, ) => { const networkFee = calculateNetworkFee(gasPriceGwei, gasLimit); - const networkFeeInServiceToken = new BigNumber(networkFee).multipliedBy(baseCurrencyPriceInServiceToken); - const networkFeeInFeeAsset = networkFeeInServiceToken - .multipliedBy( - new BigNumber(1) - .div(feeAssetPriceInServiceToken), - ); + const networkFeeInQuoteAsset = new BigNumber(networkFee).multipliedBy(baseCurrencyPrice); + const networkFeeInFeeAsset = networkFeeInQuoteAsset + .div(new BigNumber(feeAssetPriceInQuoteAsset).multipliedBy(feeAssetPrice)); return networkFeeInFeeAsset.toString(); }; diff --git a/src/utils/calculateServiceFeeInFeeAsset.ts b/src/utils/calculateServiceFeeInFeeAsset.ts index 4cad980..e4e51b3 100644 --- a/src/utils/calculateServiceFeeInFeeAsset.ts +++ b/src/utils/calculateServiceFeeInFeeAsset.ts @@ -2,14 +2,15 @@ import { BigNumber } from 'bignumber.js'; export default function calculateServiceFeeInFeeAsset( amount: BigNumber.Value, - feeAssetPriceInServiceToken: BigNumber.Value, - baseAssetPriceInServiceToken: BigNumber.Value, + feeAssetPrice: BigNumber.Value, + baseAssetPrice: BigNumber.Value, feePercent: BigNumber.Value, + feeAssetPriceInQuoteAsset: BigNumber.Value, ) { const result = new BigNumber(amount) .multipliedBy(new BigNumber(feePercent).div(100)) - .multipliedBy(baseAssetPriceInServiceToken) - .multipliedBy(new BigNumber(1).div(feeAssetPriceInServiceToken)) + .multipliedBy(baseAssetPrice) + .div(new BigNumber(feeAssetPriceInQuoteAsset).multipliedBy(feeAssetPrice)) .toString(); return result; From f9605e3d1ae27e6269658cf17d219ac72f4e5d13 Mon Sep 17 00:00:00 2001 From: Aleksandr Kraiz Date: Tue, 1 Aug 2023 21:27:17 +0400 Subject: [PATCH 05/17] Calculate fee --- src/Unit/Exchange/getSwapInfo.ts | 7 +- src/Unit/Exchange/swapLimit.ts | 11 +- src/Unit/Exchange/swapMarket.ts | 11 +- src/__tests__/fee.test.ts | 132 +++++++++++++++++++++ src/services/Aggregator/ws/index.ts | 2 +- src/utils/calculateFeeInFeeAsset.ts | 31 ++--- src/utils/calculateNetworkFeeInFeeAsset.ts | 20 ++-- src/utils/calculateServiceFeeInFeeAsset.ts | 22 ++-- src/utils/convertPrice.ts | 26 ++++ 9 files changed, 212 insertions(+), 50 deletions(-) create mode 100644 src/__tests__/fee.test.ts create mode 100644 src/utils/convertPrice.ts diff --git a/src/Unit/Exchange/getSwapInfo.ts b/src/Unit/Exchange/getSwapInfo.ts index 4689f20..4077fec 100644 --- a/src/Unit/Exchange/getSwapInfo.ts +++ b/src/Unit/Exchange/getSwapInfo.ts @@ -135,13 +135,12 @@ export default async function getSwapInfo({ networkFeeInFeeAsset, } = calculateFeeInFeeAsset( swapInfo.orderInfo.amount, - feeAssetPriceInQuoteAsset, - baseAssetPriceInQuoteAsset, - baseCurrencyPriceInQuoteAsset, gasPriceGwei, feePercent, + baseAssetAddress, + ethers.constants.AddressZero, feeAssetAddress, - allPrices.prices, + allPrices.prices ); return { diff --git a/src/Unit/Exchange/swapLimit.ts b/src/Unit/Exchange/swapLimit.ts index a821401..741af96 100644 --- a/src/Unit/Exchange/swapLimit.ts +++ b/src/Unit/Exchange/swapLimit.ts @@ -383,12 +383,11 @@ export default async function swapLimit({ const { serviceFeeInFeeAsset, networkFeeInFeeAsset, totalFeeInFeeAsset } = calculateFeeInFeeAsset( swapInfo.orderInfo.amount, - feeAssetPriceInQuoteAsset, - baseAssetPriceInQuoteAsset, - baseCurrencyPriceInQuoteAsset, gasPriceGwei, feePercent, - feeAsset, + baseAssetAddress, + ethers.constants.AddressZero, + feeAssetAddress, allPrices.prices, ); @@ -405,7 +404,7 @@ export default async function swapLimit({ name: feeAsset, address: feeAssetAddress, }, - amount: networkFeeInFeeAsset, + amount: networkFeeInFeeAsset.toString(), spenderAddress: exchangeContractAddress, sources: getAvailableSources('network_fee', feeAssetAddress, 'aggregator'), }); @@ -416,7 +415,7 @@ export default async function swapLimit({ name: feeAsset, address: feeAssetAddress, }, - amount: serviceFeeInFeeAsset, + amount: serviceFeeInFeeAsset.toString(), spenderAddress: exchangeContractAddress, sources: getAvailableSources('service_fee', feeAssetAddress, 'aggregator'), }); diff --git a/src/Unit/Exchange/swapMarket.ts b/src/Unit/Exchange/swapMarket.ts index 45d061a..af6996c 100644 --- a/src/Unit/Exchange/swapMarket.ts +++ b/src/Unit/Exchange/swapMarket.ts @@ -341,12 +341,11 @@ export default async function swapMarket({ const { serviceFeeInFeeAsset, networkFeeInFeeAsset, totalFeeInFeeAsset } = calculateFeeInFeeAsset( swapInfo.orderInfo.amount, - feeAssetPriceInQuoteAsset, - baseAssetPriceInQuoteAsset, - baseCurrencyPriceInQuoteAsset, gasPriceGwei, feePercent, - feeAsset, + baseAssetAddress, + ethers.constants.AddressZero, + feeAssetAddress, allPrices.prices, ); @@ -363,7 +362,7 @@ export default async function swapMarket({ name: feeAsset, address: feeAssetAddress, }, - amount: networkFeeInFeeAsset, + amount: networkFeeInFeeAsset.toString(), spenderAddress: exchangeContractAddress, sources: getAvailableSources('network_fee', feeAssetAddress, 'aggregator'), }); @@ -374,7 +373,7 @@ export default async function swapMarket({ name: feeAsset, address: feeAssetAddress, }, - amount: serviceFeeInFeeAsset, + amount: serviceFeeInFeeAsset.toString(), spenderAddress: exchangeContractAddress, sources: getAvailableSources('service_fee', feeAssetAddress, 'aggregator'), }); diff --git a/src/__tests__/fee.test.ts b/src/__tests__/fee.test.ts new file mode 100644 index 0000000..eec8eeb --- /dev/null +++ b/src/__tests__/fee.test.ts @@ -0,0 +1,132 @@ +/* eslint-disable max-len */ +import { ethers } from 'ethers'; +import calculateFeeInFeeAsset from '../utils/calculateFeeInFeeAsset.js'; + +describe('Fee calculation', () => { + test('Dynamic quote asset', async () => { + const ornPrices = { + '0xf223eca06261145b3287a0fefd8cfad371c7eb34': '1', + '0xcb2951e90d8dcf16e1fa84ac0c83f48906d6a744': '1.57084511467169337103', + '0x0000000000000000000000000000000000000000': '386.899151743638077284689', + '0x4b9bfdde9dab73e6e2d2dc2ef55298c24588cce0': '1.0876374489475337731674617', + '0x108f6f65f5c258678c366383840c96679e1a0fbe': '45871.190700596921143469648', + '0xdf22ff6f5bf90e92f7074de1fa2e29dafe0087be': '2881.5111530003141690163011', + '0x03a2152a9aaacb96b82fdf03de0d643c3ecb28a7': '355.016417214333651756801351013730316783167', + '0x61a072dcc55d64da4cb910cfbc943cc3d42c2a1d': '1.571473452717562048378412', + '0xcd9f77d618dfdffdaed7f8023c34eb35ea86bf2b': '1.5712221174992145774390472', + '0x6cc5e1598f95e052ed021bbb0a1990ba485cdcce': '0.0374332390826264530316449', + '0x78867bbeef44f2326bf8ddd1941a4439382ef2a7': '1.566674947779146776937419747383627421398778019', + '0x3745553f445397dfbcb622192792491e6df67510': '130.71996892903857709354866649329101687558281412962786572513363298758635752124474785635955692', + '0x8447cda1d129ec040d094c011c3ac8b19f5c693b': '27.1071613903560920438050171526477214707556556810141836390412796594504062216941295811483058089915710982545331028', + '0x4fe5767ca2fe999e760dfd358614514a3219889a': '1.70174254929807881257423716231112230510407656790753360661237', + '0x2220b40a89efa6b0df48ed79d79203477132e371': '130.3525444094548794105350358066444422201669189500289668961281052404545221556', + '0xb0827f392d8c0852c0c6454bb9640cb989dcb93b': '64.400713005859731411119486616035862848696163238405378922467895263156517684272858763674589252508', + '0x47aac1c87e618915db97626f3960512515ce9e09': '437.31331069646443999899330475877673885912', + '0xc5d535dac5e3d56505fe331e2eba9842bbd19ee2': '13.6960254871019251168696037670276578586589975026010466153339830092462843027905620215383565464144808', + '0x0021588ea52535343f32e1b36c717e6233061bd4': '546.161187756536499998742736945784452977', + '0xdd301d6bb42be154bd940084ae86e14ca31436c3': '7.473234117200213999982796615062205107372', + '0xb9f5146b403bf70907c512c5e4d09e0565f577d1': '3.27853649699826360702741064013340499717660552707269386251', + '0xffd86d9ad101f1bce1090761f1574f991e6f49ee': '1.10275456361938750235372913100208822652' + }; + + const usdtPrices = { + '0xf223eca06261145b3287a0fefd8cfad371c7eb34': '0.6366000000000000000014654532', + '0xcb2951e90d8dcf16e1fa84ac0c83f48906d6a744': '1', + '0x0000000000000000000000000000000000000000': '246.3', + '0x4b9bfdde9dab73e6e2d2dc2ef55298c24588cce0': '0.69239', + '0x108f6f65f5c258678c366383840c96679e1a0fbe': '29201.6', + '0xdf22ff6f5bf90e92f7074de1fa2e29dafe0087be': '1834.37', + '0x03a2152a9aaacb96b82fdf03de0d643c3ecb28a7': '226.0034511986448027089', + '0x61a072dcc55d64da4cb910cfbc943cc3d42c2a1d': '1.0004', + '0xcd9f77d618dfdffdaed7f8023c34eb35ea86bf2b': '1.00024', + '0x6cc5e1598f95e052ed021bbb0a1990ba485cdcce': '0.02383', + '0x78867bbeef44f2326bf8ddd1941a4439382ef2a7': '0.9973452717562048382006573', + '0x3745553f445397dfbcb622192792491e6df67510': '83.21633222022595817794464509', + '0x8447cda1d129ec040d094c011c3ac8b19f5c693b': '17.25641894110068819512599820', + '0x4fe5767ca2fe999e760dfd358614514a3219889a': '1.083329306883156972087253202', + '0x2220b40a89efa6b0df48ed79d79203477132e371': '82.98242977105897623293762935', + '0xb0827f392d8c0852c0c6454bb9640cb989dcb93b': '40.99749389953030501641304141', + '0x47aac1c87e618915db97626f3960512515ce9e09': '278.393653589369262504', + '0xc5d535dac5e3d56505fe331e2eba9842bbd19ee2': '8.718889825089085529419260642', + '0x0021588ea52535343f32e1b36c717e6233061bd4': '347.6862121258111359', + '0xdd301d6bb42be154bd940084ae86e14ca31436c3': '4.7574608390096562324', + '0xb9f5146b403bf70907c512c5e4d09e0565f577d1': '2.087116333989094612238454155', + '0xffd86d9ad101f1bce1090761f1574f991e6f49ee': '0.702013555200102084' + }; + + const bnbPrices = { + '0xf223eca06261145b3287a0fefd8cfad371c7eb34': '0.002584652862362972', + '0xcb2951e90d8dcf16e1fa84ac0c83f48906d6a744': '0.004060089321965083', + '0x0000000000000000000000000000000000000000': '1.0', + '0x4b9bfdde9dab73e6e2d2dc2ef55298c24588cce0': '0.002811165245635404', + '0x108f6f65f5c258678c366383840c96679e1a0fbe': '118.56110434429557', + '0xdf22ff6f5bf90e92f7074de1fa2e29dafe0087be': '7.44770604953309', + '0x03a2152a9aaacb96b82fdf03de0d643c3ecb28a7': '0.9175941989388746', + '0x61a072dcc55d64da4cb910cfbc943cc3d42c2a1d': '0.004061713357693869', + '0xcd9f77d618dfdffdaed7f8023c34eb35ea86bf2b': '0.004061063743402355', + '0x6cc5e1598f95e052ed021bbb0a1990ba485cdcce': '9.675192854242793e-05', + '0x78867bbeef44f2326bf8ddd1941a4439382ef2a7': '0.004049310888169732', + '0x3745553f445397dfbcb622192792491e6df67510': '0.33786574186043833', + '0x8447cda1d129ec040d094c011c3ac8b19f5c693b': '0.07006260227811892', + '0x4fe5767ca2fe999e760dfd358614514a3219889a': '0.004398413751048141', + '0x2220b40a89efa6b0df48ed79d79203477132e371': '0.33691607702419396', + '0xb0827f392d8c0852c0c6454bb9640cb989dcb93b': '0.16645348720881162', + '0x47aac1c87e618915db97626f3960512515ce9e09': '1.1303031002410446', + '0xc5d535dac5e3d56505fe331e2eba9842bbd19ee2': '0.03539947147823421', + '0x0021588ea52535343f32e1b36c717e6233061bd4': '1.4116370772464926', + '0xdd301d6bb42be154bd940084ae86e14ca31436c3': '0.01931571595213015', + '0xb9f5146b403bf70907c512c5e4d09e0565f577d1': '0.008473878741328034', + '0xffd86d9ad101f1bce1090761f1574f991e6f49ee': '0.00285023773934268' + }; + + const amount = 1000; + const gasPriceGwei = 3; + const feePercent = 0.2; + const baseAssetAddress = '0xcb2951e90d8dcf16e1fa84ac0c83f48906d6a744'; + const baseCurrencyAddress = ethers.constants.AddressZero; + const feeAssetAddress = '0xf223eca06261145b3287a0fefd8cfad371c7eb34'; + const { totalFeeInFeeAsset: ornTotalFee } = calculateFeeInFeeAsset( + amount, + gasPriceGwei, + feePercent, + baseAssetAddress, + baseCurrencyAddress, + feeAssetAddress, + ornPrices + ); + + const { totalFeeInFeeAsset: bnbTotalFee } = calculateFeeInFeeAsset( + amount, + gasPriceGwei, + feePercent, + baseAssetAddress, + baseCurrencyAddress, + feeAssetAddress, + bnbPrices + ); + const { totalFeeInFeeAsset: usdtTotalFee } = calculateFeeInFeeAsset( + amount, + gasPriceGwei, + feePercent, + baseAssetAddress, + baseCurrencyAddress, + feeAssetAddress, + usdtPrices + ); + + const ornTotalFeeNum = parseFloat(ornTotalFee); + const bnbTotalFeeNum = parseFloat(bnbTotalFee); + const usdtTotalFeeNum = parseFloat(usdtTotalFee); + + const average = (ornTotalFeeNum + bnbTotalFeeNum + usdtTotalFeeNum) / 3; + const ornDiff = Math.abs(ornTotalFeeNum - average); + const bnbDiff = Math.abs(bnbTotalFeeNum - average); + const usdtDiff = Math.abs(usdtTotalFeeNum - average); + + const acceptableDiffPercent = 0.01; + + expect(ornDiff / average).toBeLessThan(acceptableDiffPercent); + expect(bnbDiff / average).toBeLessThan(acceptableDiffPercent); + expect(usdtDiff / average).toBeLessThan(acceptableDiffPercent); + }); +}); diff --git a/src/services/Aggregator/ws/index.ts b/src/services/Aggregator/ws/index.ts index 06ca450..930b6f7 100644 --- a/src/services/Aggregator/ws/index.ts +++ b/src/services/Aggregator/ws/index.ts @@ -267,7 +267,7 @@ class AggregatorWS { if ('payload' in subscription) { if (typeof subscription.payload === 'string') { subRequest['S'] = subscription.payload; - } else { // SwapInfoSubscriptionPayload | FuturesTradeInfoPayload + } else { // SwapInfoSubscriptionPayload subRequest['S'] = { d: id, ...subscription.payload, diff --git a/src/utils/calculateFeeInFeeAsset.ts b/src/utils/calculateFeeInFeeAsset.ts index c93e4ab..e4dd53d 100644 --- a/src/utils/calculateFeeInFeeAsset.ts +++ b/src/utils/calculateFeeInFeeAsset.ts @@ -5,32 +5,33 @@ import calculateServiceFeeInFeeAsset from './calculateServiceFeeInFeeAsset.js'; const calculateFeeInFeeAsset = ( amount: BigNumber.Value, - feeAssetPrice: BigNumber.Value, - baseAssetPrice: BigNumber.Value, - baseCurrencyPrice: BigNumber.Value, gasPriceGwei: BigNumber.Value, feePercent: BigNumber.Value, - feeAsset: string, - assetPrices: Partial>, + baseAssetAddress: string, + baseCurrencyAddress: string, + feeAssetAddress: string, + prices: Partial>, ) => { - const feeAssetPriceInQuoteAsset = assetPrices[feeAsset]; - if (feeAssetPriceInQuoteAsset === undefined) throw Error('feeAssetPriceInQuoteAsset is undefined'); - - const feeAssetPriceInQuoteAssetBN = new BigNumber(feeAssetPriceInQuoteAsset); + const feeAssetPrice = prices[feeAssetAddress]; + if (feeAssetPrice === undefined) throw Error(`Fee asset price not found. Available prices: ${Object.keys(prices).join(', ')}`); + const baseAssetPrice = prices[baseAssetAddress]; + if (baseAssetPrice === undefined) throw Error(`Base asset price not found. Available prices: ${Object.keys(prices).join(', ')}`); + const baseCurrencyPrice = prices[baseCurrencyAddress]; // ETH, BNB, MATIC, etc. + if (baseCurrencyPrice === undefined) throw Error(`Base currency price not found. Available prices: ${Object.keys(prices).join(', ')}`); const serviceFeeInFeeAsset = calculateServiceFeeInFeeAsset( amount, - feeAssetPrice, - baseAssetPrice, + baseAssetAddress, + feeAssetAddress, feePercent, - feeAssetPriceInQuoteAssetBN + prices, ); const networkFeeInFeeAsset = calculateNetworkFeeInFeeAsset( gasPriceGwei, FILL_ORDERS_GAS_LIMIT, - baseCurrencyPrice, - feeAssetPrice, - feeAssetPriceInQuoteAssetBN + baseCurrencyAddress, + feeAssetAddress, + prices, ); return { diff --git a/src/utils/calculateNetworkFeeInFeeAsset.ts b/src/utils/calculateNetworkFeeInFeeAsset.ts index 07ddc81..8e399eb 100644 --- a/src/utils/calculateNetworkFeeInFeeAsset.ts +++ b/src/utils/calculateNetworkFeeInFeeAsset.ts @@ -1,20 +1,22 @@ -import { BigNumber } from 'bignumber.js'; +import type { BigNumber } from 'bignumber.js'; import calculateNetworkFee from './calculateNetworkFee.js'; +import convertPrice from './convertPrice.js'; const calculateNetworkFeeInFeeAsset = ( gasPriceGwei: BigNumber.Value, gasLimit: BigNumber.Value, - baseCurrencyPrice: BigNumber.Value, - feeAssetPrice: BigNumber.Value, - feeAssetPriceInQuoteAsset: BigNumber.Value, + baseCurrencyAddress: string, + feeAssetAddress: string, + prices: Partial> ) => { const networkFee = calculateNetworkFee(gasPriceGwei, gasLimit); - const networkFeeInQuoteAsset = new BigNumber(networkFee).multipliedBy(baseCurrencyPrice); - const networkFeeInFeeAsset = networkFeeInQuoteAsset - .div(new BigNumber(feeAssetPriceInQuoteAsset).multipliedBy(feeAssetPrice)); - - return networkFeeInFeeAsset.toString(); + return convertPrice( + networkFee, + baseCurrencyAddress, // from + feeAssetAddress, // to + prices + ); }; export default calculateNetworkFeeInFeeAsset; diff --git a/src/utils/calculateServiceFeeInFeeAsset.ts b/src/utils/calculateServiceFeeInFeeAsset.ts index e4e51b3..d329d9e 100644 --- a/src/utils/calculateServiceFeeInFeeAsset.ts +++ b/src/utils/calculateServiceFeeInFeeAsset.ts @@ -1,17 +1,21 @@ import { BigNumber } from 'bignumber.js'; +import convertPrice from './convertPrice.js'; export default function calculateServiceFeeInFeeAsset( amount: BigNumber.Value, - feeAssetPrice: BigNumber.Value, - baseAssetPrice: BigNumber.Value, + baseAssetAddress: string, + feeAssetAddress: string, feePercent: BigNumber.Value, - feeAssetPriceInQuoteAsset: BigNumber.Value, + prices: Partial> ) { - const result = new BigNumber(amount) - .multipliedBy(new BigNumber(feePercent).div(100)) - .multipliedBy(baseAssetPrice) - .div(new BigNumber(feeAssetPriceInQuoteAsset).multipliedBy(feeAssetPrice)) - .toString(); + const feeAmount = new BigNumber(amount).multipliedBy(new BigNumber(feePercent).div(100)); - return result; + const feeAssetAmount = convertPrice( + feeAmount, + baseAssetAddress, + feeAssetAddress, + prices + ); + + return feeAssetAmount; } diff --git a/src/utils/convertPrice.ts b/src/utils/convertPrice.ts new file mode 100644 index 0000000..95415bb --- /dev/null +++ b/src/utils/convertPrice.ts @@ -0,0 +1,26 @@ +import { BigNumber } from 'bignumber.js'; + +export default function convertPrice( + amount: BigNumber.Value, + assetInAddress: string, + assetOutAddress: string, + prices: Partial> // quoted in quoteAsset. [address]: priceQuotedInQuoteAsset +) { + const assetInPrice = prices[assetInAddress]; + if (assetInPrice === undefined) throw Error('assetInPrice is undefined'); + + const assetOutPrice = prices[assetOutAddress]; + if (assetOutPrice === undefined) throw Error('assetOutPrice is undefined'); + + const assetInPriceBN = new BigNumber(assetInPrice); + const assetOutPriceBN = new BigNumber(assetOutPrice); + + const assetInAmountBN = new BigNumber(amount); + + const assetInAmountInQuoteAsset = assetInAmountBN.multipliedBy(assetInPriceBN); + const assetInAmountInQuoteAssetBN = new BigNumber(assetInAmountInQuoteAsset); + + const assetOutAmountInQuoteAsset = assetInAmountInQuoteAssetBN.dividedBy(assetOutPriceBN); + + return assetOutAmountInQuoteAsset; +} From 96ec616be730dfe5ced9f2713d1d6123521a2940 Mon Sep 17 00:00:00 2001 From: Aleksandr Kraiz Date: Tue, 1 Aug 2023 21:29:13 +0400 Subject: [PATCH 06/17] bump version --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8387e0e..64f5392 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.19.42-rc3", + "version": "0.19.42-rc4", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", @@ -108,4 +108,4 @@ "overrides": { "tsconfig-paths": "^4.0.0" } -} +} \ No newline at end of file From cd3eb34b1155fdaceb1d23385d51cbe6b1605845 Mon Sep 17 00:00:00 2001 From: Aleksandr Kraiz Date: Tue, 1 Aug 2023 22:18:18 +0400 Subject: [PATCH 07/17] Compatibility --- package.json | 2 +- src/services/BlockchainService/index.ts | 9 ++++++++- .../schemas/pricesWithQuoteAssetSchema.ts | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 64f5392..e075a79 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.19.42-rc4", + "version": "0.19.42-rc5", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", diff --git a/src/services/BlockchainService/index.ts b/src/services/BlockchainService/index.ts index c71ccef..15f88a0 100644 --- a/src/services/BlockchainService/index.ts +++ b/src/services/BlockchainService/index.ts @@ -84,6 +84,7 @@ class BlockchainService { this.getUserEarned = this.getUserEarned.bind(this); this.getPoolsV3Info = this.getPoolsV3Info.bind(this); this.getHistory = this.getHistory.bind(this); + this.getPrices = this.getPrices.bind(this); this.getPricesWithQuoteAsset = this.getPricesWithQuoteAsset.bind(this); this.getTokensFee = this.getTokensFee.bind(this); this.getGasPriceWei = this.getGasPriceWei.bind(this); @@ -215,8 +216,14 @@ class BlockchainService { { headers: this.basicAuthHeaders } ); - getPricesWithQuoteAsset = () => fetchWithValidation( + getPrices = () => fetchWithValidation( `${this.apiUrl}/api/prices`, + z.record(z.string()).transform(makePartial), + { headers: this.basicAuthHeaders } + ); + + getPricesWithQuoteAsset = () => fetchWithValidation( + `${this.apiUrl}/api/quotedPrices`, pricesWithQuoteAssetSchema, { headers: this.basicAuthHeaders } ); diff --git a/src/services/BlockchainService/schemas/pricesWithQuoteAssetSchema.ts b/src/services/BlockchainService/schemas/pricesWithQuoteAssetSchema.ts index e91cb19..4fcaef0 100644 --- a/src/services/BlockchainService/schemas/pricesWithQuoteAssetSchema.ts +++ b/src/services/BlockchainService/schemas/pricesWithQuoteAssetSchema.ts @@ -3,5 +3,6 @@ import { makePartial } from '../../../utils/index.js'; export const pricesWithQuoteAssetSchema = z.object({ quoteAsset: z.string(), + quoteAssetAddress: z.string(), prices: z.record(z.string()).transform(makePartial) }); From cccf239f27f9174862d4b3093b49e9c46264d7da Mon Sep 17 00:00:00 2001 From: Kirill Litvinov Date: Wed, 2 Aug 2023 15:05:44 +0300 Subject: [PATCH 08/17] fix: remove unused code --- src/Unit/Exchange/getSwapInfo.ts | 6 ------ src/Unit/Exchange/swapLimit.ts | 6 ------ src/Unit/Exchange/swapMarket.ts | 6 ------ src/services/Aggregator/schemas/swapInfoSchema.ts | 2 +- 4 files changed, 1 insertion(+), 19 deletions(-) diff --git a/src/Unit/Exchange/getSwapInfo.ts b/src/Unit/Exchange/getSwapInfo.ts index 4077fec..e6c0f9e 100644 --- a/src/Unit/Exchange/getSwapInfo.ts +++ b/src/Unit/Exchange/getSwapInfo.ts @@ -121,12 +121,6 @@ export default async function getSwapInfo({ if (baseAssetAddress === undefined) throw new Error(`No asset address for ${baseAssetName}`); // Fee calculation - const baseAssetPriceInQuoteAsset = allPrices.prices[baseAssetAddress]; - if (baseAssetPriceInQuoteAsset === undefined) throw new Error(`Base asset price ${baseAssetName} in ${allPrices.quoteAsset} not found`); - const baseCurrencyPriceInQuoteAsset = allPrices.prices[ethers.constants.AddressZero]; - if (baseCurrencyPriceInQuoteAsset === undefined) throw new Error(`Base currency price in ${allPrices.quoteAsset} not found`); - const feeAssetPriceInQuoteAsset = allPrices.prices[feeAssetAddress]; - if (feeAssetPriceInQuoteAsset === undefined) throw new Error(`Fee asset price ${feeAsset} in ${allPrices.quoteAsset} not found`); const feePercent = feeAssets[feeAsset]; if (feePercent === undefined) throw new Error(`Fee asset ${feeAsset} not available`); diff --git a/src/Unit/Exchange/swapLimit.ts b/src/Unit/Exchange/swapLimit.ts index 741af96..3b62706 100644 --- a/src/Unit/Exchange/swapLimit.ts +++ b/src/Unit/Exchange/swapLimit.ts @@ -372,12 +372,6 @@ export default async function swapLimit({ }); // Fee calculation - const baseAssetPriceInQuoteAsset = allPrices.prices[baseAssetAddress]; - if (baseAssetPriceInQuoteAsset === undefined) throw new Error(`Base asset price ${baseAssetName} in ${allPrices.quoteAsset} not found`); - const baseCurrencyPriceInQuoteAsset = allPrices.prices[ethers.constants.AddressZero]; - if (baseCurrencyPriceInQuoteAsset === undefined) throw new Error(`Base currency price in ${allPrices.quoteAsset} not found`); - const feeAssetPriceInQuoteAsset = allPrices.prices[feeAssetAddress]; - if (feeAssetPriceInQuoteAsset === undefined) throw new Error(`Fee asset price ${feeAsset} in ${allPrices.quoteAsset} not found`); const feePercent = feeAssets[feeAsset]; if (feePercent === undefined) throw new Error(`Fee asset ${feeAsset} not available`); diff --git a/src/Unit/Exchange/swapMarket.ts b/src/Unit/Exchange/swapMarket.ts index af6996c..2ac8e2f 100644 --- a/src/Unit/Exchange/swapMarket.ts +++ b/src/Unit/Exchange/swapMarket.ts @@ -330,12 +330,6 @@ export default async function swapMarket({ }); // Fee calculation - const baseAssetPriceInQuoteAsset = allPrices.prices[baseAssetAddress]; - if (baseAssetPriceInQuoteAsset === undefined) throw new Error(`Base asset price ${baseAssetName} in ${allPrices.quoteAsset}not found`); - const baseCurrencyPriceInQuoteAsset = allPrices.prices[ethers.constants.AddressZero]; - if (baseCurrencyPriceInQuoteAsset === undefined) throw new Error(`Base currency price in ${allPrices.quoteAsset} not found`); - const feeAssetPriceInQuoteAsset = allPrices.prices[feeAssetAddress]; - if (feeAssetPriceInQuoteAsset === undefined) throw new Error(`Fee asset price ${feeAsset} in ${allPrices.quoteAsset} not found`); const feePercent = feeAssets[feeAsset]; if (feePercent === undefined) throw new Error(`Fee asset ${feeAsset} not available`); diff --git a/src/services/Aggregator/schemas/swapInfoSchema.ts b/src/services/Aggregator/schemas/swapInfoSchema.ts index 26b7947..cc2166e 100644 --- a/src/services/Aggregator/schemas/swapInfoSchema.ts +++ b/src/services/Aggregator/schemas/swapInfoSchema.ts @@ -39,7 +39,7 @@ const swapInfoBase = z.object({ orderInfo: orderInfoSchema, isThroughPoolOrCurve: z.boolean(), }).array(), - anm: z.record(z.string()).optional(), // address to ERC20 names + assetNameMapping: z.record(z.string()).optional(), // address to ERC20 names }); const swapInfoByAmountIn = swapInfoBase.extend({ From ea426c10c122fe00535f7021793bd439cd2577e8 Mon Sep 17 00:00:00 2001 From: kigastu Date: Wed, 2 Aug 2023 15:12:24 +0300 Subject: [PATCH 09/17] bump version --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e075a79..05078bf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.19.42-rc5", + "version": "0.19.42", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", @@ -108,4 +108,4 @@ "overrides": { "tsconfig-paths": "^4.0.0" } -} \ No newline at end of file +} From dec0e82b07014694a91eb11989124825564a37ab Mon Sep 17 00:00:00 2001 From: Aleksandr Kraiz Date: Thu, 3 Aug 2023 14:09:56 +0400 Subject: [PATCH 10/17] Relax Exchange type --- package.json | 4 ++-- src/services/Aggregator/index.ts | 11 +++++------ .../Aggregator/schemas/aggregatedOrderbookSchema.ts | 3 +-- src/services/Aggregator/schemas/orderSchema.ts | 2 +- src/services/Aggregator/schemas/swapInfoSchema.ts | 5 ++--- src/services/Aggregator/ws/index.ts | 4 ++-- .../Aggregator/ws/schemas/addressUpdateSchema.ts | 3 +-- src/services/Aggregator/ws/schemas/orderBookSchema.ts | 3 +-- src/services/Aggregator/ws/schemas/swapInfoSchema.ts | 5 ++--- src/services/PriceFeed/index.ts | 6 +++--- src/types.ts | 9 ++++----- 11 files changed, 24 insertions(+), 31 deletions(-) diff --git a/package.json b/package.json index 05078bf..8b72901 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.19.42", + "version": "0.19.43", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", @@ -108,4 +108,4 @@ "overrides": { "tsconfig-paths": "^4.0.0" } -} +} \ No newline at end of file diff --git a/src/services/Aggregator/index.ts b/src/services/Aggregator/index.ts index 7ff8aa3..7a220b3 100644 --- a/src/services/Aggregator/index.ts +++ b/src/services/Aggregator/index.ts @@ -8,7 +8,7 @@ import errorSchema from './schemas/errorSchema.js'; import placeAtomicSwapSchema from './schemas/placeAtomicSwapSchema.js'; import { AggregatorWS } from './ws/index.js'; import { atomicSwapHistorySchema } from './schemas/atomicSwapHistorySchema.js'; -import type { BasicAuthCredentials, Exchange, SignedCancelOrderRequest, SignedOrder } from '../../types.js'; +import type { BasicAuthCredentials, SignedCancelOrderRequest, SignedOrder } from '../../types.js'; import { pairConfigSchema, aggregatedOrderbookSchema, exchangeOrderbookSchema, poolReservesSchema, @@ -18,7 +18,6 @@ import toUpperCase from '../../utils/toUpperCase.js'; import httpToWS from '../../utils/httpToWS.js'; import { ethers } from 'ethers'; import orderSchema from './schemas/orderSchema.js'; -import { exchanges } from '../../constants/index.js'; import { fetchWithValidation } from 'simple-typed-fetch'; class Aggregator { @@ -119,12 +118,12 @@ class Aggregator { getAvailableExchanges = () => fetchWithValidation( `${this.apiUrl}/api/v1/exchange/list`, - z.enum(exchanges).array(), + z.string().array(), ); getExchangeOrderbook = ( pair: string, - exchange: Exchange, + exchange: string, depth = 20, filterByBrokerBalances: boolean | null = null, ) => { @@ -156,7 +155,7 @@ class Aggregator { getPoolReserves = ( pair: string, - exchange: Exchange, + exchange: string, ) => { const url = new URL(`${this.apiUrl}/api/v1/pools/reserves/${exchange}/${pair}`); return fetchWithValidation( @@ -255,7 +254,7 @@ class Aggregator { assetOut: string, amount: string, instantSettlement?: boolean, - exchanges?: Exchange[] | 'cex' | 'pools', + exchanges?: string[] | 'cex' | 'pools', ) => { const url = new URL(`${this.apiUrl}/api/v1/swap`); url.searchParams.append('assetIn', assetIn); diff --git a/src/services/Aggregator/schemas/aggregatedOrderbookSchema.ts b/src/services/Aggregator/schemas/aggregatedOrderbookSchema.ts index e827d68..b1cf821 100644 --- a/src/services/Aggregator/schemas/aggregatedOrderbookSchema.ts +++ b/src/services/Aggregator/schemas/aggregatedOrderbookSchema.ts @@ -1,5 +1,4 @@ import { z } from 'zod'; -import { exchanges } from '../../../constants/index.js'; const orderbookElementSchema = z.object({ price: z.number(), @@ -12,7 +11,7 @@ const orderbookElementSchema = z.object({ const aggregatedOrderbookElementSchema = orderbookElementSchema .extend({ - exchanges: z.enum(exchanges).array(), + exchanges: z.string().array(), }); export const aggregatedOrderbookSchema = z.object({ diff --git a/src/services/Aggregator/schemas/orderSchema.ts b/src/services/Aggregator/schemas/orderSchema.ts index 5d4cfd5..14fc395 100644 --- a/src/services/Aggregator/schemas/orderSchema.ts +++ b/src/services/Aggregator/schemas/orderSchema.ts @@ -86,7 +86,7 @@ const subOrderSchema = baseOrderSchema.extend({ parentOrderId: z.string().refine(ethers.utils.isHexString, (value) => ({ message: `subOrder.parentOrderId must be a hex string, got ${value}`, })), - exchange: z.enum(exchanges), + exchange: z.string(), brokerAddress: brokerAddressSchema, tradesInfo: z.record( z.string().uuid(), diff --git a/src/services/Aggregator/schemas/swapInfoSchema.ts b/src/services/Aggregator/schemas/swapInfoSchema.ts index cc2166e..8740e0a 100644 --- a/src/services/Aggregator/schemas/swapInfoSchema.ts +++ b/src/services/Aggregator/schemas/swapInfoSchema.ts @@ -1,5 +1,4 @@ import { z } from 'zod'; -import { exchanges } from '../../../constants/index.js'; const orderInfoSchema = z.object({ assetPair: z.string().toUpperCase(), @@ -18,13 +17,13 @@ const swapInfoBase = z.object({ // isThroughPoolOptimal: z.boolean(), // deprecated executionInfo: z.string(), orderInfo: orderInfoSchema, - exchanges: z.array(z.enum(exchanges)), + exchanges: z.array(z.string()), price: z.number().nullable(), // spending asset price minAmountOut: z.number(), minAmountIn: z.number(), marketPrice: z.number().nullable(), // spending asset market price alternatives: z.object({ // execution alternatives - exchanges: z.array(z.enum(exchanges)), + exchanges: z.array(z.string()), path: z.object({ units: z.object({ assetPair: z.string().toUpperCase(), diff --git a/src/services/Aggregator/ws/index.ts b/src/services/Aggregator/ws/index.ts index 930b6f7..c014e6c 100644 --- a/src/services/Aggregator/ws/index.ts +++ b/src/services/Aggregator/ws/index.ts @@ -11,7 +11,7 @@ import { import UnsubscriptionType from './UnsubscriptionType.js'; import type { SwapInfoBase, AssetPairUpdate, OrderbookItem, - Balance, Exchange, SwapInfo, Json, BasicAuthCredentials, + Balance, SwapInfo, Json, BasicAuthCredentials, } from '../../../types.js'; import unsubscriptionDoneSchema from './schemas/unsubscriptionDoneSchema.js'; import assetPairConfigSchema from './schemas/assetPairConfigSchema.js'; @@ -42,7 +42,7 @@ type SwapInfoSubscriptionPayload = { i: string // asset in o: string // asset out a: number // amount IN/OUT - es?: Exchange[] | 'cex' | 'pools' // exchange list of all cex or all pools (ORION_POOL, UNISWAP, PANCAKESWAP etc) + es?: string[] | 'cex' | 'pools' // exchange list of all cex or all pools (ORION_POOL, UNISWAP, PANCAKESWAP etc) e?: boolean // is amount IN? Value `false` means a = amount OUT, `true` if omitted is?: boolean // instant settlement } diff --git a/src/services/Aggregator/ws/schemas/addressUpdateSchema.ts b/src/services/Aggregator/ws/schemas/addressUpdateSchema.ts index 675cafe..0310b0a 100644 --- a/src/services/Aggregator/ws/schemas/addressUpdateSchema.ts +++ b/src/services/Aggregator/ws/schemas/addressUpdateSchema.ts @@ -1,5 +1,4 @@ import { z } from 'zod'; -import { exchanges } from '../../../../constants/index.js'; import orderStatuses from '../../../../constants/orderStatuses.js'; import executionTypes from '../../../../constants/executionTypes.js'; import subOrderStatuses from '../../../../constants/subOrderStatuses.js'; @@ -23,7 +22,7 @@ const subOrderSchema = z.object({ a: z.number(), // amount A: z.number(), // settled amount p: z.number(), // avg weighed settlement price - e: z.enum(exchanges), // exchange + e: z.string(), // exchange b: z.string(), // broker address S: z.enum(subOrderStatuses), // status o: z.boolean(), // internal only diff --git a/src/services/Aggregator/ws/schemas/orderBookSchema.ts b/src/services/Aggregator/ws/schemas/orderBookSchema.ts index 4c27b87..d0b04d2 100644 --- a/src/services/Aggregator/ws/schemas/orderBookSchema.ts +++ b/src/services/Aggregator/ws/schemas/orderBookSchema.ts @@ -1,5 +1,4 @@ import { z } from 'zod'; -import exchanges from '../../../../constants/exchanges.js'; import MessageType from '../MessageType.js'; import baseMessageSchema from './baseMessageSchema.js'; @@ -7,7 +6,7 @@ export const orderBookItemSchema = z.tuple([ z.string(), // price z.string(), // size z.array( - z.enum(exchanges), + z.string(), ), // exchanges z.array(z.tuple([ z.enum(['SELL', 'BUY']), // side diff --git a/src/services/Aggregator/ws/schemas/swapInfoSchema.ts b/src/services/Aggregator/ws/schemas/swapInfoSchema.ts index 7cc8e35..ef0fc6c 100644 --- a/src/services/Aggregator/ws/schemas/swapInfoSchema.ts +++ b/src/services/Aggregator/ws/schemas/swapInfoSchema.ts @@ -1,10 +1,9 @@ import { z } from 'zod'; -import exchanges from '../../../../constants/exchanges.js'; import MessageType from '../MessageType.js'; import baseMessageSchema from './baseMessageSchema.js'; const alternativeSchema = z.object({ // execution alternatives - e: z.enum(exchanges).array(), // exchanges + e: z.string().array(), // exchanges ps: z.string().array(), // path mo: z.number().optional(), // market amount out mi: z.number().optional(), // market amount in @@ -23,7 +22,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.enum(exchanges).array().optional(), // Exchanges + 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 diff --git a/src/services/PriceFeed/index.ts b/src/services/PriceFeed/index.ts index f2253c3..ff027d0 100644 --- a/src/services/PriceFeed/index.ts +++ b/src/services/PriceFeed/index.ts @@ -1,5 +1,5 @@ import { fetchWithValidation } from 'simple-typed-fetch'; -import type { BasicAuthCredentials, Exchange } from '../../types.js'; +import type { BasicAuthCredentials } from '../../types.js'; import { allTickersSchema, statisticsOverviewSchema, topPairsStatisticsSchema } from './schemas/index.js'; import candlesSchema from './schemas/candlesSchema.js'; import { PriceFeedWS } from './ws/index.js'; @@ -56,7 +56,7 @@ class PriceFeed { ); }; - getStatisticsOverview = (exchange: Exchange | 'ALL' = 'ALL') => { + getStatisticsOverview = (exchange: string | 'ALL' = 'ALL') => { const url = new URL(`${this.statisticsUrl}/overview`); url.searchParams.append('exchange', exchange); @@ -67,7 +67,7 @@ class PriceFeed { ); } - getTopPairStatistics = (exchange: Exchange | 'ALL' = 'ALL') => { + getTopPairStatistics = (exchange: string | 'ALL' = 'ALL') => { const url = new URL(`${this.statisticsUrl}/top-pairs`); url.searchParams.append('exchange', exchange); diff --git a/src/types.ts b/src/types.ts index b973dfc..b97e2f1 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/consistent-type-definitions */ import type { BigNumber } from 'bignumber.js'; -import type exchanges from './constants/exchanges.js'; import type subOrderStatuses from './constants/subOrderStatuses.js'; import type positionStatuses from './constants/positionStatuses.js'; import type { knownEnvs } from './config/schemas/index.js'; @@ -143,12 +142,12 @@ export type BalanceIssue = { readonly fixes?: Fix[] } -export type Exchange = typeof exchanges[number]; +// export type Exchange = typeof exchanges[number]; export type OrderbookItem = { price: string amount: string - exchanges: Exchange[] + exchanges: string[] vob: Array<{ side: 'BUY' | 'SELL' pairName: string @@ -156,7 +155,7 @@ export type OrderbookItem = { } export type SwapInfoAlternative = { - exchanges: Exchange[] + exchanges: string[] path: string[] marketAmountOut?: number | undefined marketAmountIn?: number | undefined @@ -175,7 +174,7 @@ export type SwapInfoBase = { minAmountOut: number path: string[] - exchanges?: Exchange[] | undefined + exchanges?: string[] | undefined poolOptimal: boolean price?: number | undefined From 230c399bdc559c5106ffa22bebf3df1afc4af244 Mon Sep 17 00:00:00 2001 From: Aleksandr Kraiz Date: Thu, 3 Aug 2023 17:08:55 +0400 Subject: [PATCH 11/17] Fix: convertPrice --- package.json | 2 +- src/utils/convertPrice.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8b72901..908b26e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.19.43", + "version": "0.19.44", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", diff --git a/src/utils/convertPrice.ts b/src/utils/convertPrice.ts index 95415bb..3055b9b 100644 --- a/src/utils/convertPrice.ts +++ b/src/utils/convertPrice.ts @@ -6,11 +6,11 @@ export default function convertPrice( assetOutAddress: string, prices: Partial> // quoted in quoteAsset. [address]: priceQuotedInQuoteAsset ) { - const assetInPrice = prices[assetInAddress]; - if (assetInPrice === undefined) throw Error('assetInPrice is undefined'); + const assetInPrice = prices[assetInAddress.toLowerCase()]; + if (assetInPrice === undefined) throw Error(`Price conversion: AssetIn (${assetInAddress}) price is undefined`); - const assetOutPrice = prices[assetOutAddress]; - if (assetOutPrice === undefined) throw Error('assetOutPrice is undefined'); + const assetOutPrice = prices[assetOutAddress.toLowerCase()]; + if (assetOutPrice === undefined) throw Error(`Price conversion: AssetOut (${assetOutAddress}) price is undefined`); const assetInPriceBN = new BigNumber(assetInPrice); const assetOutPriceBN = new BigNumber(assetOutPrice); From b6cb9ae1a1affc0b2c53e89ed49ec8fe71973592 Mon Sep 17 00:00:00 2001 From: Aleksandr Kraiz Date: Sat, 5 Aug 2023 01:10:20 +0400 Subject: [PATCH 12/17] Fix price conversion --- package.json | 2 +- src/utils/calculateFeeInFeeAsset.ts | 20 ++++++++++---------- src/utils/calculateNetworkFeeInFeeAsset.ts | 8 ++++---- src/utils/calculateServiceFeeInFeeAsset.ts | 8 ++++---- src/utils/convertPrice.ts | 14 +++++++------- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 908b26e..4506f78 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.19.44", + "version": "0.19.45", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", diff --git a/src/utils/calculateFeeInFeeAsset.ts b/src/utils/calculateFeeInFeeAsset.ts index e4dd53d..2cde7e4 100644 --- a/src/utils/calculateFeeInFeeAsset.ts +++ b/src/utils/calculateFeeInFeeAsset.ts @@ -7,30 +7,30 @@ const calculateFeeInFeeAsset = ( amount: BigNumber.Value, gasPriceGwei: BigNumber.Value, feePercent: BigNumber.Value, - baseAssetAddress: string, - baseCurrencyAddress: string, - feeAssetAddress: string, + baseAssetName: string, + baseCurrencyName: string, + feeAssetName: string, prices: Partial>, ) => { - const feeAssetPrice = prices[feeAssetAddress]; + const feeAssetPrice = prices[feeAssetName]; if (feeAssetPrice === undefined) throw Error(`Fee asset price not found. Available prices: ${Object.keys(prices).join(', ')}`); - const baseAssetPrice = prices[baseAssetAddress]; + const baseAssetPrice = prices[baseAssetName]; if (baseAssetPrice === undefined) throw Error(`Base asset price not found. Available prices: ${Object.keys(prices).join(', ')}`); - const baseCurrencyPrice = prices[baseCurrencyAddress]; // ETH, BNB, MATIC, etc. + const baseCurrencyPrice = prices[baseCurrencyName]; // ETH, BNB, MATIC, etc. if (baseCurrencyPrice === undefined) throw Error(`Base currency price not found. Available prices: ${Object.keys(prices).join(', ')}`); const serviceFeeInFeeAsset = calculateServiceFeeInFeeAsset( amount, - baseAssetAddress, - feeAssetAddress, + baseAssetName, + feeAssetName, feePercent, prices, ); const networkFeeInFeeAsset = calculateNetworkFeeInFeeAsset( gasPriceGwei, FILL_ORDERS_GAS_LIMIT, - baseCurrencyAddress, - feeAssetAddress, + baseCurrencyName, + feeAssetName, prices, ); diff --git a/src/utils/calculateNetworkFeeInFeeAsset.ts b/src/utils/calculateNetworkFeeInFeeAsset.ts index 8e399eb..4157756 100644 --- a/src/utils/calculateNetworkFeeInFeeAsset.ts +++ b/src/utils/calculateNetworkFeeInFeeAsset.ts @@ -5,16 +5,16 @@ import convertPrice from './convertPrice.js'; const calculateNetworkFeeInFeeAsset = ( gasPriceGwei: BigNumber.Value, gasLimit: BigNumber.Value, - baseCurrencyAddress: string, - feeAssetAddress: string, + baseCurrencyName: string, + feeAssetName: string, prices: Partial> ) => { const networkFee = calculateNetworkFee(gasPriceGwei, gasLimit); return convertPrice( networkFee, - baseCurrencyAddress, // from - feeAssetAddress, // to + baseCurrencyName, // from + feeAssetName, // to prices ); }; diff --git a/src/utils/calculateServiceFeeInFeeAsset.ts b/src/utils/calculateServiceFeeInFeeAsset.ts index d329d9e..599eefd 100644 --- a/src/utils/calculateServiceFeeInFeeAsset.ts +++ b/src/utils/calculateServiceFeeInFeeAsset.ts @@ -3,8 +3,8 @@ import convertPrice from './convertPrice.js'; export default function calculateServiceFeeInFeeAsset( amount: BigNumber.Value, - baseAssetAddress: string, - feeAssetAddress: string, + baseAssetName: string, + feeAssetName: string, feePercent: BigNumber.Value, prices: Partial> ) { @@ -12,8 +12,8 @@ export default function calculateServiceFeeInFeeAsset( const feeAssetAmount = convertPrice( feeAmount, - baseAssetAddress, - feeAssetAddress, + baseAssetName, + feeAssetName, prices ); diff --git a/src/utils/convertPrice.ts b/src/utils/convertPrice.ts index 3055b9b..3a56e9c 100644 --- a/src/utils/convertPrice.ts +++ b/src/utils/convertPrice.ts @@ -2,15 +2,15 @@ import { BigNumber } from 'bignumber.js'; export default function convertPrice( amount: BigNumber.Value, - assetInAddress: string, - assetOutAddress: string, - prices: Partial> // quoted in quoteAsset. [address]: priceQuotedInQuoteAsset + assetInName: string, + assetOutName: string, + prices: Partial> // quoted in quoteAsset. [name]: priceQuotedInQuoteAsset ) { - const assetInPrice = prices[assetInAddress.toLowerCase()]; - if (assetInPrice === undefined) throw Error(`Price conversion: AssetIn (${assetInAddress}) price is undefined`); + const assetInPrice = prices[assetInName]; + if (assetInPrice === undefined) throw Error(`Price conversion: AssetIn (${assetInName}) price is undefined`); - const assetOutPrice = prices[assetOutAddress.toLowerCase()]; - if (assetOutPrice === undefined) throw Error(`Price conversion: AssetOut (${assetOutAddress}) price is undefined`); + const assetOutPrice = prices[assetOutName]; + if (assetOutPrice === undefined) throw Error(`Price conversion: AssetOut (${assetOutName}) price is undefined`); const assetInPriceBN = new BigNumber(assetInPrice); const assetOutPriceBN = new BigNumber(assetOutPrice); From 321b2a2787e6dc555e63997027194f360f4b2c3c Mon Sep 17 00:00:00 2001 From: Aleksandr Kraiz Date: Mon, 7 Aug 2023 00:23:19 +0400 Subject: [PATCH 13/17] Bridge: improvements --- package.json | 2 +- src/Orion/bridge/index.ts | 139 ++++++++++++++++++++++++++++++++++++++ src/Orion/bridge/swap.ts | 13 ++-- src/Orion/index.ts | 59 +++------------- src/types.ts | 99 +++++++++++++++++++++++++++ 5 files changed, 256 insertions(+), 56 deletions(-) create mode 100644 src/Orion/bridge/index.ts diff --git a/package.json b/package.json index 4506f78..3f471f6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.19.45", + "version": "0.19.46", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", diff --git a/src/Orion/bridge/index.ts b/src/Orion/bridge/index.ts new file mode 100644 index 0000000..f935eda --- /dev/null +++ b/src/Orion/bridge/index.ts @@ -0,0 +1,139 @@ +import type { ethers } from 'ethers'; +import { + AtomicSwapStatus, type AtomicSwap, type SupportedChainId, + type Unit, INTERNAL_PROTOCOL_PRECISION +} from '../../index.js'; +import getHistoryExt from './getHistory.js'; +import swapExt from './swap.js'; + +import { BigNumber } from 'bignumber.js'; + +const backendStatusToAtomicSwapStatus = { + LOCKED: AtomicSwapStatus.ROUTING, + CLAIMED: AtomicSwapStatus.SETTLED, + REFUNDED: AtomicSwapStatus.REFUNDED, + REDEEMED: AtomicSwapStatus.SETTLED, + 'BEFORE-REDEEM': AtomicSwapStatus.ROUTING, +} as const; + +export default class Bridge { + constructor( + private readonly unitsArray: Unit[], + private readonly env?: string, + ) {} + + async getMergedHistory( + externalStoredAtomicSwaps: AtomicSwap[], + walletAddress: string, + ) { + const bridgeHistory = await this.getHistory(walletAddress); + + return Object.values(bridgeHistory).map((atomicSwap) => { + if (atomicSwap === undefined) throw new Error('No atomic swap'); + + const { + secretHash, + amountToReceive, + amountToSpend, + targetChainId, + asset, + sourceChainId, + status: asStatus, + claimed, + sender, + transactions, + expiration, + creationDate, + } = atomicSwap; + const localSwap = externalStoredAtomicSwaps.find( + (swap) => secretHash === swap.secretHash, + ); + + const amount = amountToReceive ?? amountToSpend ?? 0; + + // Checking if transaction hash from blockchain is different from the same in local storage + // and changing it to the correct one + + let assetName = asset; + + // LEGACY. Some old atomic swaps have address instead of asset name. Here we handle this case + if (asset.includes('0x')) { + assetName = '—'; // We don't want to display address even if we can't find asset name + } + + // Define status + let historyStatus = backendStatusToAtomicSwapStatus[asStatus.source]; + if (asStatus.source === 'LOCKED') { + const historySwap = bridgeHistory[secretHash]; + if (historySwap?.status.target === 'REDEEMED') { + historyStatus = AtomicSwapStatus.SETTLED; + } + } + if (claimed) historyStatus = AtomicSwapStatus.SETTLED; + let status: AtomicSwapStatus | undefined; + if ( + [AtomicSwapStatus.SETTLED, AtomicSwapStatus.REFUNDED].includes( + historyStatus, + ) + ) { + status = historyStatus; + } else { + status = localSwap !== undefined ? localSwap.status : historyStatus; + } + + // Define secret + const secret = localSwap !== undefined ? localSwap.secret : ''; + + // Define environment + const env = localSwap?.env; + + return { + liquidityMigrationTxHash: localSwap?.liquidityMigrationTxHash, + sourceNetwork: sourceChainId, + targetNetwork: targetChainId, + amount: new BigNumber(amount) + .multipliedBy(new BigNumber(10).pow(INTERNAL_PROTOCOL_PRECISION)) + .toString(), + walletAddress: sender, + secret, + secretHash, + lockTransactionHash: transactions?.lock, + refundTransactionHash: transactions?.refund, + status, + asset: assetName, + expiration: + expiration?.lock ?? creationDate.getTime() + 60 * 60 * 24 * 4, // Or default 4 days + creationDate: creationDate.getTime(), + env, + redeemOrder: atomicSwap.redeemOrder, + }; + }).filter((swap) => swap.env === undefined || swap.env === this.env); + } + + getHistory(address: string, limit = 1000) { + return getHistoryExt(this.unitsArray, address, limit); + } + + swap( + assetName: string, + amount: BigNumber.Value, + sourceChain: SupportedChainId, + targetChain: SupportedChainId, + signer: ethers.Signer, + options: { + autoApprove?: boolean + logger?: (message: string) => void + withdrawToWallet?: boolean + } + ) { + return swapExt({ + amount, + assetName, + sourceChain, + targetChain, + signer, + unitsArray: this.unitsArray, + options, + }) + } +} diff --git a/src/Orion/bridge/swap.ts b/src/Orion/bridge/swap.ts index aa723b2..9fe41be 100644 --- a/src/Orion/bridge/swap.ts +++ b/src/Orion/bridge/swap.ts @@ -14,10 +14,10 @@ import { import getNativeCryptocurrencyName from '../../utils/getNativeCryptocurrencyName.js'; import { denormalizeNumber, generateSecret, normalizeNumber, toUpperCase } from '../../utils/index.js'; import type { SupportedChainId } from '../../types.js'; -import type Orion from '../index.js'; import type { z } from 'zod'; import type { placeAtomicSwapSchema } from '../../services/Aggregator/schemas/index.js'; import { simpleFetch } from 'simple-typed-fetch'; +import type { Unit } from '../../index.js'; type Params = { assetName: string @@ -25,7 +25,7 @@ type Params = { sourceChain: SupportedChainId targetChain: SupportedChainId signer: ethers.Signer - orion: Orion + unitsArray: Unit[] options?: { withdrawToWallet?: boolean // By default, the transfer amount remains in the exchange contract autoApprove?: boolean @@ -40,7 +40,7 @@ export default async function swap({ targetChain, signer, options, - orion + unitsArray, }: Params) { const startProcessingTime = Date.now(); if (amount === '') throw new Error('Amount can not be empty'); @@ -50,8 +50,11 @@ export default async function swap({ if (amountBN.isNaN()) throw new Error(`Amount '${amountBN.toString()}' is not a number`); if (amountBN.lte(0)) throw new Error(`Amount '${amountBN.toString()}' should be greater than 0`); - const sourceChainUnit = orion.getUnit(sourceChain); - const targetChainUnit = orion.getUnit(targetChain); + const sourceChainUnit = unitsArray.find(({ chainId }) => chainId === sourceChain); + const targetChainUnit = unitsArray.find(({ chainId }) => chainId === targetChain); + + if (sourceChainUnit === undefined) throw new Error(`Source chain '${sourceChain}' not found`); + if (targetChainUnit === undefined) throw new Error(`Target chain '${targetChain}' not found`); const { blockchainService: sourceBlockchainService, diff --git a/src/Orion/index.ts b/src/Orion/index.ts index 6ca00c3..0da2614 100644 --- a/src/Orion/index.ts +++ b/src/Orion/index.ts @@ -1,36 +1,12 @@ -import type { BigNumber } from 'bignumber.js'; -import type { ethers } from 'ethers'; import { merge } from 'merge-anything'; import { chains, envs } from '../config/index.js'; import type { networkCodes } from '../constants/index.js'; import Unit from '../Unit/index.js'; import { ReferralSystem } from '../services/ReferralSystem/index.js'; -import type { SupportedChainId, DeepPartial, VerboseUnitConfig, KnownEnv } from '../types.js'; +import type { SupportedChainId, DeepPartial, VerboseUnitConfig, KnownEnv, EnvConfig, AggregatedAssets } from '../types.js'; import { isValidChainId } from '../utils/index.js'; -import swap from './bridge/swap.js'; -import getHistory from './bridge/getHistory.js'; import { simpleFetch } from 'simple-typed-fetch'; - -type EnvConfig = { - analyticsAPI: string - referralAPI: string - networks: Partial< - Record< - SupportedChainId, - VerboseUnitConfig - > - > -} -type AggregatedAssets = Partial< - Record< - string, - Partial< - Record - > - > - >; +import Bridge from './bridge/index.js'; export default class Orion { public readonly env?: string; @@ -39,6 +15,8 @@ export default class Orion { public readonly referralSystem: ReferralSystem; + public readonly bridge: Bridge; + // TODO: get tradable assets (aggregated) // TODO: get tradable pairs (aggregated) @@ -117,6 +95,11 @@ export default class Orion { [chainId]: unit, } }, {}); + + this.bridge = new Bridge( + this.unitsArray, + this.env, + ); } get unitsArray() { @@ -211,28 +194,4 @@ export default class Orion { return result; } - - bridge = { - getHistory: (address: string, limit = 1000) => getHistory(this.unitsArray, address, limit), - swap: ( - assetName: string, - amount: BigNumber.Value, - sourceChain: SupportedChainId, - targetChain: SupportedChainId, - signer: ethers.Signer, - options: { - autoApprove?: boolean - logger?: (message: string) => void - withdrawToWallet?: boolean - } - ) => swap({ - amount, - assetName, - sourceChain, - targetChain, - signer, - orion: this, - options, - }) - } } diff --git a/src/types.ts b/src/types.ts index b97e2f1..3e7be3d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -250,3 +250,102 @@ export type VerboseUnitConfig = { export type KnownEnv = typeof knownEnvs[number]; export type Json = string | number | boolean | null | Json[] | { [key: string]: Json }; + +export type EnvConfig = { + analyticsAPI: string + referralAPI: string + networks: Partial< + Record< + SupportedChainId, + VerboseUnitConfig + > + > +} +export type AggregatedAssets = Partial< + Record< + string, + Partial< + Record + > + > + >; + +export type RedeemOrder = { + sender: string + receiver: string + asset: string + amount: number + expiration: number + secretHash: string + signature: string + claimReceiver: string +} + +export enum AtomicSwapStatus { + ROUTING_REQUESTED = 'ROUTING_REQUESTED', + ROUTING_PENDING = 'ROUTING_PENDING', + ROUTING = 'ROUTING', + ROUTING_FAILED = 'ROUTING_FAILED', + + // ACCEPTED = 'ACCEPTED', + FAILED = 'FAILED', + REJECTED = 'REJECTED', + + CHECK_REDEEM_THROUGH_OB_AVAILABLE = 'CHECK_REDEEM_THROUGH_OB_AVAILABLE', + // Redeem + // Blockchain redeem + READY_TO_REDEEM = 'READY_TO_REDEEM', + REDEEM_REQUESTED = 'REDEEM_REQUESTED', + REDEEM_PENDING = 'REDEEM_PENDING', + REDEEM_FAILED = 'REDEEM_FAILED', + + // Orion blockchain redeem + READY_TO_REDEEM_THROUGH_OB = 'READY_TO_REDEEM_THROUGH_OB', + REDEEM_PENDING_THROUGH_OB = 'REDEEM_PENDING_THROUGH_OB', + REDEEM_FAILED_THROUGH_OB = 'REDEEM_FAILED_THROUGH_OB', + + SETTLED = 'SETTLED', + + // Refund + REFUND_REQUESTED = 'REFUND_REQUESTED', + REFUND_PENDING = 'REFUND_PENDING', + REFUNDED = 'REFUNDED', + REFUND_FAILED = 'REFUND_FAILED', +} + +export type AtomicSwap = { + secret: string + secretHash: string + status: AtomicSwapStatus + + walletAddress: string + env?: string | undefined + + sourceNetwork?: SupportedChainId + targetNetwork?: SupportedChainId + + amount?: string + asset?: string + + creationDate?: number + expiration?: number + + lockTransactionHash?: string + redeemTransactionHash?: string + refundTransactionHash?: string + liquidityMigrationTxHash?: string + + redeemOrder?: RedeemOrder +} + +export type ExternalStorage = { + bridge: { + getAtomicSwaps: () => AtomicSwap[] + setAtomicSwaps: (atomics: AtomicSwap[]) => void + addAtomicSwap: (atomic: AtomicSwap) => void + updateAtomicSwap: (secretHash: string, atomic: Partial) => void + removeAtomicSwaps: (secretHashes: string[]) => void + } +} From 72581b0f4b57be74f5d8fd8bc52def6e5a6d4445 Mon Sep 17 00:00:00 2001 From: Aleksandr Kraiz Date: Mon, 7 Aug 2023 00:26:25 +0400 Subject: [PATCH 14/17] Bump --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3f471f6..eb83b52 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.19.46", + "version": "0.19.47", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", From cd0a0128d8d25480bfe1cc4f691092b72ebbf834 Mon Sep 17 00:00:00 2001 From: Aleksandr Kraiz Date: Tue, 8 Aug 2023 10:21:54 +0400 Subject: [PATCH 15/17] Price conversion iprovements --- package.json | 2 +- src/Orion/bridge/index.ts | 46 +++-------------------------- src/types.ts | 33 --------------------- src/utils/convertPrice.ts | 4 +-- src/utils/index.ts | 1 + src/utils/removeFieldsFromObject.ts | 16 ++++++++++ 6 files changed, 24 insertions(+), 78 deletions(-) create mode 100644 src/utils/removeFieldsFromObject.ts diff --git a/package.json b/package.json index eb83b52..b3259d3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.19.47", + "version": "0.19.48", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", diff --git a/src/Orion/bridge/index.ts b/src/Orion/bridge/index.ts index f935eda..80f87fb 100644 --- a/src/Orion/bridge/index.ts +++ b/src/Orion/bridge/index.ts @@ -1,6 +1,6 @@ import type { ethers } from 'ethers'; import { - AtomicSwapStatus, type AtomicSwap, type SupportedChainId, + type AtomicSwap, type SupportedChainId, type Unit, INTERNAL_PROTOCOL_PRECISION } from '../../index.js'; import getHistoryExt from './getHistory.js'; @@ -8,14 +8,6 @@ import swapExt from './swap.js'; import { BigNumber } from 'bignumber.js'; -const backendStatusToAtomicSwapStatus = { - LOCKED: AtomicSwapStatus.ROUTING, - CLAIMED: AtomicSwapStatus.SETTLED, - REFUNDED: AtomicSwapStatus.REFUNDED, - REDEEMED: AtomicSwapStatus.SETTLED, - 'BEFORE-REDEEM': AtomicSwapStatus.ROUTING, -} as const; - export default class Bridge { constructor( private readonly unitsArray: Unit[], @@ -38,13 +30,12 @@ export default class Bridge { targetChainId, asset, sourceChainId, - status: asStatus, - claimed, sender, transactions, expiration, creationDate, } = atomicSwap; + const localSwap = externalStoredAtomicSwaps.find( (swap) => secretHash === swap.secretHash, ); @@ -61,53 +52,24 @@ export default class Bridge { assetName = '—'; // We don't want to display address even if we can't find asset name } - // Define status - let historyStatus = backendStatusToAtomicSwapStatus[asStatus.source]; - if (asStatus.source === 'LOCKED') { - const historySwap = bridgeHistory[secretHash]; - if (historySwap?.status.target === 'REDEEMED') { - historyStatus = AtomicSwapStatus.SETTLED; - } - } - if (claimed) historyStatus = AtomicSwapStatus.SETTLED; - let status: AtomicSwapStatus | undefined; - if ( - [AtomicSwapStatus.SETTLED, AtomicSwapStatus.REFUNDED].includes( - historyStatus, - ) - ) { - status = historyStatus; - } else { - status = localSwap !== undefined ? localSwap.status : historyStatus; - } - - // Define secret - const secret = localSwap !== undefined ? localSwap.secret : ''; - - // Define environment - const env = localSwap?.env; - return { - liquidityMigrationTxHash: localSwap?.liquidityMigrationTxHash, + localSwap, sourceNetwork: sourceChainId, targetNetwork: targetChainId, amount: new BigNumber(amount) .multipliedBy(new BigNumber(10).pow(INTERNAL_PROTOCOL_PRECISION)) .toString(), walletAddress: sender, - secret, secretHash, lockTransactionHash: transactions?.lock, refundTransactionHash: transactions?.refund, - status, asset: assetName, expiration: expiration?.lock ?? creationDate.getTime() + 60 * 60 * 24 * 4, // Or default 4 days creationDate: creationDate.getTime(), - env, redeemOrder: atomicSwap.redeemOrder, }; - }).filter((swap) => swap.env === undefined || swap.env === this.env); + }); } getHistory(address: string, limit = 1000) { diff --git a/src/types.ts b/src/types.ts index 3e7be3d..0c19b6c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -283,42 +283,9 @@ export type RedeemOrder = { claimReceiver: string } -export enum AtomicSwapStatus { - ROUTING_REQUESTED = 'ROUTING_REQUESTED', - ROUTING_PENDING = 'ROUTING_PENDING', - ROUTING = 'ROUTING', - ROUTING_FAILED = 'ROUTING_FAILED', - - // ACCEPTED = 'ACCEPTED', - FAILED = 'FAILED', - REJECTED = 'REJECTED', - - CHECK_REDEEM_THROUGH_OB_AVAILABLE = 'CHECK_REDEEM_THROUGH_OB_AVAILABLE', - // Redeem - // Blockchain redeem - READY_TO_REDEEM = 'READY_TO_REDEEM', - REDEEM_REQUESTED = 'REDEEM_REQUESTED', - REDEEM_PENDING = 'REDEEM_PENDING', - REDEEM_FAILED = 'REDEEM_FAILED', - - // Orion blockchain redeem - READY_TO_REDEEM_THROUGH_OB = 'READY_TO_REDEEM_THROUGH_OB', - REDEEM_PENDING_THROUGH_OB = 'REDEEM_PENDING_THROUGH_OB', - REDEEM_FAILED_THROUGH_OB = 'REDEEM_FAILED_THROUGH_OB', - - SETTLED = 'SETTLED', - - // Refund - REFUND_REQUESTED = 'REFUND_REQUESTED', - REFUND_PENDING = 'REFUND_PENDING', - REFUNDED = 'REFUNDED', - REFUND_FAILED = 'REFUND_FAILED', -} - export type AtomicSwap = { secret: string secretHash: string - status: AtomicSwapStatus walletAddress: string env?: string | undefined diff --git a/src/utils/convertPrice.ts b/src/utils/convertPrice.ts index 3a56e9c..a7807f4 100644 --- a/src/utils/convertPrice.ts +++ b/src/utils/convertPrice.ts @@ -7,10 +7,10 @@ export default function convertPrice( prices: Partial> // quoted in quoteAsset. [name]: priceQuotedInQuoteAsset ) { const assetInPrice = prices[assetInName]; - if (assetInPrice === undefined) throw Error(`Price conversion: AssetIn (${assetInName}) price is undefined`); + if (assetInPrice === undefined) throw Error(`Price conversion: AssetIn (${assetInName}) price is undefined. Available prices: ${JSON.stringify(prices)}`); const assetOutPrice = prices[assetOutName]; - if (assetOutPrice === undefined) throw Error(`Price conversion: AssetOut (${assetOutName}) price is undefined`); + if (assetOutPrice === undefined) throw Error(`Price conversion: AssetOut (${assetOutName}) price is undefined. Available prices: ${JSON.stringify(prices)}`); const assetInPriceBN = new BigNumber(assetInPrice); const assetOutPriceBN = new BigNumber(assetOutPrice); diff --git a/src/utils/index.ts b/src/utils/index.ts index 1a7aea2..df7e0d7 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -16,6 +16,7 @@ export { default as getNativeCryptocurrencyName } from './getNativeCryptocurrenc export { default as laconicParse } from './laconic-parse.js'; export { default as isValidChainId } from './isValidChainId.js'; export { default as isKnownEnv } from './isKnownEnv.js'; +export { default as removeFieldsFromObject } from './removeFieldsFromObject.js'; // export { default as HttpError } from './httpError'; export * from './typeHelpers.js'; diff --git a/src/utils/removeFieldsFromObject.ts b/src/utils/removeFieldsFromObject.ts new file mode 100644 index 0000000..276a3de --- /dev/null +++ b/src/utils/removeFieldsFromObject.ts @@ -0,0 +1,16 @@ +const removeFieldsFromObject = < + T extends Record, + K extends keyof T +>( + obj: T, + fields: K[] +): Omit => { + const result = { ...obj }; + for (const field of fields) { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete result[field]; + } + return result; +}; + +export default removeFieldsFromObject; From 0fcc180b083316002a554987a83da5b6d0507ad7 Mon Sep 17 00:00:00 2001 From: Aleksandr Kraiz Date: Tue, 8 Aug 2023 10:24:47 +0400 Subject: [PATCH 16/17] Fix: build --- src/Orion/bridge/index.ts | 1 - src/Orion/index.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Orion/bridge/index.ts b/src/Orion/bridge/index.ts index 80f87fb..3ecc29f 100644 --- a/src/Orion/bridge/index.ts +++ b/src/Orion/bridge/index.ts @@ -11,7 +11,6 @@ import { BigNumber } from 'bignumber.js'; export default class Bridge { constructor( private readonly unitsArray: Unit[], - private readonly env?: string, ) {} async getMergedHistory( diff --git a/src/Orion/index.ts b/src/Orion/index.ts index 0da2614..80dbbf1 100644 --- a/src/Orion/index.ts +++ b/src/Orion/index.ts @@ -98,7 +98,6 @@ export default class Orion { this.bridge = new Bridge( this.unitsArray, - this.env, ); } From 7b32a6d52ac1396722f3de30ee4f5c9978026c64 Mon Sep 17 00:00:00 2001 From: Aleksandr Kraiz Date: Wed, 9 Aug 2023 19:31:14 +0400 Subject: [PATCH 17/17] Fix mapping --- package.json | 2 +- src/constants/exchangesMap.ts | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index b3259d3..feab0ee 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.19.48", + "version": "0.19.49", "description": "Orion Protocol SDK", "main": "./lib/index.cjs", "module": "./lib/index.js", diff --git a/src/constants/exchangesMap.ts b/src/constants/exchangesMap.ts index d95078b..6b77aac 100644 --- a/src/constants/exchangesMap.ts +++ b/src/constants/exchangesMap.ts @@ -1,9 +1,4 @@ -import type exchanges from './exchanges.js'; - -const mapping: Record< - typeof exchanges[number], - string -> = { +const mapping: Record = { // CEXes ASCENDEX: 'AscendEx', OKX: 'OKX', @@ -28,6 +23,6 @@ const mapping: Record< OKXSWAP: 'OKXSwap', CURVE: 'Curve', CURVE_FACTORY: 'Curve Factory', -} as const; +}; export default mapping;