diff --git a/README.md b/README.md index b664244..bd03103 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ Orion’s SDK is free to use and does not require an API key or registration. Re - [Withdraw](#withdraw) - [Deposit](#deposit) - [Get swap info](#get-swap-info) + - [Make swap limit](#make-swap-limit) - [Make swap market](#make-swap-market) - [Add liquidity](#add-liquidity) - [Remove all liquidity](#remove-all-liquidity) @@ -223,6 +224,45 @@ console.log(fee); // } ``` +### Make swap limit + +```ts +// Each trading pair has its own quantity precision +// You need to prepare (round) the quantity according to quantity precision + +const pairConfig = await simpleFetch(orionAggregator.getPairConfig)("ORN-USDT"); +if (!pairConfig) throw new Error(`Pair config ORN-USDT not found`); + +const { qtyPrecision } = pairConfig; + +const amount = 23.5346563; +const roundedAmount = new BigNumber(amount).decimalPlaces( + qtyPrecision, + BigNumber.ROUND_FLOOR +); // You can use your own Math lib + +orionUnit.exchange + .swapLimit({ + type: "exactSpend", + assetIn: "ORN", + assetOut: "USDT", + feeAsset: "ORN", + amount: roundedAmount.toNumber(), + price: 20, + signer: wallet, // or signer when UI + options: { + // All options are optional 🙂 + poolOnly: true, // You can specify whether you want to perform the exchange only through the pool + instantSettlement: true, // Set true to ensure that funds can be instantly transferred to wallet (otherwise, there is a possibility of receiving funds to the balance of the exchange contract) + logger: console.log, + // Set it to true if you want the issues associated with + // the lack of allowance to be automatically corrected + autoApprove: true, + }, + }) + .then(console.log); +``` + ### Make swap market ```ts diff --git a/package.json b/package.json index 632d749..c4461a3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@orionprotocol/sdk", - "version": "0.17.19", + "version": "0.17.20", "description": "Orion Protocol SDK", "main": "./lib/esm/index.js", "module": "./lib/esm/index.js", diff --git a/src/OrionUnit/Exchange/index.ts b/src/OrionUnit/Exchange/index.ts index 59fe4f6..d96ccad 100644 --- a/src/OrionUnit/Exchange/index.ts +++ b/src/OrionUnit/Exchange/index.ts @@ -1,10 +1,13 @@ import type OrionUnit from '..'; import deposit, { type DepositParams } from './deposit'; import getSwapInfo, { type GetSwapInfoParams } from './getSwapInfo'; +import type { SwapLimitParams } from './swapLimit'; +import swapLimit from './swapLimit'; import swapMarket, { type SwapMarketParams } from './swapMarket'; import withdraw, { type WithdrawParams } from './withdraw'; type PureSwapMarketParams = Omit +type PureSwapLimitParams = Omit type PureDepositParams = Omit type PureWithdrawParams = Omit type PureGetSwapMarketInfoParams = Omit @@ -16,6 +19,13 @@ export default class Exchange { this.orionUnit = orionUnit; } + public swapLimit(params: PureSwapLimitParams) { + return swapLimit({ + ...params, + orionUnit: this.orionUnit, + }); + } + public swapMarket(params: PureSwapMarketParams) { return swapMarket({ ...params, diff --git a/src/OrionUnit/Exchange/swapLimit.ts b/src/OrionUnit/Exchange/swapLimit.ts new file mode 100644 index 0000000..b504f17 --- /dev/null +++ b/src/OrionUnit/Exchange/swapLimit.ts @@ -0,0 +1,469 @@ +import BigNumber from 'bignumber.js'; +import { ethers } from 'ethers'; +import { Exchange__factory } from '@orionprotocol/contracts'; +import getBalances from '../../utils/getBalances'; +import BalanceGuard from '../../BalanceGuard'; +import getAvailableSources from '../../utils/getAvailableFundsSources'; +import type OrionUnit from '..'; +import { INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION, SWAP_THROUGH_ORION_POOL_GAS_LIMIT } from '../../constants'; +import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency'; +import simpleFetch from '../../simpleFetch'; +import { calculateFeeInFeeAsset, denormalizeNumber, normalizeNumber } from '../../utils'; +import { signOrder } from '../../crypt'; +import type orderSchema from '../../services/OrionAggregator/schemas/orderSchema'; +import type { z } from 'zod'; + +export type SwapLimitParams = { + type: 'exactSpend' | 'exactReceive' + assetIn: string + assetOut: string + price: BigNumber.Value + amount: BigNumber.Value + feeAsset: string + signer: ethers.Signer + orionUnit: OrionUnit + options?: { + poolOnly?: boolean + instantSettlement?: boolean + logger?: (message: string) => void + autoApprove?: boolean + developer?: { + route?: 'aggregator' | 'pool' + } + } +} + +type AggregatorOrder = { + amountOut: number + through: 'aggregator' + id: string + wait: () => Promise> +} + +type PoolSwap = { + amountOut: number + through: 'orion_pool' + txHash: string + wait: (confirmations?: number | undefined) => Promise +} + +export type Swap = AggregatorOrder | PoolSwap; + +export default async function swapLimit({ + type, + assetIn, + assetOut, + price, + amount, + feeAsset, + signer, + orionUnit, + options, +}: SwapLimitParams): Promise { + if (options?.developer) options.logger?.('YOU SPECIFIED A DEVELOPER OPTIONS. BE CAREFUL!'); + if (amount === '') throw new Error('Amount can not be empty'); + if (assetIn === '') throw new Error('AssetIn can not be empty'); + if (assetOut === '') throw new Error('AssetOut can not be empty'); + if (feeAsset === '') throw new Error('Fee asset can not be empty'); + if (price === '') throw new Error('Price can not be empty'); + + const amountBN = new BigNumber(amount); + 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 priceBN = new BigNumber(price); + if (priceBN.isNaN()) throw new Error(`Price '${priceBN.toString()}' is not a number`); + if (priceBN.lte(0)) throw new Error('Price should be greater than 0'); + + const walletAddress = await signer.getAddress(); + options?.logger?.(`Wallet address is ${walletAddress}`); + + const { + orionBlockchain, orionAggregator, provider, chainId, + } = orionUnit; + const { + exchangeContractAddress, + matcherAddress, + assetToAddress, + } = await simpleFetch(orionBlockchain.getInfo)(); + const nativeCryptocurrency = getNativeCryptocurrency(assetToAddress); + + const exchangeContract = Exchange__factory.connect(exchangeContractAddress, provider); + 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(); + + const assetInAddress = assetToAddress[assetIn]; + if (assetInAddress === undefined) throw new Error(`Asset '${assetIn}' not found`); + const feeAssetAddress = assetToAddress[feeAsset]; + if (feeAssetAddress === undefined) { + throw new Error(`Fee asset '${feeAsset}' not found. Available assets: ${Object.keys(feeAssets).join(', ')}`); + } + + const balances = await getBalances( + { + [assetIn]: assetInAddress, + [feeAsset]: feeAssetAddress, + [nativeCryptocurrency]: ethers.constants.AddressZero, + }, + orionAggregator, + walletAddress, + exchangeContract, + provider, + ); + + const balanceGuard = new BalanceGuard( + balances, + { + name: nativeCryptocurrency, + address: ethers.constants.AddressZero, + }, + provider, + signer, + options?.logger, + ); + + const swapInfo = await simpleFetch(orionAggregator.getSwapInfo)( + type, + assetIn, + assetOut, + amountBN.toString(), + options?.instantSettlement, + options?.poolOnly !== undefined && options.poolOnly + ? 'pools' + : undefined, + ); + + const { exchanges: swapExchanges } = swapInfo; + + const [firstSwapExchange] = swapExchanges; + + if (swapExchanges.length > 0) options?.logger?.(`Swap exchanges: ${swapExchanges.join(', ')}`); + + if (swapInfo.type === 'exactReceive' && amountBN.lt(swapInfo.minAmountOut)) { + throw new Error(`Amount is too low. Min amountOut is ${swapInfo.minAmountOut} ${assetOut}`); + } + + if (swapInfo.type === 'exactSpend' && amountBN.lt(swapInfo.minAmountIn)) { + throw new Error(`Amount is too low. Min amountIn is ${swapInfo.minAmountIn} ${assetIn}`); + } + + 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}`); + const minQtyBN = new BigNumber(pairConfig.minQty); + const qtyPrecisionBN = new BigNumber(pairConfig.qtyPrecision); + const pricePrecisionBN = new BigNumber(pairConfig.pricePrecision); + const minPrice = new BigNumber(pairConfig.minPrice); + const maxPrice = new BigNumber(pairConfig.maxPrice); + + const qtyDecimalPlaces = amountBN.dp(); + const priceDecimalPlaces = priceBN.dp(); + + if (qtyDecimalPlaces === null) throw new Error('Qty decimal places is null. Likely amount is -Infinity, +Infinity or NaN'); + 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}.` + ); + } + if (priceDecimalPlaces === null) throw new Error('Price decimal places is null. Likely price is -Infinity, +Infinity or NaN'); + if (pricePrecisionBN.lt(priceDecimalPlaces)) { + throw new Error( + `Actual price decimal places (${priceDecimalPlaces}) is greater than max allowed decimal places (${pricePrecisionBN.toString()}) on pair ${baseAssetName}-${quoteAssetName}.` + ); + } + + if (priceBN.lt(minPrice)) { + throw new Error(`Price is too low. Min price is ${minPrice.toString()} ${quoteAssetName}`); + } + if (priceBN.gt(maxPrice)) { + throw new Error(`Price is too high. Max price is ${maxPrice.toString()} ${quoteAssetName}`); + } + + options?.logger?.(`Safe price is ${swapInfo.orderInfo.safePrice} ${quoteAssetName}`); + // BTEMP — better than or equal market price + const priceIsBTEMP = type === 'exactSpend' + ? priceBN.lte(swapInfo.orderInfo.safePrice) + : priceBN.gte(swapInfo.orderInfo.safePrice); + + options?.logger?.(`Your price ${priceBN.toString()} is ${priceIsBTEMP ? 'better than or equal' : 'worse than'} market price ${swapInfo.orderInfo.safePrice}`); + + let route: 'aggregator' | 'pool'; + + if (options?.developer?.route !== undefined) { + if (options.developer.route === 'pool' && !priceIsBTEMP) { + throw new Error( + 'CONFLICT: Pool execution is not available for this swap.' + + ' Price is worse than market price. Please unset "route" option or set it to "aggregator"' + ); + } + route = options.developer.route; + options.logger?.(`Swap is through ${route} (because route forced to ${route})`); + } else if (options?.poolOnly !== undefined && options.poolOnly) { + if (!priceIsBTEMP) { + throw new Error( + 'CONFLICT: Pool execution is not available for this swap.' + + ' Price is worse than market price. Please disable "poolOnly" option' + ); + } + options.logger?.('Swap is through pool (because "poolOnly" option is true)'); + route = 'pool'; + } else if ( + poolExchangesList.length > 0 && + swapExchanges.length === 1 && + firstSwapExchange !== undefined && + poolExchangesList.some((poolExchange) => poolExchange === firstSwapExchange) && + priceIsBTEMP + ) { + options?.logger?.(`Swap is through pool [via ${firstSwapExchange}] (detected by "exchanges" field)`); + route = 'pool'; + } else { + route = 'aggregator'; + } + + if (route === 'pool') { + let factoryAddress: string | undefined; + if (factories && firstSwapExchange !== undefined) { + factoryAddress = factories[firstSwapExchange]; + if (factoryAddress !== undefined) options?.logger?.(`Factory address is ${factoryAddress}. Exchange is ${firstSwapExchange}`); + } + + const pathAddresses = swapInfo.path.map((name) => { + const assetAddress = assetToAddress[name]; + if (assetAddress === undefined) throw new Error(`No asset address for ${name}`); + return assetAddress; + }); + + const amountSpend = swapInfo.type === 'exactSpend' + ? swapInfo.amountIn + : new BigNumber(swapInfo.orderInfo.amount).multipliedBy(swapInfo.orderInfo.safePrice) + + balanceGuard.registerRequirement({ + reason: 'Amount spend', + asset: { + name: assetIn, + address: assetInAddress, + }, + amount: amountSpend.toString(), + spenderAddress: exchangeContractAddress, + sources: getAvailableSources('amount', assetInAddress, 'orion_pool'), + }); + + const amountReceive = swapInfo.type === 'exactReceive' + ? swapInfo.amountOut + : new BigNumber(swapInfo.orderInfo.amount).multipliedBy(swapInfo.orderInfo.safePrice) + const amountSpendBlockchainParam = normalizeNumber( + amountSpend, + INTERNAL_ORION_PRECISION, + BigNumber.ROUND_CEIL, + ); + const amountReceiveBlockchainParam = normalizeNumber( + amountReceive, + INTERNAL_ORION_PRECISION, + BigNumber.ROUND_FLOOR, + ); + + const unsignedSwapThroughOrionPoolTx = await exchangeContract.populateTransaction.swapThroughOrionPool( + amountSpendBlockchainParam, + amountReceiveBlockchainParam, + factoryAddress !== undefined + ? [factoryAddress, ...pathAddresses] + : pathAddresses, + type === 'exactSpend', + ); + + unsignedSwapThroughOrionPoolTx.chainId = parseInt(chainId, 10); + unsignedSwapThroughOrionPoolTx.gasPrice = ethers.BigNumber.from(gasPriceWei); + + unsignedSwapThroughOrionPoolTx.from = walletAddress; + const amountSpendBN = new BigNumber(amountSpend); + + let value = new BigNumber(0); + const denormalizedAssetInExchangeBalance = balances[assetIn]?.exchange; + if (denormalizedAssetInExchangeBalance === undefined) throw new Error(`Asset '${assetIn}' exchange balance is not found`); + if (assetIn === nativeCryptocurrency && amountSpendBN.gt(denormalizedAssetInExchangeBalance)) { + value = amountSpendBN.minus(denormalizedAssetInExchangeBalance); + } + unsignedSwapThroughOrionPoolTx.value = normalizeNumber( + value.dp(INTERNAL_ORION_PRECISION, BigNumber.ROUND_CEIL), + NATIVE_CURRENCY_PRECISION, + BigNumber.ROUND_CEIL, + ); + unsignedSwapThroughOrionPoolTx.gasLimit = ethers.BigNumber.from(SWAP_THROUGH_ORION_POOL_GAS_LIMIT); + + const transactionCost = ethers.BigNumber.from(SWAP_THROUGH_ORION_POOL_GAS_LIMIT).mul(gasPriceWei); + const denormalizedTransactionCost = denormalizeNumber(transactionCost, NATIVE_CURRENCY_PRECISION); + + balanceGuard.registerRequirement({ + reason: 'Network fee', + asset: { + name: nativeCryptocurrency, + address: ethers.constants.AddressZero, + }, + amount: denormalizedTransactionCost.toString(), + sources: getAvailableSources('network_fee', ethers.constants.AddressZero, 'orion_pool'), + }); + + // if (value.gt(0)) { + // balanceGuard.registerRequirement({ + // reason: 'Transaction value (extra amount)', + // asset: { + // name: nativeCryptocurrency, + // address: ethers.constants.AddressZero, + // }, + // amount: value.toString(), + // sources: getAvailableSources('amount', ethers.constants.AddressZero, 'orion_pool'), + // }); + // } + + await balanceGuard.check(options?.autoApprove); + + const nonce = await provider.getTransactionCount(walletAddress, 'pending'); + unsignedSwapThroughOrionPoolTx.nonce = nonce; + + options?.logger?.('Signing transaction...'); + const swapThroughOrionPoolTxResponse = await signer.sendTransaction(unsignedSwapThroughOrionPoolTx); + options?.logger?.(`Transaction sent. Tx hash: ${swapThroughOrionPoolTxResponse.hash}`); + return { + amountOut: swapInfo.amountOut, + wait: swapThroughOrionPoolTxResponse.wait, + through: 'orion_pool', + txHash: swapThroughOrionPoolTxResponse.hash, + }; + } + options?.logger?.('Swap through aggregator'); + + if (amountBN.lt(minQtyBN)) { + throw new Error(`Amount is too low. Min amount is ${minQtyBN.toString()} ${baseAssetName}`); + } + + const baseAssetAddress = assetToAddress[baseAssetName]; + if (baseAssetAddress === undefined) throw new Error(`No asset address for ${baseAssetName}`); + const quoteAssetAddress = assetToAddress[quoteAssetName]; + if (quoteAssetAddress === undefined) throw new Error(`No asset address for ${quoteAssetName}`); + + const safePriceWithAppliedPrecision = priceBN + .decimalPlaces( + pairConfig.pricePrecision, + swapInfo.orderInfo.side === 'BUY' + ? BigNumber.ROUND_CEIL + : BigNumber.ROUND_FLOOR, + ); + + balanceGuard.registerRequirement({ + reason: 'Amount', + asset: { + name: assetIn, + address: assetInAddress, + }, + amount: swapInfo.orderInfo.side === 'SELL' + ? swapInfo.orderInfo.amount.toString() + : safePriceWithAppliedPrecision.multipliedBy(swapInfo.orderInfo.amount).toString(), + spenderAddress: exchangeContractAddress, + sources: getAvailableSources('amount', assetInAddress, 'aggregator'), + }); + + // 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 feePercent = feeAssets[feeAsset]; + if (feePercent === undefined) throw new Error(`Fee asset ${feeAsset} not available`); + + const { orionFeeInFeeAsset, networkFeeInFeeAsset, totalFeeInFeeAsset } = calculateFeeInFeeAsset( + swapInfo.orderInfo.amount, + feeAssetPriceInOrn, + baseAssetPriceInOrn, + baseCurrencyPriceInOrn, + gasPriceGwei, + feePercent, + ); + + if (feeAsset === assetOut) { + options?.logger?.('Fee asset equals received asset. The fee can be paid from the amount received'); + options?.logger?.(`Set extra balance: + ${swapInfo.amountOut} ${assetOut} to exchange`); + + balanceGuard.setExtraBalance(feeAsset, swapInfo.amountOut, 'exchange'); + } + + balanceGuard.registerRequirement({ + reason: 'Network fee', + asset: { + name: feeAsset, + address: feeAssetAddress, + }, + amount: networkFeeInFeeAsset, + spenderAddress: exchangeContractAddress, + sources: getAvailableSources('network_fee', feeAssetAddress, 'aggregator'), + }); + + balanceGuard.registerRequirement({ + reason: 'Orion fee', + asset: { + name: feeAsset, + address: feeAssetAddress, + }, + amount: orionFeeInFeeAsset, + spenderAddress: exchangeContractAddress, + sources: getAvailableSources('orion_fee', feeAssetAddress, 'aggregator'), + }); + + await balanceGuard.check(options?.autoApprove); + + const signedOrder = await signOrder( + baseAssetAddress, + quoteAssetAddress, + swapInfo.orderInfo.side, + safePriceWithAppliedPrecision.toString(), + swapInfo.orderInfo.amount, + totalFeeInFeeAsset, + walletAddress, + matcherAddress, + feeAssetAddress, + false, + signer, + chainId, + ); + const orderIsOk = await exchangeContract.validateOrder(signedOrder); + 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 { + amountOut: amountBN.multipliedBy(safePriceWithAppliedPrecision).toNumber(), + wait: () => new Promise>((resolve, reject) => { + const timeout = setTimeout(() => { + reject(new Error('Timeout')) + }, 60000); + const interval = setInterval(() => { + simpleFetch(orionAggregator.getOrder)(orderId).then((data) => { + if (data.order.status === 'SETTLED') { + options?.logger?.(`Order ${orderId} settled`); + clearTimeout(timeout); + clearInterval(interval); + resolve(data); + } else { + options?.logger?.(`Order ${orderId} status: ${data.order.status}`); + } + }).catch((e) => { + if (!(e instanceof Error)) throw new Error('Not an error'); + options?.logger?.(`Error while getting order status: ${e.message}`); + }); + }, 1000); + }), + through: 'aggregator', + id: orderId, + }; +} diff --git a/src/OrionUnit/Exchange/swapMarket.ts b/src/OrionUnit/Exchange/swapMarket.ts index be8d217..92755ea 100644 --- a/src/OrionUnit/Exchange/swapMarket.ts +++ b/src/OrionUnit/Exchange/swapMarket.ts @@ -4,7 +4,6 @@ import { Exchange__factory } from '@orionprotocol/contracts'; import getBalances from '../../utils/getBalances'; import BalanceGuard from '../../BalanceGuard'; import getAvailableSources from '../../utils/getAvailableFundsSources'; -import type OrionUnit from '..'; import { INTERNAL_ORION_PRECISION, NATIVE_CURRENCY_PRECISION, SWAP_THROUGH_ORION_POOL_GAS_LIMIT } from '../../constants'; import getNativeCryptocurrency from '../../utils/getNativeCryptocurrency'; import simpleFetch from '../../simpleFetch'; @@ -12,26 +11,10 @@ import { calculateFeeInFeeAsset, denormalizeNumber, normalizeNumber } from '../. import { signOrder } from '../../crypt'; import type orderSchema from '../../services/OrionAggregator/schemas/orderSchema'; import type { z } from 'zod'; +import type { SwapLimitParams } from './swapLimit'; -export type SwapMarketParams = { - type: 'exactSpend' | 'exactReceive' - assetIn: string - assetOut: string - amount: BigNumber.Value - feeAsset: string +export type SwapMarketParams = Omit & { slippagePercent: BigNumber.Value - signer: ethers.Signer - orionUnit: OrionUnit - options?: { - // rounding?: 'up' | 'down' TODO - poolOnly?: boolean - instantSettlement?: boolean - logger?: (message: string) => void - autoApprove?: boolean - developer?: { - route?: 'aggregator' | 'pool' - } - } } type AggregatorOrder = { diff --git a/src/config/envs.json b/src/config/envs.json index 10ca282..b2bc672 100644 --- a/src/config/envs.json +++ b/src/config/envs.json @@ -101,22 +101,6 @@ }, "liquidityMigratorAddress": "0x01b10dds12478C88A5E18e2707E729906bC25CfF6" }, - "3": { - "api": "https://testing.orionprotocol.io/eth-ropsten", - "services": { - "aggregator": { - "http": "/backend", - "ws": "/v1" - }, - "blockchain": { - "http": "" - }, - "priceFeed": { - "all": "/price-feed" - } - }, - "liquidityMigratorAddress": "0x36969a25622AE31bA9946e0c8151f0dc08b3A1c8" - }, "5": { "api": "https://testing.orionprotocol.io/eth-goerli", "services": { diff --git a/tsconfig.json b/tsconfig.json index 02ef5dc..2a50607 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,7 @@ "./src/index.ts" ], "include": [ - "./src/**/*.ts", + "./src/**/*.ts" ], "exclude": [ "node_modules",