From 5c9b23e9d5c47245c2bbb8636d3194a189e7b56c Mon Sep 17 00:00:00 2001 From: sdgoh Date: Wed, 28 Oct 2020 06:46:12 +0800 Subject: [PATCH 1/7] Merge dev into master --- .eslintignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .eslintignore diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..0980665 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +# turn off specific file for eslint +/*.js \ No newline at end of file From ad859e55fc5a788e0f8bb85a4432879ed91cf4e3 Mon Sep 17 00:00:00 2001 From: james-hummingbot Date: Thu, 3 Jun 2021 13:18:06 +0200 Subject: [PATCH 2/7] Apply simplified lint rules to all files and make eslint a part of the precommit --- .eslintrc.js | 33 +- package.json | 6 +- src/app.js | 38 +- src/index.js | 78 +- src/routes/balancer.route.js | 306 +-- src/routes/celo.route.js | 272 +- src/routes/eth.route.js | 377 ++- src/routes/index.route.js | 2 +- src/routes/perpetual_finance.route.js | 474 ++-- src/routes/terra.route.js | 207 +- src/routes/uniswap.route.js | 309 ++- src/services/access.js | 25 +- src/services/balancer.js | 191 +- src/services/eth.js | 168 +- src/services/fees.js | 57 +- src/services/logger.js | 39 +- src/services/perpetual_finance.js | 346 ++- src/services/terra.js | 355 +-- src/services/uniswap.js | 209 +- src/services/utils.js | 93 +- yarn.lock | 3443 +++++++++++++------------ 21 files changed, 3641 insertions(+), 3387 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 8156b59..96a7ca9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,14 +1,27 @@ module.exports = { - extends: 'standard', + extends: 'airbnb-base', + env: { + node: true, + }, rules: { - // disable semicolon check - semi: 'off', - - // override default options for rules from base configurations - 'comma-dangle': 'off', - - // disable rules from base configurations + camelcase: 'off', + 'consistent-return': 'off', + 'class-methods-use-this': 'off', + 'guard-for-in': 'off', + 'import/prefer-default-export': 'off', + 'max-len': 'off', + 'no-await-in-loop': 'off', + 'no-case-declarations': 'off', 'no-console': 'off', - 'no-multi-spaces': 'off', - } + 'no-mixed-operators': 'off', + 'no-plusplus': 'off', + 'no-prototype-builtins': 'off', + 'no-restricted-syntax': 'off', + 'no-return-assign': 'off', + 'no-unused-expressions': 'off', + 'no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + 'no-underscore-dangle': 'off', + 'prefer-destructuring': 'off', + radix: 'off', + }, }; diff --git a/package.json b/package.json index 817ee0d..40b9c09 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "start": "babel-node src/index.js", "dev": "nodemon --exec babel-node src/index.js", "debug": "DEBUG=*router nodemon --exec babel-node src/index.js", + "lint": "node_modules/.bin/eslint src --format table", "test": "echo \"Error: no test specified\" && exit 1" }, "dependencies": { @@ -40,9 +41,10 @@ "@babel/core": "^7.11.6", "@babel/node": "^7.10.5", "@babel/preset-env": "^7.11.5", - "eslint": "^7.10.0", + "eslint": "^7.27.0", + "eslint-config-airbnb-base": "^14.2.1", "eslint-config-standard": "^14.1.1", - "eslint-plugin-import": "^2.22.1", + "eslint-plugin-import": "^2.23.3", "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^4.2.1", "eslint-plugin-standard": "^4.0.1", diff --git a/src/app.js b/src/app.js index 647b14f..81ff332 100644 --- a/src/app.js +++ b/src/app.js @@ -1,20 +1,20 @@ import dotenv from 'dotenv'; -import bodyParser from 'body-parser' -import express from 'express' -import helmet from 'helmet' +import bodyParser from 'body-parser'; +import express from 'express'; +import helmet from 'helmet'; +import { IpFilter } from 'express-ipfilter'; import { statusMessages } from './services/utils'; import { validateAccess } from './services/access'; -import { IpFilter } from 'express-ipfilter' import { logger } from './services/logger'; // Routes -import apiRoutes from './routes/index.route' -import balancerRoutes from './routes/balancer.route' +import apiRoutes from './routes/index.route'; +import balancerRoutes from './routes/balancer.route'; // import celoRoutes from './routes/celo.route' -import ethRoutes from './routes/eth.route' -import terraRoutes from './routes/terra.route' -import uniswapRoutes from './routes/uniswap.route' -import perpFiRoutes from './routes/perpetual_finance.route' +import ethRoutes from './routes/eth.route'; +import terraRoutes from './routes/terra.route'; +import uniswapRoutes from './routes/uniswap.route'; +import perpFiRoutes from './routes/perpetual_finance.route'; // terminate if environment not found const result = dotenv.config(); @@ -33,12 +33,12 @@ app.use(helmet()); const ipWhitelist = process.env.IP_WHITELIST; if (ipWhitelist) { - app.use(IpFilter(JSON.parse(ipWhitelist), { mode: 'allow' })) + app.use(IpFilter(JSON.parse(ipWhitelist), { mode: 'allow' })); } app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); -app.use(validateAccess) +app.use(validateAccess); // mount routes to specific path app.use('/api', apiRoutes); @@ -49,19 +49,19 @@ app.use('/terra', terraRoutes); app.use('/perpfi', perpFiRoutes); // app.use('/celo', celoRoutes); -app.get('/', (req, res, next) => { - res.send('ok') -}) +app.get('/', (req, res, _next) => { + res.send('ok'); +}); /** * Catch all 404 response when routes are not found */ -app.use((req, res, next) => { - const message = `${statusMessages.page_not_found} at ${req.originalUrl}` - logger.error(message) +app.use((req, res, _next) => { + const message = `${statusMessages.page_not_found} at ${req.originalUrl}`; + logger.error(message); res.status(404).send({ error: 'Page not found', - message: message + message, }); }); diff --git a/src/index.js b/src/index.js index 957acc3..4e977dd 100644 --- a/src/index.js +++ b/src/index.js @@ -1,13 +1,13 @@ #!/usr/bin/env node // absolute imports -import https from 'https' -import dotenv from 'dotenv' -import fs from 'fs' +import https from 'https'; +import dotenv from 'dotenv'; +import fs from 'fs'; // relative imports -import app from './app' -import { logger } from './services/logger' +import app from './app'; +import { logger } from './services/logger'; // terminate if environment not found const result = dotenv.config(); @@ -16,22 +16,22 @@ if (result.error) { process.exit(1); } -const env = process.env.NODE_ENV -const port = process.env.PORT -const certPassphrase = process.env.CERT_PASSPHRASE -const ethereumChain = process.env.ETHEREUM_CHAIN -const terraChain = process.env.TERRA_CHAIN -let certPath = process.env.CERT_PATH +const env = process.env.NODE_ENV; +const port = process.env.PORT; +const certPassphrase = process.env.CERT_PASSPHRASE; +const ethereumChain = process.env.ETHEREUM_CHAIN; +const terraChain = process.env.TERRA_CHAIN; +let certPath = process.env.CERT_PATH; if ((typeof certPath === 'undefined' && certPath == null) || certPath === '') { // assuming it is local development using test script to generate certs - certPath = './certs' + certPath = './certs'; } else { certPath = certPath.replace(/\/$/, ''); } // set app environment -app.set('env', env) +app.set('env', env); const options = { key: fs.readFileSync(certPath.concat('/server_key.pem'), { encoding: 'utf-8' }), cert: fs.readFileSync(certPath.concat('/server_cert.pem'), { encoding: 'utf-8' }), @@ -41,51 +41,53 @@ const options = { rejectUnauthorized: true, // use ca cert created with own key for self-signed ca: [fs.readFileSync(certPath.concat('/ca_cert.pem'), { encoding: 'utf-8' })], - passphrase: certPassphrase + passphrase: certPassphrase, }; -const server = https.createServer(options, app) +const server = https.createServer(options, app); // event listener for "error" event -const onError = error => { +const onError = (error) => { if (error.syscall !== 'listen') { - throw error + throw error; } - const bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port + const bind = typeof port === 'string' ? `Pipe ${port}` : `Port ${port}`; // handle specific listen errors with friendly messages switch (error.code) { case 'EACCES': - console.error(bind + ' requires elevated privileges') - process.exit(1) + console.error(`${bind} requires elevated privileges`); + process.exit(1); + break; case 'EADDRINUSE': - console.error(bind + ' is already in use') - process.exit(1) + console.error(`${bind} is already in use`); + process.exit(1); + break; default: - throw error + throw error; } -} +}; // event listener for "listening" event. const onListening = () => { - const addr = server.address() - const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port - console.log('listening on ' + bind) - logger.debug('listening on ' + bind) -} + const addr = server.address(); + const bind = typeof addr === 'string' ? `pipe ${addr}` : `port ${addr.port}`; + console.log(`listening on ${bind}`); + logger.debug(`listening on ${bind}`); +}; // listen on provided port, on all network interfaces. -server.listen(port) -server.on('error', onError) -server.on('listening', onListening) +server.listen(port); +server.on('error', onError); +server.on('listening', onListening); const serverConfig = { app: 'gateway-api', - port: port, - ethereumChain: ethereumChain, - terraChain: terraChain -} + port, + ethereumChain, + terraChain, +}; -logger.info(JSON.stringify(serverConfig)) -console.log(serverConfig) +logger.info(JSON.stringify(serverConfig)); +console.log(serverConfig); diff --git a/src/routes/balancer.route.js b/src/routes/balancer.route.js index a27fe5d..358bd9d 100644 --- a/src/routes/balancer.route.js +++ b/src/routes/balancer.route.js @@ -2,26 +2,29 @@ import BigNumber from 'bignumber.js'; import { ethers } from 'ethers'; import express from 'express'; -import { getParamData, latency, reportConnectionError, statusMessages } from '../services/utils'; +import { + getParamData, latency, statusMessages, +} from '../services/utils'; import Ethereum from '../services/eth'; import Balancer from '../services/balancer'; import Fees from '../services/fees'; import { logger } from '../services/logger'; -const debug = require('debug')('router') -const router = express.Router() -const eth = new Ethereum(process.env.ETHEREUM_CHAIN) -const balancer = new Balancer(process.env.ETHEREUM_CHAIN) -const fees = new Fees() +const debug = require('debug')('router'); -const swapMoreThanMaxPriceError = 'Price too high' -const swapLessThanMaxPriceError = 'Price too low' +const router = express.Router(); +const eth = new Ethereum(process.env.ETHEREUM_CHAIN); +const balancer = new Balancer(process.env.ETHEREUM_CHAIN); +const fees = new Fees(); + +const swapMoreThanMaxPriceError = 'Price too high'; +const swapLessThanMaxPriceError = 'Price too low'; const estimateGasLimit = (maxswaps) => { - const gasLimit = balancer.gasBase + maxswaps * balancer.gasPerSwap - return gasLimit -} + const gasLimit = balancer.gasBase + maxswaps * balancer.gasPerSwap; + return gasLimit; +}; router.post('/', async (req, res) => { /* @@ -34,8 +37,8 @@ router.post('/', async (req, res) => { subgraphUrl: balancer.subgraphUrl, connection: true, timestamp: Date.now(), - }) -}) + }); +}); router.post('/gas-limit', async (req, res) => { /* @@ -44,85 +47,84 @@ router.post('/gas-limit', async (req, res) => { "maxSwaps":4 } */ - const paramData = getParamData(req.body) + const paramData = getParamData(req.body); try { - const swaps = paramData.maxSwaps - const maxSwaps = typeof swaps === 'undefined' || parseInt(swaps) === 0 ? balancer.maxSwaps : parseInt(swaps) - const gasLimit = estimateGasLimit(maxSwaps) + const swaps = paramData.maxSwaps; + const maxSwaps = typeof swaps === 'undefined' || parseInt(swaps) === 0 ? balancer.maxSwaps : parseInt(swaps); + const gasLimit = estimateGasLimit(maxSwaps); res.status(200).json({ network: balancer.network, - gasLimit: gasLimit, + gasLimit, timestamp: Date.now(), - }) + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); router.get('/start', async (req, res) => { - /* + /* POST: /eth/balancer/start x-www-form-urlencoded: { "pairs":'["ETH-USDT", ...]' "gasPrice":30 } */ - const initTime = Date.now() - const paramData = getParamData(req.query) - const pairs = JSON.parse(paramData.pairs) - let gasPrice + const initTime = Date.now(); + const paramData = getParamData(req.query); + const pairs = JSON.parse(paramData.pairs); + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } // get token contract address and cache pools - for (let pair of pairs){ - pair = pair.split("-") - const baseTokenSymbol = pair[0] - const quoteTokenSymbol = pair[1] - const baseTokenContractInfo = eth.getERC20TokenAddresses(baseTokenSymbol) - const quoteTokenContractInfo = eth.getERC20TokenAddresses(quoteTokenSymbol) + for (let pair of pairs) { + pair = pair.split('-'); + const baseTokenSymbol = pair[0]; + const quoteTokenSymbol = pair[1]; + const baseTokenContractInfo = eth.getERC20TokenAddresses(baseTokenSymbol); + const quoteTokenContractInfo = eth.getERC20TokenAddresses(quoteTokenSymbol); // check for valid token symbols if (baseTokenContractInfo === undefined || quoteTokenContractInfo === undefined) { - const undefinedToken = baseTokenContractInfo === undefined ? baseTokenSymbol : quoteTokenSymbol + const undefinedToken = baseTokenContractInfo === undefined ? baseTokenSymbol : quoteTokenSymbol; res.status(500).json({ error: `Token ${undefinedToken} contract address not found`, message: `Token contract address not found for ${undefinedToken}. Check token list source`, - }) - return + }); + return; } await Promise.allSettled([balancer.fetchPool(baseTokenContractInfo.address, quoteTokenContractInfo.address), - balancer.fetchPool(quoteTokenContractInfo.address, baseTokenContractInfo.address)]) + balancer.fetchPool(quoteTokenContractInfo.address, baseTokenContractInfo.address)]); } - - const gasLimit = estimateGasLimit(balancer.maxSwaps) - const gasCost = await fees.getGasCost(gasPrice, gasLimit) + const gasLimit = estimateGasLimit(balancer.maxSwaps); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); const result = { network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), success: true, - pairs: pairs, - gasPrice: gasPrice, - gasLimit: gasLimit, - gasCost: gasCost, - } - console.log('Initializing balancer') - res.status(200).json(result) -}) + pairs, + gasPrice, + gasLimit, + gasCost, + }; + console.log('Initializing balancer'); + res.status(200).json(result); +}); router.post('/price', async (req, res) => { /* @@ -134,48 +136,48 @@ router.post('/price', async (req, res) => { "side":buy } */ - const initTime = Date.now() + const initTime = Date.now(); // params: base (required), quote (required), amount (required) - const paramData = getParamData(req.body) - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base) - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote) - const baseTokenAddress = baseTokenContractInfo.address - const quoteTokenAddress = quoteTokenContractInfo.address - const baseDenomMultiplier = 10 ** baseTokenContractInfo.decimals - const quoteDenomMultiplier = 10 ** quoteTokenContractInfo.decimals - const amount = new BigNumber(parseInt(paramData.amount * baseDenomMultiplier)) - const maxSwaps = balancer.maxSwaps - const side = paramData.side.toUpperCase() - let gasPrice + const paramData = getParamData(req.body); + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base); + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote); + const baseTokenAddress = baseTokenContractInfo.address; + const quoteTokenAddress = quoteTokenContractInfo.address; + const baseDenomMultiplier = 10 ** baseTokenContractInfo.decimals; + const quoteDenomMultiplier = 10 ** quoteTokenContractInfo.decimals; + const amount = new BigNumber(parseInt(paramData.amount * baseDenomMultiplier)); + const maxSwaps = balancer.maxSwaps; + const side = paramData.side.toUpperCase(); + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } try { // fetch the optimal pool mix from balancer-sor const { swaps, expectedAmount } = side === 'BUY' ? await balancer.priceSwapOut( - quoteTokenAddress, // tokenIn is quote asset - baseTokenAddress, // tokenOut is base asset + quoteTokenAddress, // tokenIn is quote asset + baseTokenAddress, // tokenOut is base asset amount, maxSwaps, ) : await balancer.priceSwapIn( - baseTokenAddress, // tokenIn is base asset - quoteTokenAddress, // tokenOut is quote asset + baseTokenAddress, // tokenIn is base asset + quoteTokenAddress, // tokenOut is quote asset amount, maxSwaps, - ) + ); if (swaps != null && expectedAmount != null) { - const gasLimit = estimateGasLimit(swaps.length) - const gasCost = await fees.getGasCost(gasPrice, gasLimit) + const gasLimit = estimateGasLimit(swaps.length); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); - const tradeAmount = parseFloat(amount) - const expectedTradeAmount = parseInt(expectedAmount) / quoteDenomMultiplier - const tradePrice = expectedAmount / amount * baseDenomMultiplier / quoteDenomMultiplier + const tradeAmount = parseFloat(amount); + const expectedTradeAmount = parseInt(expectedAmount) / quoteDenomMultiplier; + const tradePrice = expectedAmount / amount * baseDenomMultiplier / quoteDenomMultiplier; const result = { network: balancer.network, @@ -184,32 +186,32 @@ router.post('/price', async (req, res) => { base: baseTokenContractInfo, quote: quoteTokenContractInfo, amount: tradeAmount, - side: side, + side, expectedAmount: expectedTradeAmount, price: tradePrice, - gasPrice: gasPrice, - gasLimit: gasLimit, - gasCost: gasCost, - swaps: swaps, - } - debug(`Price ${side} ${baseTokenContractInfo.symbol}-${quoteTokenContractInfo.symbol} | amount:${amount} (rate:${tradePrice}) - gasPrice:${gasPrice} gasLimit:${gasLimit} estimated fee:${gasCost} ETH`) - res.status(200).json(result) + gasPrice, + gasLimit, + gasCost, + swaps, + }; + debug(`Price ${side} ${baseTokenContractInfo.symbol}-${quoteTokenContractInfo.symbol} | amount:${amount} (rate:${tradePrice}) - gasPrice:${gasPrice} gasLimit:${gasLimit} estimated fee:${gasCost} ETH`); + res.status(200).json(result); } else { // no pool available res.status(200).json({ info: statusMessages.no_pool_available, - message: statusMessages.no_pool_available - }) + message: statusMessages.no_pool_available, + }); } } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); router.post('/trade', async (req, res) => { /* @@ -224,65 +226,65 @@ router.post('/trade', async (req, res) => { "privateKey":{{privateKey}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - const wallet = new ethers.Wallet(privateKey, balancer.provider) + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + const wallet = new ethers.Wallet(privateKey, balancer.provider); - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base) - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote) - const baseTokenAddress = baseTokenContractInfo.address - const quoteTokenAddress = quoteTokenContractInfo.address - const baseDenomMultiplier = 10 ** baseTokenContractInfo.decimals - const quoteDenomMultiplier = 10 ** quoteTokenContractInfo.decimals - const amount = new BigNumber(parseInt(paramData.amount * baseDenomMultiplier)) + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base); + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote); + const baseTokenAddress = baseTokenContractInfo.address; + const quoteTokenAddress = quoteTokenContractInfo.address; + const baseDenomMultiplier = 10 ** baseTokenContractInfo.decimals; + const quoteDenomMultiplier = 10 ** quoteTokenContractInfo.decimals; + const amount = new BigNumber(parseInt(paramData.amount * baseDenomMultiplier)); - const maxSwaps = balancer.maxSwaps - const side = paramData.side.toUpperCase() + const maxSwaps = balancer.maxSwaps; + const side = paramData.side.toUpperCase(); - let limitPrice + let limitPrice; if (paramData.limitPrice) { - limitPrice = parseFloat(paramData.limitPrice) + limitPrice = parseFloat(paramData.limitPrice); } - let gasPrice + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } try { // fetch the optimal pool mix from balancer-sor const { swaps, expectedAmount } = side === 'BUY' ? await balancer.priceSwapOut( - quoteTokenAddress, // tokenIn is quote asset - baseTokenAddress, // tokenOut is base asset + quoteTokenAddress, // tokenIn is quote asset + baseTokenAddress, // tokenOut is base asset amount, maxSwaps, ) : await balancer.priceSwapIn( - baseTokenAddress, // tokenIn is base asset - quoteTokenAddress, // tokenOut is quote asset + baseTokenAddress, // tokenIn is base asset + quoteTokenAddress, // tokenOut is quote asset amount, maxSwaps, - ) + ); - const gasLimit = estimateGasLimit(swaps.length) - const gasCost = await fees.getGasCost(gasPrice, gasLimit) + const gasLimit = estimateGasLimit(swaps.length); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); if (side === 'BUY') { - const price = expectedAmount / amount * baseDenomMultiplier / quoteDenomMultiplier - logger.info(`Price: ${price.toString()}`) + const price = expectedAmount / amount * baseDenomMultiplier / quoteDenomMultiplier; + logger.info(`Price: ${price.toString()}`); if (!limitPrice || price <= limitPrice) { // pass swaps to exchange-proxy to complete trade const tx = await balancer.swapExactOut( wallet, swaps, - quoteTokenAddress, // tokenIn is quote asset - baseTokenAddress, // tokenOut is base asset + quoteTokenAddress, // tokenIn is quote asset + baseTokenAddress, // tokenOut is base asset expectedAmount.toString(), gasPrice, - ) + ); // submit response res.status(200).json({ @@ -293,36 +295,36 @@ router.post('/trade', async (req, res) => { quote: quoteTokenContractInfo, amount: parseFloat(paramData.amount), expectedIn: expectedAmount / quoteDenomMultiplier, - price: price, - gasPrice: gasPrice, - gasLimit: gasLimit, - gasCost: gasCost, + price, + gasPrice, + gasLimit, + gasCost, txHash: tx.hash, - }) + }); } else { res.status(200).json({ error: swapMoreThanMaxPriceError, - message: `Swap price ${price} exceeds limitPrice ${limitPrice}` - }) - debug(`Swap price ${price} exceeds limitPrice ${limitPrice}`) + message: `Swap price ${price} exceeds limitPrice ${limitPrice}`, + }); + debug(`Swap price ${price} exceeds limitPrice ${limitPrice}`); } } else { // sell - const minAmountOut = limitPrice / amount * baseDenomMultiplier - debug('minAmountOut', minAmountOut) - const price = expectedAmount / amount * baseDenomMultiplier / quoteDenomMultiplier - logger.info(`Price: ${price.toString()}`) + const minAmountOut = limitPrice / amount * baseDenomMultiplier; + debug('minAmountOut', minAmountOut); + const price = expectedAmount / amount * baseDenomMultiplier / quoteDenomMultiplier; + logger.info(`Price: ${price.toString()}`); if (!limitPrice || price >= limitPrice) { // pass swaps to exchange-proxy to complete trade const tx = await balancer.swapExactIn( wallet, swaps, - baseTokenAddress, // tokenIn is base asset - quoteTokenAddress, // tokenOut is quote asset + baseTokenAddress, // tokenIn is base asset + quoteTokenAddress, // tokenOut is quote asset amount.toString(), parseInt(expectedAmount) / quoteDenomMultiplier, gasPrice, - ) + ); // submit response res.status(200).json({ network: balancer.network, @@ -332,29 +334,29 @@ router.post('/trade', async (req, res) => { quote: quoteTokenContractInfo, amount: parseFloat(paramData.amount), expectedOut: expectedAmount / quoteDenomMultiplier, - price: price, - gasPrice: gasPrice, - gasLimit: gasLimit, - gasCost: gasCost, + price, + gasPrice, + gasLimit, + gasCost, txHash: tx.hash, - }) + }); } else { res.status(200).json({ error: swapLessThanMaxPriceError, - message: `Swap price ${price} lower than limitPrice ${limitPrice}` - }) - debug(`Swap price ${price} lower than limitPrice ${limitPrice}`) + message: `Swap price ${price} lower than limitPrice ${limitPrice}`, + }); + debug(`Swap price ${price} lower than limitPrice ${limitPrice}`); } } } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); export default router; diff --git a/src/routes/celo.route.js b/src/routes/celo.route.js index a5ad910..f305edc 100644 --- a/src/routes/celo.route.js +++ b/src/routes/celo.route.js @@ -1,26 +1,26 @@ -'use strict' +const express = require('express'); -const express = require('express') -const router = express.Router() +const router = express.Router(); const BigNumber = require('bignumber.js'); -const debug = require('debug')('router') -const spawn = require('child_process').spawn +const debug = require('debug')('router'); +const spawn = require('child_process').spawn; -const network = 'celo' -const celocli = 'celocli' -const DENOM_UNIT_MULTIPLIER = BigNumber('1e+18') +const network = 'celo'; +const celocli = 'celocli'; +const DENOM_UNIT_MULTIPLIER = BigNumber('1e+18'); -const hbUtils = require('../services/utils') -const separator = '=>' +const hbUtils = require('../services/utils'); + +const separator = '=>'; router.use((req, res, next) => { - debug('celo route:', Date.now()) - next() -}) + debug('celo route:', Date.now()); + next(); +}); router.get('/', (req, res) => { - res.status(200).send(network) -}) + res.status(200).send(network); +}); router.get('/status', (req, res) => { /* @@ -29,147 +29,143 @@ router.get('/status', (req, res) => { const nodeSync = spawn(celocli, ['node:synced']); - let err_message = [], out_message = [] + const err_message = []; const + out_message = []; - nodeSync.stdout.on( 'data', out => { - out_message.push(out.toString().trim()) - debug('out_message', out_message) - }) + nodeSync.stdout.on('data', (out) => { + out_message.push(out.toString().trim()); + debug('out_message', out_message); + }); - nodeSync.stderr.on( 'data', err => { - err_message.push(err.toString().trim()) - debug('err_message', err_message) - }) + nodeSync.stderr.on('data', (err) => { + err_message.push(err.toString().trim()); + debug('err_message', err_message); + }); - nodeSync.on( 'close', code => { + nodeSync.on('close', (code) => { if (code === 0) { res.status(200).json({ synced: out_message[0].toLowerCase() === 'true', - message: err_message.join('') - }) + message: err_message.join(''), + }); } else { res.status(401).json({ - error: err_message.join('') - }) + error: err_message.join(''), + }); } - }) -}) - + }); +}); router.get('/price', (req, res) => { /* api request format: /price?trading_pair=CELO-CUSD&trade_type=sell&amount=1.2345 */ - const keyFormat = ['trading_pair', 'trade_type', 'amount'] + const keyFormat = ['trading_pair', 'trade_type', 'amount']; - const initTime = Date.now() + const initTime = Date.now(); - const paramData = hbUtils.getParamData(req.query, keyFormat) - const tradingPair = paramData.trading_pair - const tradeType = paramData.trade_type - const requestAmount = paramData.amount - const amount = parseFloat(requestAmount) * DENOM_UNIT_MULTIPLIER - debug('params', req.params) - debug('paramData', paramData) + const paramData = hbUtils.getParamData(req.query, keyFormat); + const tradingPair = paramData.trading_pair; + const requestAmount = paramData.amount; + const amount = parseFloat(requestAmount) * DENOM_UNIT_MULTIPLIER; + debug('params', req.params); + debug('paramData', paramData); - const nodeSync = spawn(celocli, ["exchange:show", "--amount", amount]); + const nodeSync = spawn(celocli, ['exchange:show', '--amount', amount]); - let err_message = [], out_message = [] + const err_message = []; const + out_message = []; - nodeSync.stdout.on( 'data', out => { - out_message.push(out.toString().trim()) - }) + nodeSync.stdout.on('data', (out) => { + out_message.push(out.toString().trim()); + }); - nodeSync.stderr.on( 'data', err => { - err_message.push(err.toString().trim()) - }) + nodeSync.stderr.on('data', (err) => { + err_message.push(err.toString().trim()); + }); - nodeSync.on( 'close', code => { - - let exchange_rates = {} - let price + nodeSync.on('close', (code) => { + const exchange_rates = {}; + let price; if (code === 0) { // extract exchange rate from cli output - out_message.forEach((item, index) => { + out_message.forEach((item, _index) => { if (item.includes(separator)) { - let exchangeInfo = item.split(separator) - let base = exchangeInfo[0].trim().split(' ') - let quote = exchangeInfo[1].trim().split(' ') - let market = [base[1].toUpperCase(), quote[1].toUpperCase()].join('-') - exchange_rates[market] = quote[0]/DENOM_UNIT_MULTIPLIER - debug (exchangeInfo, exchange_rates) + const exchangeInfo = item.split(separator); + const base = exchangeInfo[0].trim().split(' '); + const quote = exchangeInfo[1].trim().split(' '); + const market = [base[1].toUpperCase(), quote[1].toUpperCase()].join('-'); + exchange_rates[market] = quote[0] / DENOM_UNIT_MULTIPLIER; + debug(exchangeInfo, exchange_rates); } - }) + }); - price = exchange_rates[tradingPair] + price = exchange_rates[tradingPair]; const result = Object.assign(paramData, { - price: price, - timestamp: initTime, - latency: hbUtils.latency(initTime, Date.now()), - } - ) - res.status(200).json(result) + price, + timestamp: initTime, + latency: hbUtils.latency(initTime, Date.now()), + }); + res.status(200).json(result); } - }) - -}) + }); +}); router.get('/balance', (req, res) => { /* api request format: /balance?address=0x87A4...b120 */ - const keyFormat = ['address'] - const paramData = hbUtils.getParamData(req.query, keyFormat) - const address = paramData.address - debug(paramData) + const keyFormat = ['address']; + const paramData = hbUtils.getParamData(req.query, keyFormat); + const address = paramData.address; + debug(paramData); - const balance = spawn(celocli, ["account:balance", address]); + const balance = spawn(celocli, ['account:balance', address]); - let err_message = [], out_message = [] - let walletBalances = {} + const err_message = []; const + out_message = []; + const walletBalances = {}; - balance.stdout.on( 'data', out => { - out_message.push(out.toString().trim()) - debug(out_message) - }) + balance.stdout.on('data', (out) => { + out_message.push(out.toString().trim()); + debug(out_message); + }); - balance.stderr.on( 'data', err => { - err_message.push(err.toString().trim()) - debug(err_message) - }) + balance.stderr.on('data', (err) => { + err_message.push(err.toString().trim()); + debug(err_message); + }); - balance.on( 'close', code => { + balance.on('close', (code) => { if (code === 0) { - out_message.forEach((item, index) => { + out_message.forEach((item, _index) => { // key indicator in balance result: "celo", "gold", "lockedcelo", "lockedgold", "usd", "pending" - if (item.toLowerCase().includes( "lockedcelo") || item.toLowerCase().includes("lockedgold")) { - let balanceArray = item.split('\n') + if (item.toLowerCase().includes('lockedcelo') || item.toLowerCase().includes('lockedgold')) { + const balanceArray = item.split('\n'); balanceArray.forEach((x) => { - let keyValue = x.split(':') - walletBalances[keyValue[0].trim()] = keyValue[1].trim()/DENOM_UNIT_MULTIPLIER - } - ) - debug('walletBalances', walletBalances) + const keyValue = x.split(':'); + walletBalances[keyValue[0].trim()] = keyValue[1].trim() / DENOM_UNIT_MULTIPLIER; + }); + debug('walletBalances', walletBalances); } - }) + }); res.status(200).json({ - address: address, + address, balance: walletBalances, - timestamp: Date.now() - }) + timestamp: Date.now(), + }); } else { res.status(401).json({ error: err_message, - }) + }); } - }) -}) - + }); +}); router.post('/unlock', (req, res) => { /* @@ -180,52 +176,53 @@ router.post('/unlock', (req, res) => { "secret": "mysupersecret" } */ - const keyFormat = ['address', 'secret'] - const paramData = hbUtils.getParamData(req.body, keyFormat) - const address = paramData.address - const secret = paramData.secret + const keyFormat = ['address', 'secret']; + const paramData = hbUtils.getParamData(req.body, keyFormat); + const address = paramData.address; + const secret = paramData.secret; - debug(paramData) - debug(req.body) + debug(paramData); + debug(req.body); - const lockStatus = spawn(celocli, ["account:unlock", address, "--password", secret]); + const lockStatus = spawn(celocli, ['account:unlock', address, '--password', secret]); - let err_message = [], out_message = [] + const err_message = []; const + out_message = []; - lockStatus.stdout.on( 'data', out => { - out_message.push(out.toString().trim()) - debug(out_message) - }) + lockStatus.stdout.on('data', (out) => { + out_message.push(out.toString().trim()); + debug(out_message); + }); - lockStatus.stderr.on( 'data', err => { - err_message.push(err.toString().trim()) - debug(err_message) - }) + lockStatus.stderr.on('data', (err) => { + err_message.push(err.toString().trim()); + debug(err_message); + }); - lockStatus.on( 'close', code => { - let unlocked = false + lockStatus.on('close', (code) => { + let unlocked = false; if (code === 0) { if (out_message.length > 0) { - out_message.forEach((item, index) => { + out_message.forEach((item, _index) => { if (item.includes(separator)) { - debug('item', item) + debug('item', item); } - }) + }); } else { - unlocked = true + unlocked = true; } res.status(200).json({ - unlocked: unlocked, + unlocked, message: out_message.join(), - timestamp: Date.now() - }) + timestamp: Date.now(), + }); } else { res.status(401).json({ error: err_message.join(), - }) + }); } - }) -}) + }); +}); router.post('/trade', (req, res) => { /* @@ -238,15 +235,14 @@ router.post('/trade', (req, res) => { "price": 3.512 } */ - const keyFormat = ['trading_pair', 'trade_type', 'amount', 'price'] - const paramData = hbUtils.getParamData(req.body, keyFormat) - debug(paramData) + const keyFormat = ['trading_pair', 'trade_type', 'amount', 'price']; + const paramData = hbUtils.getParamData(req.body, keyFormat); + debug(paramData); // const result = Object.assign(paramData, { // message: 'WIP', // timestamp: Date.now() // }) - res.status(200).json({"status": "WIP"}) -}) - + res.status(200).json({ status: 'WIP' }); +}); -module.exports = router +module.exports = router; diff --git a/src/routes/eth.route.js b/src/routes/eth.route.js index 53dfe79..daf02ab 100644 --- a/src/routes/eth.route.js +++ b/src/routes/eth.route.js @@ -6,14 +6,15 @@ import Ethereum from '../services/eth'; import Fees from '../services/fees'; import { logger } from '../services/logger'; -const debug = require('debug')('router') -const router = express.Router() -const eth = new Ethereum(process.env.ETHEREUM_CHAIN) +const debug = require('debug')('router'); + +const router = express.Router(); +const eth = new Ethereum(process.env.ETHEREUM_CHAIN); const spenders = { balancer: process.env.EXCHANGE_PROXY, - uniswap: process.env.UNISWAP_ROUTER -} -const fees = new Fees() + uniswap: process.env.UNISWAP_ROUTER, +}; +const fees = new Fees(); router.post('/', async (req, res) => { /* @@ -24,8 +25,8 @@ router.post('/', async (req, res) => { rpcUrl: eth.provider.connection.url, connection: true, timestamp: Date.now(), - }) -}) + }); +}); router.post('/balances', async (req, res) => { /* @@ -35,65 +36,65 @@ router.post('/balances', async (req, res) => { tokenList:{{tokenList}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + let wallet; try { - wallet = new ethers.Wallet(privateKey, eth.provider) + wallet = new ethers.Wallet(privateKey, eth.provider); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = 'Error getting wallet' + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = 'Error getting wallet'; res.status(500).json({ error: reason, - message: err - }) - return + message: err, + }); + return; } // populate token contract info using token symbol list - const tokenContractList = [] - const tokenList = JSON.parse(paramData.tokenList) - tokenList.forEach(symbol => { - const tokenContractInfo = eth.getERC20TokenAddresses(symbol) - tokenContractList[symbol] = tokenContractInfo + const tokenContractList = []; + const tokenList = JSON.parse(paramData.tokenList); + tokenList.forEach((symbol) => { + const tokenContractInfo = eth.getERC20TokenAddresses(symbol); + tokenContractList[symbol] = tokenContractInfo; }); - const balances = {} - balances.ETH = await eth.getETHBalance(wallet, privateKey) + const balances = {}; + balances.ETH = await eth.getETHBalance(wallet, privateKey); try { Promise.all( - Object.keys(tokenContractList).map(async (symbol, index) => { - if (tokenContractList[symbol] !== undefined) { - const address = tokenContractList[symbol].address - const decimals = tokenContractList[symbol].decimals - balances[symbol] = await eth.getERC20Balance(wallet, address, decimals) - } else { - const err = `Token contract info for ${symbol} not found` - logger.error('Token info not found', { message: err }) - debug(err) - } + Object.keys(tokenContractList).map(async (symbol, _index) => { + if (tokenContractList[symbol] !== undefined) { + const address = tokenContractList[symbol].address; + const decimals = tokenContractList[symbol].decimals; + balances[symbol] = await eth.getERC20Balance(wallet, address, decimals); + } else { + const err = `Token contract info for ${symbol} not found`; + logger.error('Token info not found', { message: err }); + debug(err); } - )).then(() => { - console.log('eth.route - Get Account Balance', { message: JSON.stringify(tokenList) }) - res.status(200).json({ + }), + ).then(() => { + console.log('eth.route - Get Account Balance', { message: JSON.stringify(tokenList) }); + res.status(200).json({ network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), - balances: balances - }) - }) + balances, + }); + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); router.post('/allowances', async (req, res) => { /* @@ -104,61 +105,60 @@ router.post('/allowances', async (req, res) => { connector:{{connector_name}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - const spender = spenders[paramData.connector] - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + const spender = spenders[paramData.connector]; + let wallet; try { - wallet = new ethers.Wallet(privateKey, eth.provider) + wallet = new ethers.Wallet(privateKey, eth.provider); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = 'Error getting wallet' + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = 'Error getting wallet'; res.status(500).json({ error: reason, - message: err - }) - return + message: err, + }); + return; } // populate token contract info using token symbol list - const tokenContractList = [] - const tokenList = JSON.parse(paramData.tokenList) - tokenList.forEach(symbol => { - const tokenContractInfo = eth.getERC20TokenAddresses(symbol) - tokenContractList[symbol] = tokenContractInfo + const tokenContractList = []; + const tokenList = JSON.parse(paramData.tokenList); + tokenList.forEach((symbol) => { + const tokenContractInfo = eth.getERC20TokenAddresses(symbol); + tokenContractList[symbol] = tokenContractInfo; }); - const approvals = {} + const approvals = {}; try { Promise.all( - Object.keys(tokenContractList).map(async (symbol, index) => { - const address = tokenContractList[symbol].address - const decimals = tokenContractList[symbol].decimals - approvals[symbol] = await eth.getERC20Allowance(wallet, spender, address, decimals) - } - )).then(() => { - logger.info('eth.route - Getting allowances', { message: JSON.stringify(tokenList) }) + Object.keys(tokenContractList).map(async (symbol, _index) => { + const address = tokenContractList[symbol].address; + const decimals = tokenContractList[symbol].decimals; + approvals[symbol] = await eth.getERC20Allowance(wallet, spender, address, decimals); + }), + ).then(() => { + logger.info('eth.route - Getting allowances', { message: JSON.stringify(tokenList) }); res.status(200).json({ network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), - spender: spender, - approvals: approvals, - }) - } - ) + spender, + approvals, + }); + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); router.post('/balances-2', async (req, res) => { /* @@ -169,53 +169,52 @@ router.post('/balances-2', async (req, res) => { tokenDecimalList:{{tokenDecimalList}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + let wallet; try { - wallet = new ethers.Wallet(privateKey, eth.provider) + wallet = new ethers.Wallet(privateKey, eth.provider); } catch (err) { - let reason - err.reason ? reason = err.reason : reason = 'Error getting wallet' + let reason; + err.reason ? reason = err.reason : reason = 'Error getting wallet'; res.status(500).json({ error: reason, - message: err - }) - return + message: err, + }); + return; } - let tokenAddressList + let tokenAddressList; if (paramData.tokenAddressList) { - tokenAddressList = paramData.tokenAddressList.split(',') + tokenAddressList = paramData.tokenAddressList.split(','); } - let tokenDecimalList + let tokenDecimalList; if (paramData.tokenDecimalList) { - tokenDecimalList = paramData.tokenDecimalList.split(',') + tokenDecimalList = paramData.tokenDecimalList.split(','); } - const balances = {} - balances.ETH = await eth.getETHBalance(wallet, privateKey) + const balances = {}; + balances.ETH = await eth.getETHBalance(wallet, privateKey); try { Promise.all( - tokenAddressList.map(async (value, index) => - balances[value] = await eth.getERC20Balance(wallet, value, tokenDecimalList[index]) - )).then(() => { + tokenAddressList.map(async (value, index) => balances[value] = await eth.getERC20Balance(wallet, value, tokenDecimalList[index])), + ).then(() => { res.status(200).json({ network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), - balances: balances - }) - }) + balances, + }); + }); } catch (err) { - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); router.post('/allowances-2', async (req, res) => { /* @@ -227,55 +226,53 @@ router.post('/allowances-2', async (req, res) => { connector:{{connector_name}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - const spender = spenders[paramData.connector] - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + const spender = spenders[paramData.connector]; + let wallet; try { - wallet = new ethers.Wallet(privateKey, eth.provider) + wallet = new ethers.Wallet(privateKey, eth.provider); } catch (err) { - let reason - err.reason ? reason = err.reason : reason = 'Error getting wallet' + let reason; + err.reason ? reason = err.reason : reason = 'Error getting wallet'; res.status(500).json({ error: reason, - message: err - }) - return + message: err, + }); + return; } - let tokenAddressList + let tokenAddressList; if (paramData.tokenAddressList) { - tokenAddressList = paramData.tokenAddressList.split(',') + tokenAddressList = paramData.tokenAddressList.split(','); } - let tokenDecimalList + let tokenDecimalList; if (paramData.tokenDecimalList) { - tokenDecimalList = paramData.tokenDecimalList.split(',') + tokenDecimalList = paramData.tokenDecimalList.split(','); } - const approvals = {} + const approvals = {}; try { Promise.all( - tokenAddressList.map(async (value, index) => - approvals[value] = await eth.getERC20Allowance(wallet, spender, value, tokenDecimalList[index]) - )).then(() => { + tokenAddressList.map(async (value, index) => approvals[value] = await eth.getERC20Allowance(wallet, spender, value, tokenDecimalList[index])), + ).then(() => { res.status(200).json({ network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), - spender: spender, - approvals: approvals, - }) - } - ) + spender, + approvals, + }); + }); } catch (err) { - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); router.post('/approve', async (req, res) => { /* @@ -288,87 +285,87 @@ router.post('/approve', async (req, res) => { amount:{{amount}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - const spender = spenders[paramData.connector] - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + const spender = spenders[paramData.connector]; + let wallet; try { - wallet = new ethers.Wallet(privateKey, eth.provider) + wallet = new ethers.Wallet(privateKey, eth.provider); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = 'Error getting wallet' + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = 'Error getting wallet'; res.status(500).json({ error: reason, - message: err - }) - return + message: err, + }); + return; } - const token = paramData.token - const tokenContractInfo = eth.getERC20TokenAddresses(token) - const tokenAddress = tokenContractInfo.address - const decimals = tokenContractInfo.decimals + const token = paramData.token; + const tokenContractInfo = eth.getERC20TokenAddresses(token); + const tokenAddress = tokenContractInfo.address; + const decimals = tokenContractInfo.decimals; - let amount - paramData.amount ? amount = ethers.utils.parseUnits(paramData.amount, decimals) - : amount = ethers.utils.parseUnits('1000000000', decimals) // approve for 1 billion units if no amount specified - let gasPrice + let amount; + paramData.amount ? amount = ethers.utils.parseUnits(paramData.amount, decimals) + : amount = ethers.utils.parseUnits('1000000000', decimals); // approve for 1 billion units if no amount specified + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } try { // call approve function - const approval = await eth.approveERC20(wallet, spender, tokenAddress, amount, gasPrice) + const approval = await eth.approveERC20(wallet, spender, tokenAddress, amount, gasPrice); // console.log('eth.route - Approving allowance', { message: approval }) // submit response res.status(200).json({ network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), - tokenAddress: tokenAddress, - spender: spender, + tokenAddress, + spender, amount: amount / 1e18.toString(), - approval: approval - }) + approval, + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); router.post('/poll', async (req, res) => { - const initTime = Date.now() - const paramData = getParamData(req.body) - const txHash = paramData.txHash - const txReceipt = await eth.provider.getTransactionReceipt(txHash) - const receipt = {} - const confirmed = txReceipt && txReceipt.blockNumber ? true : false + const initTime = Date.now(); + const paramData = getParamData(req.body); + const txHash = paramData.txHash; + const txReceipt = await eth.provider.getTransactionReceipt(txHash); + const receipt = {}; + const confirmed = !!(txReceipt && txReceipt.blockNumber); if (confirmed) { - receipt.gasUsed = BigNumber.from(txReceipt.gasUsed).toNumber() - receipt.blockNumber = txReceipt.blockNumber - receipt.confirmations = txReceipt.confirmations - receipt.status = txReceipt.status + receipt.gasUsed = BigNumber.from(txReceipt.gasUsed).toNumber(); + receipt.blockNumber = txReceipt.blockNumber; + receipt.confirmations = txReceipt.confirmations; + receipt.status = txReceipt.status; } - logger.info(`eth.route - Get TX Receipt: ${txHash}`, { message: JSON.stringify(receipt) }) + logger.info(`eth.route - Get TX Receipt: ${txHash}`, { message: JSON.stringify(receipt) }); res.status(200).json({ network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), - txHash: txHash, - confirmed: confirmed, - receipt: receipt, - }) - return txReceipt -}) + txHash, + confirmed, + receipt, + }); + return txReceipt; +}); // Kovan faucet to get test tokens (wip) & weth conversion // router.post('/get-weth', async (req, res) => { diff --git a/src/routes/index.route.js b/src/routes/index.route.js index 1ea698f..fbe93c6 100644 --- a/src/routes/index.route.js +++ b/src/routes/index.route.js @@ -11,6 +11,6 @@ router.get('/', (req, res) => { config: loadConfig(), status: 'ok', }); -}) +}); module.exports = router; diff --git a/src/routes/perpetual_finance.route.js b/src/routes/perpetual_finance.route.js index f16b30e..46eb82a 100644 --- a/src/routes/perpetual_finance.route.js +++ b/src/routes/perpetual_finance.route.js @@ -1,23 +1,15 @@ -import { ethers, BigNumber } from 'ethers'; +import { ethers } from 'ethers'; import express from 'express'; import { getParamData, latency, statusMessages } from '../services/utils'; import { logger } from '../services/logger'; import PerpetualFinance from '../services/perpetual_finance'; -require('dotenv').config() +require('dotenv').config(); -const router = express.Router() -const perpFi = new PerpetualFinance(process.env.ETHEREUM_CHAIN) -setTimeout(perpFi.update_price_loop.bind(perpFi), 2000) - -const getErrorMessage = (err) => { - /* - [WIP] Custom error message based-on string match - */ - let message = err - return message -} +const router = express.Router(); +const perpFi = new PerpetualFinance(process.env.ETHEREUM_CHAIN); +setTimeout(perpFi.update_price_loop.bind(perpFi), 2000); router.get('/', async (req, res) => { /* @@ -29,22 +21,22 @@ router.get('/', async (req, res) => { loadedMetadata: perpFi.loadedMetadata, connection: true, timestamp: Date.now(), - }) -}) + }); +}); router.get('/load-metadata', async (req, res) => { /* GET / */ - const loadedMetadata = await perpFi.load_metadata() + const loadedMetadata = await perpFi.load_metadata(); res.status(200).json({ network: perpFi.network, provider: perpFi.provider.connection.url, - loadedMetadata: loadedMetadata, + loadedMetadata, connection: true, timestamp: Date.now(), - }) -}) + }); +}); router.post('/balances', async (req, res) => { /* @@ -53,41 +45,41 @@ router.post('/balances', async (req, res) => { privateKey:{{privateKey}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + let wallet; try { - wallet = new ethers.Wallet(privateKey, perpFi.provider) + wallet = new ethers.Wallet(privateKey, perpFi.provider); } catch (err) { - let reason - err.reason ? reason = err.reason : reason = 'Error getting wallet' + let reason; + err.reason ? reason = err.reason : reason = 'Error getting wallet'; res.status(500).json({ error: reason, - message: err - }) - return + message: err, + }); + return; } - const balances = {} - balances["XDAI"] = await perpFi.getXdaiBalance(wallet) - balances["USDC"] = await perpFi.getUSDCBalance(wallet) + const balances = {}; + balances.XDAI = await perpFi.getXdaiBalance(wallet); + balances.USDC = await perpFi.getUSDCBalance(wallet); try { res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - balances: balances - }) + balances, + }); } catch (err) { - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); router.post('/allowances', async (req, res) => { /* @@ -96,40 +88,40 @@ router.post('/allowances', async (req, res) => { privateKey:{{privateKey}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + let wallet; try { - wallet = new ethers.Wallet(privateKey, perpFi.provider) + wallet = new ethers.Wallet(privateKey, perpFi.provider); } catch (err) { - let reason - err.reason ? reason = err.reason : reason = 'Error getting wallet' + let reason; + err.reason ? reason = err.reason : reason = 'Error getting wallet'; res.status(500).json({ error: reason, - message: err - }) - return + message: err, + }); + return; } - const approvals = {} - approvals["USDC"] = await perpFi.getAllowance(wallet) + const approvals = {}; + approvals.USDC = await perpFi.getAllowance(wallet); try { - res.status(200).json({ - network: perpFi.network, - timestamp: initTime, - latency: latency(initTime, Date.now()), - approvals: approvals - }) + res.status(200).json({ + network: perpFi.network, + timestamp: initTime, + latency: latency(initTime, Date.now()), + approvals, + }); } catch (err) { - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); router.post('/approve', async (req, res) => { /* @@ -139,48 +131,48 @@ router.post('/approve', async (req, res) => { amount:{{amount}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - let amount - paramData.amount ? amount = paramData.amount - : amount = '1000000000' - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + let amount; + paramData.amount ? amount = paramData.amount + : amount = '1000000000'; + let wallet; try { - wallet = new ethers.Wallet(privateKey, perpFi.provider) + wallet = new ethers.Wallet(privateKey, perpFi.provider); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = 'Error getting wallet' + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = 'Error getting wallet'; res.status(500).json({ error: reason, - message: err - }) - return + message: err, + }); + return; } try { // call approve function - const approval = await perpFi.approve(wallet, amount) - logger.info('perpFi.route - Approving allowance') + const approval = await perpFi.approve(wallet, amount); + logger.info('perpFi.route - Approving allowance'); // submit response res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - amount: amount, - approval: approval - }) + amount, + approval, + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); router.post('/open', async (req, res) => { /* @@ -194,54 +186,54 @@ router.post('/open', async (req, res) => { privateKey:{{privateKey}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const side = paramData.side - const pair = paramData.pair - const margin = paramData.margin - const leverage = paramData.leverage - const minBaseAssetAmount = paramData.minBaseAssetAmount - console.log(minBaseAssetAmount) - const privateKey = paramData.privateKey - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const side = paramData.side; + const pair = paramData.pair; + const margin = paramData.margin; + const leverage = paramData.leverage; + const minBaseAssetAmount = paramData.minBaseAssetAmount; + console.log(minBaseAssetAmount); + const privateKey = paramData.privateKey; + let wallet; try { - wallet = new ethers.Wallet(privateKey, perpFi.provider) + wallet = new ethers.Wallet(privateKey, perpFi.provider); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = 'Error getting wallet' + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = 'Error getting wallet'; res.status(500).json({ error: reason, - message: err - }) - return + message: err, + }); + return; } try { // call openPosition function - const tx = await perpFi.openPosition(side, margin, leverage, pair, minBaseAssetAmount, wallet) - logger.info('perpFi.route - Opening position') + const tx = await perpFi.openPosition(side, margin, leverage, pair, minBaseAssetAmount, wallet); + logger.info('perpFi.route - Opening position'); // submit response res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - margin: margin, - side: side, - leverage: leverage, - minBaseAssetAmount: minBaseAssetAmount, - txHash: tx.hash - }) + margin, + side, + leverage, + minBaseAssetAmount, + txHash: tx.hash, + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); router.post('/close', async (req, res) => { /* @@ -252,48 +244,47 @@ router.post('/close', async (req, res) => { pair:{{pair}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const minimalQuoteAsset = paramData.minimalQuoteAsset - const privateKey = paramData.privateKey - const pair = paramData.pair - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const minimalQuoteAsset = paramData.minimalQuoteAsset; + const privateKey = paramData.privateKey; + const pair = paramData.pair; + let wallet; try { - wallet = new ethers.Wallet(privateKey, perpFi.provider) + wallet = new ethers.Wallet(privateKey, perpFi.provider); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = 'Error getting wallet' + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = 'Error getting wallet'; res.status(500).json({ error: reason, - message: err - }) - return + message: err, + }); + return; } try { // call closePosition function - const tx = await perpFi.closePosition(wallet, pair, minimalQuoteAsset) - logger.info('perpFi.route - Closing position') + const tx = await perpFi.closePosition(wallet, pair, minimalQuoteAsset); + logger.info('perpFi.route - Closing position'); // submit response res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - minimalQuoteAsset: minimalQuoteAsset, - txHash: tx.hash - }) + minimalQuoteAsset, + txHash: tx.hash, + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) - +}); router.post('/position', async (req, res) => { /* @@ -303,45 +294,45 @@ router.post('/position', async (req, res) => { pair:{{pair}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - const pair = paramData.pair - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + const pair = paramData.pair; + let wallet; try { - wallet = new ethers.Wallet(privateKey, perpFi.provider) + wallet = new ethers.Wallet(privateKey, perpFi.provider); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = 'Error getting wallet' + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = 'Error getting wallet'; res.status(500).json({ error: reason, - message: err - }) - return + message: err, + }); + return; } try { // call getPosition function - const position = await perpFi.getPosition(wallet, pair) - logger.info('perpFi.route - getting active position') + const position = await perpFi.getPosition(wallet, pair); + logger.info('perpFi.route - getting active position'); // submit response res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - position: position - }) + position, + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); router.post('/margin', async (req, res) => { /* @@ -350,44 +341,44 @@ router.post('/margin', async (req, res) => { privateKey:{{privateKey}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + let wallet; try { - wallet = new ethers.Wallet(privateKey, perpFi.provider) + wallet = new ethers.Wallet(privateKey, perpFi.provider); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = 'Error getting wallet' + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = 'Error getting wallet'; res.status(500).json({ error: reason, - message: err - }) - return + message: err, + }); + return; } try { // call getAllBalances function - const allBalances = await perpFi.getActiveMargin(wallet) - logger.info('perpFi.route - Getting all balances') + const allBalances = await perpFi.getActiveMargin(wallet); + logger.info('perpFi.route - Getting all balances'); // submit response res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - margin: allBalances - }) + margin: allBalances, + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); router.post('/receipt', async (req, res) => { /* @@ -396,29 +387,29 @@ router.post('/receipt', async (req, res) => { txHash:{{txHash}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const txHash = paramData.txHash - const txReceipt = await perpFi.provider.getTransactionReceipt(txHash) - const receipt = {} - const confirmed = txReceipt && txReceipt.blockNumber ? true : false + const initTime = Date.now(); + const paramData = getParamData(req.body); + const txHash = paramData.txHash; + const txReceipt = await perpFi.provider.getTransactionReceipt(txHash); + const receipt = {}; + const confirmed = !!(txReceipt && txReceipt.blockNumber); if (txReceipt !== null) { - receipt.gasUsed = ethers.utils.formatEther(txReceipt.gasUsed) - receipt.blockNumber = txReceipt.blockNumber - receipt.confirmations = txReceipt.confirmations - receipt.status = txReceipt.status + receipt.gasUsed = ethers.utils.formatEther(txReceipt.gasUsed); + receipt.blockNumber = txReceipt.blockNumber; + receipt.confirmations = txReceipt.confirmations; + receipt.status = txReceipt.status; } - logger.info(`eth.route - Get TX Receipt: ${txHash}`, { message: JSON.stringify(receipt) }) + logger.info(`eth.route - Get TX Receipt: ${txHash}`, { message: JSON.stringify(receipt) }); res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - txHash: txHash, - confirmed: confirmed, - receipt: receipt, - }) - return txReceipt -}) + txHash, + confirmed, + receipt, + }); + return txReceipt; +}); router.post('/price', async (req, res) => { /* @@ -429,59 +420,58 @@ router.post('/price', async (req, res) => { amount:{{amount}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const side = paramData.side - const pair = paramData.pair - const amount = paramData.amount + const initTime = Date.now(); + const paramData = getParamData(req.body); + const side = paramData.side; + const pair = paramData.pair; + const amount = paramData.amount; try { // call getPrice function - const price = await perpFi.getPrice(side, amount, pair) - logger.info('perpFi.route - Getting price') + const price = await perpFi.getPrice(side, amount, pair); + logger.info('perpFi.route - Getting price'); // submit response res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - side: side, - price: price - }) + side, + price, + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) - +}); router.get('/pairs', async (req, res) => { /* GET */ - const initTime = Date.now() + const initTime = Date.now(); try { res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - pairs: Object.keys(perpFi.amm) - }) + pairs: Object.keys(perpFi.amm), + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); router.post('/funding', async (req, res) => { /* @@ -490,30 +480,30 @@ router.post('/funding', async (req, res) => { pair:{{pair}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const pair = paramData.pair + const initTime = Date.now(); + const paramData = getParamData(req.body); + const pair = paramData.pair; try { // call getFundingRate function - const fr = await perpFi.getFundingRate(pair) - logger.info('perpFi.route - Getting funding info') + const fr = await perpFi.getFundingRate(pair); + logger.info('perpFi.route - Getting funding info'); // submit response res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - fr: fr - }) + fr, + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); export default router; diff --git a/src/routes/terra.route.js b/src/routes/terra.route.js index f2c64c3..506935f 100644 --- a/src/routes/terra.route.js +++ b/src/routes/terra.route.js @@ -1,80 +1,79 @@ -'use strict' - -import express from 'express' -import { getParamData, latency, reportConnectionError, statusMessages } from '../services/utils'; +import express from 'express'; +import { + getParamData, latency, reportConnectionError, statusMessages, +} from '../services/utils'; import { logger } from '../services/logger'; import Terra from '../services/terra'; -const debug = require('debug')('router') const router = express.Router(); -const terra = new Terra() +const terra = new Terra(); // constants -const network = terra.lcd.config.chainID -const denomUnitMultiplier = terra.denomUnitMultiplier +const network = terra.lcd.config.chainID; +const denomUnitMultiplier = terra.denomUnitMultiplier; router.post('/', async (req, res) => { /* POST / */ res.status(200).json({ - network: network, + network, lcdUrl: terra.lcd.config.URL, gasPrices: terra.lcd.config.gasPrices, gasAdjustment: terra.lcd.config.gasAdjustment, connection: true, - timestamp: Date.now() - }) -}) + timestamp: Date.now(), + }); +}); router.post('/balances', async (req, res) => { /* POST: address:{{address}} */ - const initTime = Date.now() + const initTime = Date.now(); - const paramData = getParamData(req.body) - const address = paramData.address + const paramData = getParamData(req.body); + const address = paramData.address; - let balances = {} + const balances = {}; try { - await terra.lcd.bank.balance(address).then(bal => { + await terra.lcd.bank.balance(address).then((bal) => { bal.toArray().forEach(async (x) => { - const item = x.toData() - const denom = item.denom - const amount = item.amount / denomUnitMultiplier - const symbol = terra.tokens[denom].symbol - balances[symbol] = amount - }) - }) - logger.info('terra.route - Get Account Balance') + const item = x.toData(); + const denom = item.denom; + const amount = item.amount / denomUnitMultiplier; + const symbol = terra.tokens[denom].symbol; + balances[symbol] = amount; + }); + }); + logger.info('terra.route - Get Account Balance'); res.status(200).json({ - network: network, + network, timestamp: initTime, latency: latency(initTime, Date.now()), - balances: balances, - }) + balances, + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let message - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error - const isAxiosError = err.isAxiosError + logger.error(req.originalUrl, { message: err }); + let message; + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; + const isAxiosError = err.isAxiosError; if (isAxiosError) { - reason = err.response.status - message = err.response.statusText + reason = err.response.status; + message = err.response.statusText; } else { - message = err + message = err; } res.status(500).json({ error: reason, - message: message - }) + message, + }); } -}) +}); router.post('/start', async (req, res) => { /* @@ -85,21 +84,21 @@ router.post('/start', async (req, res) => { "amount":1 } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const baseTokenSymbol = paramData.base - const quoteTokenSymbol = paramData.quote + const initTime = Date.now(); + const paramData = getParamData(req.body); + const baseTokenSymbol = paramData.base; + const quoteTokenSymbol = paramData.quote; const result = { - network: network, + network, timestamp: initTime, latency: latency(initTime, Date.now()), success: true, base: baseTokenSymbol, quote: quoteTokenSymbol, - } - res.status(200).json(result) -}) + }; + res.status(200).json(result); +}); router.post('/price', async (req, res) => { /* @@ -111,55 +110,55 @@ router.post('/price', async (req, res) => { "amount":1 } */ - const initTime = Date.now() + const initTime = Date.now(); - const paramData = getParamData(req.body) - const baseToken = paramData.base - const quoteToken = paramData.quote - const tradeType = paramData.side.toUpperCase() - const amount = parseFloat(paramData.amount) + const paramData = getParamData(req.body); + const baseToken = paramData.base; + const quoteToken = paramData.quote; + const tradeType = paramData.side.toUpperCase(); + const amount = parseFloat(paramData.amount); - let exchangeRate + let exchangeRate; try { await terra.getSwapRate(baseToken, quoteToken, amount, tradeType).then((rate) => { - exchangeRate = rate + exchangeRate = rate; }).catch((err) => { - reportConnectionError(res, err) - }) + reportConnectionError(res, err); + }); res.status(200).json( { - network: network, + network, timestamp: initTime, latency: latency(initTime, Date.now()), base: baseToken, quote: quoteToken, - amount: amount, - tradeType: tradeType, + amount, + tradeType, price: exchangeRate.price.amount, cost: exchangeRate.cost.amount, txFee: exchangeRate.txFee.amount, - } - ) + }, + ); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let message - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error - const isAxiosError = err.isAxiosError + logger.error(req.originalUrl, { message: err }); + let message; + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; + const isAxiosError = err.isAxiosError; if (isAxiosError) { - reason = err.response.status - message = err.response.statusText + reason = err.response.status; + message = err.response.statusText; } else { - message = err + message = err; } res.status(500).json({ error: reason, - message: message - }) + message, + }); } -}) +}); router.post('/trade', async (req, res) => { /* @@ -172,57 +171,57 @@ router.post('/trade', async (req, res) => { "secret": "mysupersecret" } */ - const initTime = Date.now() + const initTime = Date.now(); - const paramData = getParamData(req.body) - const baseToken = paramData.base - const quoteToken = paramData.quote - const tradeType = paramData.side.toUpperCase() - const amount = parseFloat(paramData.amount) - const gasPrice = parseFloat(paramData.gas_price) || terra.lcd.config.gasPrices.uluna - const gasAdjustment = paramData.gas_adjustment || terra.lcd.config.gasAdjustment - const secret = paramData.privateKey + const paramData = getParamData(req.body); + const baseToken = paramData.base; + const quoteToken = paramData.quote; + const tradeType = paramData.side.toUpperCase(); + const amount = parseFloat(paramData.amount); + const gasPrice = parseFloat(paramData.gas_price) || terra.lcd.config.gasPrices.uluna; + const gasAdjustment = paramData.gas_adjustment || terra.lcd.config.gasAdjustment; + const secret = paramData.privateKey; - let tokenSwaps + let tokenSwaps; try { await terra.swapTokens(baseToken, quoteToken, amount, tradeType, gasPrice, gasAdjustment, secret).then((swap) => { - tokenSwaps = swap + tokenSwaps = swap; }).catch((err) => { - reportConnectionError(res, err) - }) + reportConnectionError(res, err); + }); const swapResult = { - network: network, + network, timestamp: initTime, latency: latency(initTime, Date.now()), base: baseToken, - tradeType: tradeType, + tradeType, quote: quoteToken, - amount: amount, - } + amount, + }; Object.assign(swapResult, tokenSwaps); - logger.info(`terra.route - ${tradeType}: ${baseToken}-${quoteToken} - Amount: ${amount}`) + logger.info(`terra.route - ${tradeType}: ${baseToken}-${quoteToken} - Amount: ${amount}`); res.status(200).json( - swapResult - ) + swapResult, + ); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let message - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error - const isAxiosError = err.isAxiosError + logger.error(req.originalUrl, { message: err }); + let message; + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; + const isAxiosError = err.isAxiosError; if (isAxiosError) { - reason = err.response.status - message = err.response.statusText + reason = err.response.status; + message = err.response.statusText; } else { - message = err + message = err; } res.status(500).json({ error: reason, - message: message - }) + message, + }); } -}) +}); module.exports = router; diff --git a/src/routes/uniswap.route.js b/src/routes/uniswap.route.js index 812e0ef..825bfb8 100644 --- a/src/routes/uniswap.route.js +++ b/src/routes/uniswap.route.js @@ -7,39 +7,38 @@ import Ethereum from '../services/eth'; import Uniswap from '../services/uniswap'; import Fees from '../services/fees'; -require('dotenv').config() +require('dotenv').config(); -const debug = require('debug')('router') -const router = express.Router() -const eth = new Ethereum(process.env.ETHEREUM_CHAIN) -const uniswap = new Uniswap(process.env.ETHEREUM_CHAIN) -uniswap.generate_tokens() -setTimeout(uniswap.update_pairs.bind(uniswap), 2000) -const fees = new Fees() +const debug = require('debug')('router'); -const swapMoreThanMaxPriceError = 'Price too high' -const swapLessThanMaxPriceError = 'Price too low' +const router = express.Router(); +const eth = new Ethereum(process.env.ETHEREUM_CHAIN); +const uniswap = new Uniswap(process.env.ETHEREUM_CHAIN); +uniswap.generate_tokens(); +setTimeout(uniswap.update_pairs.bind(uniswap), 2000); +const fees = new Fees(); -const estimateGasLimit = () => { - return uniswap.gasLimit -} +const swapMoreThanMaxPriceError = 'Price too high'; +const swapLessThanMaxPriceError = 'Price too low'; + +const estimateGasLimit = () => uniswap.gasLimit; const getErrorMessage = (err) => { /* [WIP] Custom error message based-on string match */ - let message = err + let message = err; if (err.includes('failed to meet quorum')) { - message = 'Failed to meet quorum in Uniswap' + message = 'Failed to meet quorum in Uniswap'; } else if (err.includes('Invariant failed: ADDRESSES')) { - message = 'Invariant failed: ADDRESSES' + message = 'Invariant failed: ADDRESSES'; } else if (err.includes('"call revert exception')) { - message = statusMessages.no_pool_available + message = statusMessages.no_pool_available; } else if (err.includes('"trade" is read-only')) { - message = statusMessages.no_pool_available + message = statusMessages.no_pool_available; } - return message -} + return message; +}; router.post('/', async (req, res) => { /* @@ -51,31 +50,31 @@ router.post('/', async (req, res) => { uniswap_router: uniswap.router, connection: true, timestamp: Date.now(), - }) -}) + }); +}); router.post('/gas-limit', async (req, res) => { /* POST: /buy-price */ - const gasLimit = estimateGasLimit() + const gasLimit = estimateGasLimit(); try { res.status(200).json({ network: uniswap.network, - gasLimit: gasLimit, + gasLimit, timestamp: Date.now(), - }) + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); router.get('/start', async (req, res) => { /* @@ -85,52 +84,51 @@ router.get('/start', async (req, res) => { "gasPrice":30 } */ - const initTime = Date.now() - const paramData = getParamData(req.query) - const pairs = JSON.parse(paramData.pairs) - let gasPrice + const initTime = Date.now(); + const paramData = getParamData(req.query); + const pairs = JSON.parse(paramData.pairs); + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } // get token contract address and cache paths - for (let pair of pairs){ - pair = pair.split("-") - const baseTokenSymbol = pair[0] - const quoteTokenSymbol = pair[1] - const baseTokenContractInfo = eth.getERC20TokenAddresses(baseTokenSymbol) - const quoteTokenContractInfo = eth.getERC20TokenAddresses(quoteTokenSymbol) + for (let pair of pairs) { + pair = pair.split('-'); + const baseTokenSymbol = pair[0]; + const quoteTokenSymbol = pair[1]; + const baseTokenContractInfo = eth.getERC20TokenAddresses(baseTokenSymbol); + const quoteTokenContractInfo = eth.getERC20TokenAddresses(quoteTokenSymbol); // check for valid token symbols if (baseTokenContractInfo === undefined || quoteTokenContractInfo === undefined) { - const undefinedToken = baseTokenContractInfo === undefined ? baseTokenSymbol : quoteTokenSymbol + const undefinedToken = baseTokenContractInfo === undefined ? baseTokenSymbol : quoteTokenSymbol; res.status(500).json({ error: `Token ${undefinedToken} contract address not found`, message: `Token contract address not found for ${undefinedToken}. Check token list source`, - }) - return + }); + return; } - await Promise.allSettled([uniswap.extend_update_pairs([baseTokenContractInfo.address, quoteTokenContractInfo.address])]) + await Promise.allSettled([uniswap.extend_update_pairs([baseTokenContractInfo.address, quoteTokenContractInfo.address])]); } - const gasLimit = estimateGasLimit() - const gasCost = await fees.getGasCost(gasPrice, gasLimit) - + const gasLimit = estimateGasLimit(); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); const result = { network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), success: true, - pairs: pairs, - gasPrice: gasPrice, - gasLimit: gasLimit, - gasCost: gasCost, - } - res.status(200).json(result) -}) + pairs, + gasPrice, + gasLimit, + gasCost, + }; + res.status(200).json(result); +}); router.post('/trade', async (req, res) => { /* @@ -145,49 +143,49 @@ router.post('/trade', async (req, res) => { "side":{buy|sell} } */ - const initTime = Date.now() + const initTime = Date.now(); // params: privateKey (required), base (required), quote (required), amount (required), maxPrice (required), gasPrice (required) - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - const wallet = new ethers.Wallet(privateKey, uniswap.provider) - const amount = paramData.amount + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + const wallet = new ethers.Wallet(privateKey, uniswap.provider); + const amount = paramData.amount; - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base) - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote) - const baseTokenAddress = baseTokenContractInfo.address - const quoteTokenAddress = quoteTokenContractInfo.address - const side = paramData.side.toUpperCase() + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base); + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote); + const baseTokenAddress = baseTokenContractInfo.address; + const quoteTokenAddress = quoteTokenContractInfo.address; + const side = paramData.side.toUpperCase(); - let limitPrice + let limitPrice; if (paramData.limitPrice) { - limitPrice = parseFloat(paramData.limitPrice) + limitPrice = parseFloat(paramData.limitPrice); } - let gasPrice + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } - const gasLimit = estimateGasLimit() - const gasCost = await fees.getGasCost(gasPrice, gasLimit) + const gasLimit = estimateGasLimit(); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); try { // fetch the optimal pool mix from uniswap const { trade, expectedAmount } = side === 'BUY' ? await uniswap.priceSwapOut( - quoteTokenAddress, // tokenIn is quote asset - baseTokenAddress, // tokenOut is base asset - amount + quoteTokenAddress, // tokenIn is quote asset + baseTokenAddress, // tokenOut is base asset + amount, ) : await uniswap.priceSwapIn( - baseTokenAddress, // tokenIn is base asset - quoteTokenAddress, // tokenOut is quote asset - amount - ) + baseTokenAddress, // tokenIn is base asset + quoteTokenAddress, // tokenOut is quote asset + amount, + ); if (side === 'BUY') { - const price = trade.executionPrice.invert().toSignificant(8) - logger.info(`uniswap.route - Price: ${price.toString()}`) + const price = trade.executionPrice.invert().toSignificant(8); + logger.info(`uniswap.route - Price: ${price.toString()}`); if (!limitPrice || price <= limitPrice) { // pass swaps to exchange-proxy to complete trade const tx = await uniswap.swapExactOut( @@ -195,7 +193,7 @@ router.post('/trade', async (req, res) => { trade, baseTokenAddress, gasPrice, - ) + ); // submit response res.status(200).json({ network: uniswap.network, @@ -203,25 +201,25 @@ router.post('/trade', async (req, res) => { latency: latency(initTime, Date.now()), base: baseTokenAddress, quote: quoteTokenAddress, - amount: amount, + amount, expectedIn: expectedAmount.toSignificant(8), - price: price, - gasPrice: gasPrice, - gasLimit, gasLimit, - gasCost, gasCost, + price, + gasPrice, + gasLimit, + gasCost, txHash: tx.hash, - }) + }); } else { res.status(200).json({ error: swapMoreThanMaxPriceError, - message: `Swap price ${price} exceeds limitPrice ${limitPrice}` - }) - logger.info(`uniswap.route - Swap price ${price} exceeds limitPrice ${limitPrice}`) + message: `Swap price ${price} exceeds limitPrice ${limitPrice}`, + }); + logger.info(`uniswap.route - Swap price ${price} exceeds limitPrice ${limitPrice}`); } } else { // sell - const price = trade.executionPrice.toSignificant(8) - logger.info(`Price: ${price.toString()}`) + const price = trade.executionPrice.toSignificant(8); + logger.info(`Price: ${price.toString()}`); if (!limitPrice || price >= limitPrice) { // pass swaps to exchange-proxy to complete trade const tx = await uniswap.swapExactIn( @@ -229,7 +227,7 @@ router.post('/trade', async (req, res) => { trade, baseTokenAddress, gasPrice, - ) + ); // submit response res.status(200).json({ network: uniswap.network, @@ -240,29 +238,29 @@ router.post('/trade', async (req, res) => { amount: parseFloat(paramData.amount), expectedOut: expectedAmount.toSignificant(8), price: parseFloat(price), - gasPrice: gasPrice, - gasLimit, gasLimit, - gasCost: gasCost, + gasPrice, + gasLimit, + gasCost, txHash: tx.hash, - }) + }); } else { res.status(200).json({ error: swapLessThanMaxPriceError, - message: `Swap price ${price} lower than limitPrice ${limitPrice}` - }) - logger.info(`uniswap.route - Swap price ${price} lower than limitPrice ${limitPrice}`) + message: `Swap price ${price} lower than limitPrice ${limitPrice}`, + }); + logger.info(`uniswap.route - Swap price ${price} lower than limitPrice ${limitPrice}`); } } } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? reason = err.reason : reason = statusMessages.operation_error + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? reason = err.reason : reason = statusMessages.operation_error; res.status(500).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); router.post('/price', async (req, res) => { /* @@ -273,48 +271,47 @@ router.post('/price', async (req, res) => { "amount":1 } */ - const initTime = Date.now() + const initTime = Date.now(); // params: base (required), quote (required), amount (required) - const paramData = getParamData(req.body) - const amount = paramData.amount + const paramData = getParamData(req.body); + const amount = paramData.amount; - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base) - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote) - const baseTokenAddress = baseTokenContractInfo.address - const quoteTokenAddress = quoteTokenContractInfo.address - const side = paramData.side.toUpperCase() - let gasPrice + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base); + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote); + const baseTokenAddress = baseTokenContractInfo.address; + const quoteTokenAddress = quoteTokenContractInfo.address; + const side = paramData.side.toUpperCase(); + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } - const gasLimit = estimateGasLimit() - const gasCost = await fees.getGasCost(gasPrice, gasLimit) - + const gasLimit = estimateGasLimit(); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); try { // fetch the optimal pool mix from uniswap const { trade, expectedAmount } = side === 'BUY' ? await uniswap.priceSwapOut( - quoteTokenAddress, // tokenIn is quote asset - baseTokenAddress, // tokenOut is base asset - amount + quoteTokenAddress, // tokenIn is quote asset + baseTokenAddress, // tokenOut is base asset + amount, ) : await uniswap.priceSwapIn( - baseTokenAddress, // tokenIn is base asset - quoteTokenAddress, // tokenOut is quote asset - amount - ) + baseTokenAddress, // tokenIn is base asset + quoteTokenAddress, // tokenOut is quote asset + amount, + ); if (trade !== null && expectedAmount !== null) { const price = side === 'BUY' ? trade.executionPrice.invert().toSignificant(8) - : trade.executionPrice.toSignificant(8) + : trade.executionPrice.toSignificant(8); - const tradeAmount = parseFloat(amount) - const expectedTradeAmount = parseFloat(expectedAmount.toSignificant(8)) - const tradePrice = parseFloat(price) + const tradeAmount = parseFloat(amount); + const expectedTradeAmount = parseFloat(expectedAmount.toSignificant(8)); + const tradePrice = parseFloat(price); const result = { network: uniswap.network, @@ -325,43 +322,43 @@ router.post('/price', async (req, res) => { amount: tradeAmount, expectedAmount: expectedTradeAmount, price: tradePrice, - gasPrice: gasPrice, - gasLimit: gasLimit, - gasCost: gasCost, - trade: trade, - } - debug(`Price ${side} ${baseTokenContractInfo.symbol}-${quoteTokenContractInfo.symbol} | amount:${amount} (rate:${tradePrice}) - gasPrice:${gasPrice} gasLimit:${gasLimit} estimated fee:${gasCost} ETH`) - res.status(200).json(result) + gasPrice, + gasLimit, + gasCost, + trade, + }; + debug(`Price ${side} ${baseTokenContractInfo.symbol}-${quoteTokenContractInfo.symbol} | amount:${amount} (rate:${tradePrice}) - gasPrice:${gasPrice} gasLimit:${gasLimit} estimated fee:${gasCost} ETH`); + res.status(200).json(result); } else { // no pool available res.status(200).json({ info: statusMessages.no_pool_available, - message: '' - }) + message: '', + }); } } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - let errCode = 500 + logger.error(req.originalUrl, { message: err }); + let reason; + let errCode = 500; if (Object.keys(err).includes('isInsufficientReservesError')) { - errCode = 200 - reason = statusMessages.insufficient_reserves + ' in ' + side + ' at Uniswap' + errCode = 200; + reason = `${statusMessages.insufficient_reserves} in ${side} at Uniswap`; } else if (Object.getOwnPropertyNames(err).includes('message')) { - reason = getErrorMessage(err.message) + reason = getErrorMessage(err.message); if (reason === statusMessages.no_pool_available) { - errCode = 200 + errCode = 200; res.status(errCode).json({ info: reason, - message: err - }) + message: err, + }); } } else { - err.reason ? reason = err.reason : reason = statusMessages.operation_error + err.reason ? reason = err.reason : reason = statusMessages.operation_error; } res.status(errCode).json({ error: reason, - message: err - }) + message: err, + }); } -}) +}); export default router; diff --git a/src/services/access.js b/src/services/access.js index 708f3aa..cf374b9 100644 --- a/src/services/access.js +++ b/src/services/access.js @@ -4,22 +4,21 @@ import { logger } from './logger'; import { statusMessages } from './utils'; -const debug = require('debug')('router') export const validateAccess = (req, res, next) => { - const cert = req.connection.getPeerCertificate() + const cert = req.connection.getPeerCertificate(); if (req.client.authorized) { - const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress - const method = req.method - const url = req.url - const requestInfo = 'Request from IP: ' + ip + ' ' + method + ' ' + url - console.log(requestInfo) - next() + const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; + const method = req.method; + const url = req.url; + const requestInfo = `Request from IP: ${ip} ${method} ${url}`; + console.log(requestInfo); + next(); } else if (cert.subject) { - logger.error(statusMessages.ssl_cert_invalid) - res.status(403).send({ error: statusMessages.ssl_cert_invalid }) + logger.error(statusMessages.ssl_cert_invalid); + res.status(403).send({ error: statusMessages.ssl_cert_invalid }); } else { - logger.error(statusMessages.ssl_cert_required) - res.status(401).send({ error: statusMessages.ssl_cert_required }) + logger.error(statusMessages.ssl_cert_required); + res.status(401).send({ error: statusMessages.ssl_cert_required }); } -} +}; diff --git a/src/services/balancer.js b/src/services/balancer.js index dc4bb43..a954f21 100644 --- a/src/services/balancer.js +++ b/src/services/balancer.js @@ -1,10 +1,11 @@ -import { logger } from '../services/logger'; -const debug = require('debug')('router') -require('dotenv').config() // DO NOT REMOVE. needed to configure REACT_APP_SUBGRAPH_URL used by @balancer-labs/sor -const sor = require('@balancer-labs/sor') -const BigNumber = require('bignumber.js') -const ethers = require('ethers') -const proxyArtifact = require('../static/ExchangeProxy.json') +import { logger } from './logger'; + +const debug = require('debug')('router'); +require('dotenv').config(); // DO NOT REMOVE. needed to configure REACT_APP_SUBGRAPH_URL used by @balancer-labs/sor +const sor = require('@balancer-labs/sor'); +const BigNumber = require('bignumber.js'); +const ethers = require('ethers'); +const proxyArtifact = require('../static/ExchangeProxy.json'); // constants const MULTI = '0xeefba1e63905ef1d7acba5a8513c70307c1ce441'; @@ -14,16 +15,16 @@ const GAS_BASE = process.env.BALANCER_GAS_BASE || 200688; const GAS_PER_SWAP = process.env.BALANCER_GAS_PER_SWAP || 100000; export default class Balancer { - constructor (network = 'kovan') { - const providerUrl = process.env.ETHEREUM_RPC_URL - this.network = process.env.ETHEREUM_CHAIN - this.provider = new ethers.providers.JsonRpcProvider(providerUrl) - this.subgraphUrl = process.env.REACT_APP_SUBGRAPH_URL - this.gasBase = GAS_BASE - this.gasPerSwap = GAS_PER_SWAP - this.maxSwaps = process.env.BALANCER_MAX_SWAPS || 4 + constructor(network = 'kovan') { + const providerUrl = process.env.ETHEREUM_RPC_URL; + this.network = process.env.ETHEREUM_CHAIN; + this.provider = new ethers.providers.JsonRpcProvider(providerUrl); + this.subgraphUrl = process.env.REACT_APP_SUBGRAPH_URL; + this.gasBase = GAS_BASE; + this.gasPerSwap = GAS_PER_SWAP; + this.maxSwaps = process.env.BALANCER_MAX_SWAPS || 4; this.exchangeProxy = process.env.EXCHANGE_PROXY; - this.cachedPools = [] + this.cachedPools = []; switch (network) { case 'mainnet': @@ -33,132 +34,132 @@ export default class Balancer { this.multiCall = MULTI_KOVAN; break; default: - const err = `Invalid network ${network}` - logger.error(err) - throw Error(err) + const err = `Invalid network ${network}`; + logger.error(err); + throw Error(err); } } - async fetchPool (tokenIn, tokenOut) { - const pools = await sor.getPoolsWithTokens(tokenIn, tokenOut) - this.cachedPools[tokenIn + tokenOut] = pools + async fetchPool(tokenIn, tokenOut) { + const pools = await sor.getPoolsWithTokens(tokenIn, tokenOut); + this.cachedPools[tokenIn + tokenOut] = pools; if (pools.pools.length === 0) { debug('>>> No pools contain the tokens provided.', { message: this.network }); return {}; } - debug(`>>> ${pools.pools.length} Pools Retrieved.`, { message: this.network }) + debug(`>>> ${pools.pools.length} Pools Retrieved.`, { message: this.network }); } - async getCachedPools (tokenIn, tokenOut) { - const cachePools = this.cachedPools[tokenIn + tokenOut].pools - debug(`>>> get cached Pools. ${tokenIn + tokenOut}`, { message: `total pools: ${cachePools.length}` }) - return cachePools + async getCachedPools(tokenIn, tokenOut) { + const cachePools = this.cachedPools[tokenIn + tokenOut].pools; + debug(`>>> get cached Pools. ${tokenIn + tokenOut}`, { message: `total pools: ${cachePools.length}` }); + return cachePools; } - async priceSwapIn (tokenIn, tokenOut, tokenInAmount, maxSwaps = this.maxSwaps) { + async priceSwapIn(tokenIn, tokenOut, tokenInAmount, maxSwaps = this.maxSwaps) { // Fetch all the pools that contain the tokens provided try { // Get current on-chain data about the fetched pools - await this.fetchPool(tokenIn, tokenOut) + await this.fetchPool(tokenIn, tokenOut); - let poolData - const cachedPools = await this.getCachedPools(tokenIn, tokenOut) + let poolData; + const cachedPools = await this.getCachedPools(tokenIn, tokenOut); if (this.network === 'mainnet') { - poolData = await sor.parsePoolDataOnChain(cachedPools, tokenIn, tokenOut, this.multiCall, this.provider) + poolData = await sor.parsePoolDataOnChain(cachedPools, tokenIn, tokenOut, this.multiCall, this.provider); } else { // Kovan multicall throws an ENS error - poolData = await sor.parsePoolData(cachedPools, tokenIn, tokenOut) + poolData = await sor.parsePoolData(cachedPools, tokenIn, tokenOut); } // Parse the pools and pass them to smart order outer to get the swaps needed const sorSwaps = sor.smartOrderRouter( - poolData, // balancers: Pool[] - 'swapExactIn', // swapType: string - tokenInAmount, // targetInputAmount: BigNumber - new BigNumber(maxSwaps.toString()), // maxBalancers: number - 0 // costOutputToken: BigNumber - ) - - const swapsFormatted = sor.formatSwapsExactAmountIn(sorSwaps, MAX_UINT, 0) - const expectedAmount = sor.calcTotalOutput(swapsFormatted, poolData) + poolData, // balancers: Pool[] + 'swapExactIn', // swapType: string + tokenInAmount, // targetInputAmount: BigNumber + new BigNumber(maxSwaps.toString()), // maxBalancers: number + 0, // costOutputToken: BigNumber + ); + + const swapsFormatted = sor.formatSwapsExactAmountIn(sorSwaps, MAX_UINT, 0); + const expectedAmount = sor.calcTotalOutput(swapsFormatted, poolData); debug(`Expected Out: ${expectedAmount.toString()} (${tokenOut})`); // Create correct swap format for new proxy - let swaps = []; + const swaps = []; for (let i = 0; i < swapsFormatted.length; i++) { - let swap = { + const swap = { pool: swapsFormatted[i].pool, - tokenIn: tokenIn, - tokenOut: tokenOut, + tokenIn, + tokenOut, swapAmount: swapsFormatted[i].tokenInParam, limitReturnAmount: swapsFormatted[i].tokenOutParam, maxPrice: swapsFormatted[i].maxPrice.toString(), }; swaps.push(swap); } - return { swaps, expectedAmount } + return { swaps, expectedAmount }; } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error in swapExactOut' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error in swapExactOut'; + return reason; } } - async priceSwapOut (tokenIn, tokenOut, tokenOutAmount, maxSwaps = this.maxSwaps) { + async priceSwapOut(tokenIn, tokenOut, tokenOutAmount, maxSwaps = this.maxSwaps) { // Fetch all the pools that contain the tokens provided try { // Get current on-chain data about the fetched pools - await this.fetchPool(tokenIn, tokenOut) + await this.fetchPool(tokenIn, tokenOut); - let poolData - const cachedPools = await this.getCachedPools(tokenIn, tokenOut) + let poolData; + const cachedPools = await this.getCachedPools(tokenIn, tokenOut); if (this.network === 'mainnet') { - poolData = await sor.parsePoolDataOnChain(cachedPools, tokenIn, tokenOut, this.multiCall, this.provider) + poolData = await sor.parsePoolDataOnChain(cachedPools, tokenIn, tokenOut, this.multiCall, this.provider); } else { // Kovan multicall throws an ENS error - poolData = await sor.parsePoolData(cachedPools, tokenIn, tokenOut) + poolData = await sor.parsePoolData(cachedPools, tokenIn, tokenOut); } // Parse the pools and pass them to smart order outer to get the swaps needed const sorSwaps = sor.smartOrderRouter( - poolData, // balancers: Pool[] - 'swapExactOut', // swapType: string - tokenOutAmount, // targetInputAmount: BigNumber - new BigNumber(maxSwaps.toString()), // maxBalancers: number - 0 // costOutputToken: BigNumber - ) - const swapsFormatted = sor.formatSwapsExactAmountOut(sorSwaps, MAX_UINT, MAX_UINT) - const expectedAmount = sor.calcTotalInput(swapsFormatted, poolData) + poolData, // balancers: Pool[] + 'swapExactOut', // swapType: string + tokenOutAmount, // targetInputAmount: BigNumber + new BigNumber(maxSwaps.toString()), // maxBalancers: number + 0, // costOutputToken: BigNumber + ); + const swapsFormatted = sor.formatSwapsExactAmountOut(sorSwaps, MAX_UINT, MAX_UINT); + const expectedAmount = sor.calcTotalInput(swapsFormatted, poolData); debug(`Expected In: ${expectedAmount.toString()} (${tokenIn})`); // Create correct swap format for new proxy - let swaps = []; + const swaps = []; for (let i = 0; i < swapsFormatted.length; i++) { - let swap = { + const swap = { pool: swapsFormatted[i].pool, - tokenIn: tokenIn, - tokenOut: tokenOut, + tokenIn, + tokenOut, swapAmount: swapsFormatted[i].tokenOutParam, limitReturnAmount: swapsFormatted[i].tokenInParam, maxPrice: swapsFormatted[i].maxPrice.toString(), }; swaps.push(swap); } - return { swaps, expectedAmount } + return { swaps, expectedAmount }; } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error in swapExactOut' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error in swapExactOut'; + return reason; } } - async swapExactIn (wallet, swaps, tokenIn, tokenOut, amountIn, minAmountOut, gasPrice) { - debug(`Number of swaps: ${swaps.length}`) + async swapExactIn(wallet, swaps, tokenIn, tokenOut, amountIn, minAmountOut, gasPrice) { + debug(`Number of swaps: ${swaps.length}`); try { - const contract = new ethers.Contract(this.exchangeProxy, proxyArtifact.abi, wallet) + const contract = new ethers.Contract(this.exchangeProxy, proxyArtifact.abi, wallet); const tx = await contract.batchSwapExactIn( swaps, tokenIn, @@ -168,22 +169,22 @@ export default class Balancer { { gasPrice: gasPrice * 1e9, gasLimit: GAS_BASE + swaps.length * GAS_PER_SWAP, - } - ) + }, + ); debug(`Tx Hash: ${tx.hash}`); - return tx + return tx; } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error in swapExactIn' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error in swapExactIn'; + return reason; } } - async swapExactOut (wallet, swaps, tokenIn, tokenOut, expectedIn, gasPrice) { - debug(`Number of swaps: ${swaps.length}`) + async swapExactOut(wallet, swaps, tokenIn, tokenOut, expectedIn, gasPrice) { + debug(`Number of swaps: ${swaps.length}`); try { - const contract = new ethers.Contract(this.exchangeProxy, proxyArtifact.abi, wallet) + const contract = new ethers.Contract(this.exchangeProxy, proxyArtifact.abi, wallet); const tx = await contract.batchSwapExactOut( swaps, tokenIn, @@ -192,15 +193,15 @@ export default class Balancer { { gasPrice: gasPrice * 1e9, gasLimit: GAS_BASE + swaps.length * GAS_PER_SWAP, - } - ) - debug(`Tx Hash: ${tx.hash}`) - return tx + }, + ); + debug(`Tx Hash: ${tx.hash}`); + return tx; } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error in swapExactOut' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error in swapExactOut'; + return reason; } } } diff --git a/src/services/eth.js b/src/services/eth.js index 61a51cd..a1dba27 100644 --- a/src/services/eth.js +++ b/src/services/eth.js @@ -1,166 +1,164 @@ +import axios from 'axios'; import { logger } from './logger'; -import axios from 'axios' -const debug = require('debug')('router') -require('dotenv').config() +require('dotenv').config(); const fs = require('fs'); -const ethers = require('ethers') -const abi = require('../static/abi') +const ethers = require('ethers'); +const abi = require('../static/abi'); // constants const APPROVAL_GAS_LIMIT = process.env.ETH_APPROVAL_GAS_LIMIT || 50000; export default class Ethereum { - constructor (network = 'mainnet') { + constructor(network = 'mainnet') { // network defaults to kovan - const providerUrl = process.env.ETHEREUM_RPC_URL - this.provider = new ethers.providers.JsonRpcProvider(providerUrl) - this.erc20TokenListURL = process.env.ETHEREUM_TOKEN_LIST_URL - this.network = network + const providerUrl = process.env.ETHEREUM_RPC_URL; + this.provider = new ethers.providers.JsonRpcProvider(providerUrl); + this.erc20TokenListURL = process.env.ETHEREUM_TOKEN_LIST_URL; + this.network = network; this.spenders = { balancer: process.env.EXCHANGE_PROXY, - uniswap: process.env.UNISWAP_ROUTER - } + uniswap: process.env.UNISWAP_ROUTER, + }; // update token list - this.getERC20TokenList() // erc20TokenList + this.getERC20TokenList(); // erc20TokenList } // get ETH balance - async getETHBalance (wallet) { + async getETHBalance(wallet) { try { - const balance = await wallet.getBalance() - return balance / 1e18.toString() + const balance = await wallet.getBalance(); + return balance / 1e18.toString(); } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error ETH balance lookup' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error ETH balance lookup'; + return reason; } } // get ERC-20 token balance - async getERC20Balance (wallet, tokenAddress, decimals = 18) { + async getERC20Balance(wallet, tokenAddress, decimals = 18) { // instantiate a contract and pass in provider for read-only access - const contract = new ethers.Contract(tokenAddress, abi.ERC20Abi, this.provider) + const contract = new ethers.Contract(tokenAddress, abi.ERC20Abi, this.provider); try { - const balance = await contract.balanceOf(wallet.address) - return balance / Math.pow(10, decimals).toString() + const balance = await contract.balanceOf(wallet.address); + return balance / (10 ** decimals).toString(); } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error balance lookup' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error balance lookup'; + return reason; } } // get ERC-20 token allowance - async getERC20Allowance (wallet, spender, tokenAddress, decimals = 18) { + async getERC20Allowance(wallet, spender, tokenAddress, decimals = 18) { // instantiate a contract and pass in provider for read-only access - const contract = new ethers.Contract(tokenAddress, abi.ERC20Abi, this.provider) + const contract = new ethers.Contract(tokenAddress, abi.ERC20Abi, this.provider); try { - const allowance = await contract.allowance(wallet.address, spender) - return allowance / Math.pow(10, decimals).toString() + const allowance = await contract.allowance(wallet.address, spender); + return allowance / (10 ** decimals).toString(); } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error allowance lookup' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error allowance lookup'; + return reason; } } // approve a spender to transfer tokens from a wallet address - async approveERC20 (wallet, spender, tokenAddress, amount, gasPrice = this.gasPrice, gasLimit) { + async approveERC20(wallet, spender, tokenAddress, amount, gasPrice = this.gasPrice, _gasLimit) { try { // fixate gas limit to prevent overwriting - const approvalGasLimit = APPROVAL_GAS_LIMIT + const approvalGasLimit = APPROVAL_GAS_LIMIT; // instantiate a contract and pass in wallet, which act on behalf of that signer - const contract = new ethers.Contract(tokenAddress, abi.ERC20Abi, wallet) + const contract = new ethers.Contract(tokenAddress, abi.ERC20Abi, wallet); return await contract.approve( spender, amount, { gasPrice: gasPrice * 1e9, - gasLimit: approvalGasLimit - } - ) + gasLimit: approvalGasLimit, + }, + ); } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error approval' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error approval'; + return reason; } } // get current Gas - async getCurrentGasPrice () { + async getCurrentGasPrice() { try { - this.provider.getGasPrice().then(function (gas) { + this.provider.getGasPrice().then((gas) => { // gasPrice is a BigNumber; convert it to a decimal string const gasPrice = gas.toString(); - return gasPrice - }) + return gasPrice; + }); } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error gas lookup' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error gas lookup'; + return reason; } } - async deposit (wallet, tokenAddress, amount, gasPrice = this.gasPrice, gasLimit = this.approvalGasLimit) { + async deposit(wallet, tokenAddress, amount, gasPrice = this.gasPrice, gasLimit = this.approvalGasLimit) { // deposit ETH to a contract address try { - const contract = new ethers.Contract(tokenAddress, abi.KovanWETHAbi, wallet) + const contract = new ethers.Contract(tokenAddress, abi.KovanWETHAbi, wallet); return await contract.deposit( - { value: amount, + { + value: amount, gasPrice: gasPrice * 1e9, - gasLimit: gasLimit - } - ) + gasLimit, + }, + ); } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error deposit' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error deposit'; + return reason; } } // get ERC20 Token List - async getERC20TokenList () { - let tokenListSource + async getERC20TokenList() { + let tokenListSource; try { if (this.network === 'kovan') { - tokenListSource = 'src/static/erc20_tokens_kovan.json' - this.erc20TokenList = JSON.parse(fs.readFileSync(tokenListSource)) + tokenListSource = 'src/static/erc20_tokens_kovan.json'; + this.erc20TokenList = JSON.parse(fs.readFileSync(tokenListSource)); } else if (this.network === 'mainnet') { - tokenListSource = this.erc20TokenListURL + tokenListSource = this.erc20TokenListURL; if (tokenListSource === undefined || tokenListSource === null) { - const errMessage = 'Token List source not found' - logger.error('ERC20 Token List Error', { message: errMessage}) - console.log('eth - Error: ', errMessage) + const errMessage = 'Token List source not found'; + logger.error('ERC20 Token List Error', { message: errMessage }); + console.log('eth - Error: ', errMessage); } if (this.erc20TokenList === undefined || this.erc20TokenList === null || this.erc20TokenList === {}) { - const response = await axios.get(tokenListSource) + const response = await axios.get(tokenListSource); if (response.status === 200 && response.data) { - this.erc20TokenList = response.data + this.erc20TokenList = response.data; } } } else { - throw Error(`Invalid network ${this.network}`) + throw Error(`Invalid network ${this.network}`); } - console.log('get ERC20 Token List', this.network, 'source', tokenListSource) + console.log('get ERC20 Token List', this.network, 'source', tokenListSource); } catch (err) { console.log(err); - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error ERC 20 Token List' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error ERC 20 Token List'; + return reason; } } - getERC20TokenAddresses (tokenSymbol) { - const tokenContractAddress = this.erc20TokenList.tokens.filter(obj => { - return obj.symbol === tokenSymbol.toUpperCase() - }) - return tokenContractAddress[0] + getERC20TokenAddresses(tokenSymbol) { + const tokenContractAddress = this.erc20TokenList.tokens.filter((obj) => obj.symbol === tokenSymbol.toUpperCase()); + return tokenContractAddress[0]; } } diff --git a/src/services/fees.js b/src/services/fees.js index 0535897..faa5805 100644 --- a/src/services/fees.js +++ b/src/services/fees.js @@ -1,44 +1,43 @@ +import axios from 'axios'; +import BigNumber from 'bignumber.js'; import { logger } from './logger'; -import axios from 'axios' -import BigNumber from 'bignumber.js' -require('dotenv').config() +require('dotenv').config(); -const debug = require('debug')('router') // constants -const ethGasStationHost = 'https://ethgasstation.info' -const ethGasStationEnabled = process.env.ENABLE_ETH_GAS_STATION || false -const ethGasStationApiKey = process.env.ETH_GAS_STATION_API_KEY -const ethManualGasPrice = parseInt(process.env.MANUAL_GAS_PRICE) -const ethGasStationURL = ethGasStationHost + '/api/ethgasAPI.json?api-key=' + ethGasStationApiKey -const defaultRefreshInterval = 120 -const denom = BigNumber('1e+9') +const ethGasStationHost = 'https://ethgasstation.info'; +const ethGasStationEnabled = process.env.ENABLE_ETH_GAS_STATION || false; +const ethGasStationApiKey = process.env.ETH_GAS_STATION_API_KEY; +const ethManualGasPrice = parseInt(process.env.MANUAL_GAS_PRICE); +const ethGasStationURL = `${ethGasStationHost}/api/ethgasAPI.json?api-key=${ethGasStationApiKey}`; +const defaultRefreshInterval = 120; +const denom = BigNumber('1e+9'); export default class Fees { - constructor () { - this.ethGasStationGasLevel = process.env.ETH_GAS_STATION_GAS_LEVEL - this.ethGasStationRefreshTime = (process.env.ETH_GAS_STATION_REFRESH_TIME || defaultRefreshInterval) * 1000 - this.getETHGasStationFee(this.ethGasStationGasLevel, 0) + constructor() { + this.ethGasStationGasLevel = process.env.ETH_GAS_STATION_GAS_LEVEL; + this.ethGasStationRefreshTime = (process.env.ETH_GAS_STATION_REFRESH_TIME || defaultRefreshInterval) * 1000; + this.getETHGasStationFee(this.ethGasStationGasLevel, 0); } // get ETH Gas Station - async getETHGasStationFee (gasLevel = this.ethGasStationGasLevel, interval = defaultRefreshInterval) { + async getETHGasStationFee(gasLevel = this.ethGasStationGasLevel, interval = defaultRefreshInterval) { try { if (ethGasStationEnabled === true || ethGasStationEnabled.toLowerCase() === 'true') { - const response = await axios.get(ethGasStationURL) + const response = await axios.get(ethGasStationURL); // divite by 10 to convert it to Gwei) - this.ethGasPrice = response.data[gasLevel] / 10 - console.log(`get ETHGasStation gas price (${gasLevel}): ${this.ethGasPrice} / interval: ${this.ethGasStationRefreshTime / 1000} sec`) + this.ethGasPrice = response.data[gasLevel] / 10; + console.log(`get ETHGasStation gas price (${gasLevel}): ${this.ethGasPrice} / interval: ${this.ethGasStationRefreshTime / 1000} sec`); } else { - this.ethGasPrice = ethManualGasPrice - console.log(`get manual fixed gas price: ${this.ethGasPrice} / interval: ${this.ethGasStationRefreshTime / 1000} sec`) + this.ethGasPrice = ethManualGasPrice; + console.log(`get manual fixed gas price: ${this.ethGasPrice} / interval: ${this.ethGasStationRefreshTime / 1000} sec`); } } catch (err) { console.log(err); - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error ETH gas fee lookup' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error ETH gas fee lookup'; + return reason; } if (interval > 0) { // set to '0' for one-time retrieval setTimeout(this.getETHGasStationFee.bind(this), this.ethGasStationRefreshTime); // update every x seconds @@ -46,8 +45,8 @@ export default class Fees { } // get gas cost - async getGasCost (gasPrice, gasLimit, inGwei = false) { - const cost = gasPrice * gasLimit - return inGwei ? cost : cost / denom - } + async getGasCost(gasPrice, gasLimit, inGwei = false) { + const cost = gasPrice * gasLimit; + return inGwei ? cost : cost / denom; + } } diff --git a/src/services/logger.js b/src/services/logger.js index 90bf160..d12da4c 100644 --- a/src/services/logger.js +++ b/src/services/logger.js @@ -1,27 +1,28 @@ -import { getLocalDate } from './utils' -require('dotenv').config() -const appRoot = require('app-root-path') -const winston = require('winston') +import { getLocalDate } from './utils'; + +require('dotenv').config(); +const appRoot = require('app-root-path'); +const winston = require('winston'); require('winston-daily-rotate-file'); const logFormat = winston.format.combine( winston.format.timestamp(), winston.format.align(), winston.format.printf( - info => { - const localDate = getLocalDate() - return `${localDate} | ${info.level} | ${info.message}` - } + (info) => { + const localDate = getLocalDate(); + return `${localDate} | ${info.level} | ${info.message}`; + }, ), -) +); const getLogPath = () => { - let logPath = process.env.LOG_PATH + let logPath = process.env.LOG_PATH; if (typeof logPath === 'undefined' || logPath == null || logPath === '') { - logPath = [appRoot.path, 'logs'].join('/') + logPath = [appRoot.path, 'logs'].join('/'); } - return logPath -} + return logPath; +}; const config = { file: { @@ -29,16 +30,16 @@ const config = { filename: `${getLogPath()}/logs_gateway_app.log.%DATE%`, datePattern: 'YYYY-MM-DD', handleExceptions: true, - handleRejections: true - } -} + handleRejections: true, + }, +}; -const allLogsFileTransport = new winston.transports.DailyRotateFile(config.file) +const allLogsFileTransport = new winston.transports.DailyRotateFile(config.file); const options = { format: logFormat, transports: [allLogsFileTransport], exitOnError: false, -} +}; -export const logger = winston.createLogger(options) +export const logger = winston.createLogger(options); diff --git a/src/services/perpetual_finance.js b/src/services/perpetual_finance.js index f2d482e..9113ad0 100644 --- a/src/services/perpetual_finance.js +++ b/src/services/perpetual_finance.js @@ -2,34 +2,30 @@ import { logger } from './logger'; const fetch = require('cross-fetch'); -const Ethers = require('ethers') -const AmmArtifact = require("@perp/contract/build/contracts/Amm.json") -const ClearingHouseArtifact = require("@perp/contract/build/contracts/ClearingHouse.json") -const RootBridgeArtifact = require("@perp/contract/build/contracts/RootBridge.json") -const ClientBridgeArtifact = require("@perp/contract/build/contracts/ClientBridge.json") -const ClearingHouseViewerArtifact = require("@perp/contract/build/contracts/ClearingHouseViewer.json") -const TetherTokenArtifact = require("@perp/contract/build/contracts/TetherToken.json") +const Ethers = require('ethers'); +const AmmArtifact = require('@perp/contract/build/contracts/Amm.json'); +const ClearingHouseArtifact = require('@perp/contract/build/contracts/ClearingHouse.json'); +const ClearingHouseViewerArtifact = require('@perp/contract/build/contracts/ClearingHouseViewer.json'); +const TetherTokenArtifact = require('@perp/contract/build/contracts/TetherToken.json'); const GAS_LIMIT = 2123456; const DEFAULT_DECIMALS = 18; const CONTRACT_ADDRESSES = 'https://metadata.perp.exchange/'; const XDAI_PROVIDER = process.env.XDAI_PROVIDER || 'https://dai.poa.network'; const PNL_OPTION_SPOT_PRICE = 0; -const UPDATE_PERIOD = 60000; // stop updating prices after 30 secs from last request - +const UPDATE_PERIOD = 60000; // stop updating prices after 30 secs from last request export default class PerpetualFinance { - constructor (network = 'mainnet') { - this.providerUrl = XDAI_PROVIDER - this.network = network - this.provider = new Ethers.providers.JsonRpcProvider(this.providerUrl) - this.gasLimit = GAS_LIMIT - this.contractAddressesUrl = CONTRACT_ADDRESSES - this.amm = {} - this.priceCache = {} - this.cacheExpirary = {} - this.pairAmountCache = {} - + constructor(network = 'mainnet') { + this.providerUrl = XDAI_PROVIDER; + this.network = network; + this.provider = new Ethers.providers.JsonRpcProvider(this.providerUrl); + this.gasLimit = GAS_LIMIT; + this.contractAddressesUrl = CONTRACT_ADDRESSES; + this.amm = {}; + this.priceCache = {}; + this.cacheExpirary = {}; + this.pairAmountCache = {}; switch (network) { case 'mainnet': @@ -39,260 +35,262 @@ export default class PerpetualFinance { this.contractAddressesUrl += 'staging.json'; break; default: - const err = `Invalid network ${network}` - logger.error(err) - throw Error(err) + const err = `Invalid network ${network}`; + logger.error(err); + throw Error(err); } - this.loadedMetadata = this.load_metadata() - + this.loadedMetadata = this.load_metadata(); } async load_metadata() { - try{ - const metadata = await fetch(this.contractAddressesUrl).then(res => res.json()) - const layer2 = Object.keys(metadata.layers.layer2.contracts) + try { + const metadata = await fetch(this.contractAddressesUrl).then((res) => res.json()); + const layer2 = Object.keys(metadata.layers.layer2.contracts); - for (var key of layer2){ - if (metadata.layers.layer2.contracts[key].name === "Amm") { + for (const key of layer2) { + if (metadata.layers.layer2.contracts[key].name === 'Amm') { this.amm[key] = metadata.layers.layer2.contracts[key].address; - } else{ + } else { this[key] = metadata.layers.layer2.contracts[key].address; } } - this.layer2AmbAddr = metadata.layers.layer2.externalContracts.ambBridgeOnXDai - this.xUsdcAddr = metadata.layers.layer2.externalContracts.usdc - this.loadedMetadata = true - return true - } catch(err) { - return false + this.layer2AmbAddr = metadata.layers.layer2.externalContracts.ambBridgeOnXDai; + this.xUsdcAddr = metadata.layers.layer2.externalContracts.usdc; + this.loadedMetadata = true; + return true; + } catch (err) { + return false; } - } async update_price_loop() { if (Object.keys(this.cacheExpirary).length > 0) { - for (let pair in this.cacheExpirary){ + for (const pair in this.cacheExpirary) { if (this.cacheExpirary[pair] <= Date.now()) { delete this.cacheExpirary[pair]; delete this.priceCache[pair]; } } - for (let pair in this.cacheExpirary){ - let amm = new Ethers.Contract(this.amm[pair], AmmArtifact.abi, this.provider) - await Promise.allSettled([amm.getInputPrice(0, {d: Ethers.utils.parseUnits(this.pairAmountCache[pair], DEFAULT_DECIMALS) }), - amm.getOutputPrice(0, {d: Ethers.utils.parseUnits(this.pairAmountCache[pair], DEFAULT_DECIMALS) })]) - .then(values => {if (!this.priceCache.hasOwnProperty(pair)) { this.priceCache[pair] = [] }; - this.priceCache[pair][0] = this.pairAmountCache[pair] / Ethers.utils.formatUnits(values[0].value.d); - this.priceCache[pair][1] = Ethers.utils.formatUnits(values[1].value.d) / this.pairAmountCache[pair];})} - + for (const pair in this.cacheExpirary) { + const amm = new Ethers.Contract(this.amm[pair], AmmArtifact.abi, this.provider); + await Promise.allSettled([amm.getInputPrice(0, { d: Ethers.utils.parseUnits(this.pairAmountCache[pair], DEFAULT_DECIMALS) }), + amm.getOutputPrice(0, { d: Ethers.utils.parseUnits(this.pairAmountCache[pair], DEFAULT_DECIMALS) })]) + .then((values) => { + if (!this.priceCache.hasOwnProperty(pair)) { this.priceCache[pair] = []; } + this.priceCache[pair][0] = this.pairAmountCache[pair] / Ethers.utils.formatUnits(values[0].value.d); + this.priceCache[pair][1] = Ethers.utils.formatUnits(values[1].value.d) / this.pairAmountCache[pair]; + }); } - setTimeout(this.update_price_loop.bind(this), 10000); // update every 10 seconds + } + setTimeout(this.update_price_loop.bind(this), 10000); // update every 10 seconds } // get XDai balance - async getXdaiBalance (wallet) { + async getXdaiBalance(wallet) { try { - const xDaiBalance = await wallet.getBalance() - return Ethers.utils.formatEther(xDaiBalance) + const xDaiBalance = await wallet.getBalance(); + return Ethers.utils.formatEther(xDaiBalance); } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error xDai balance lookup' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error xDai balance lookup'; + return reason; } } // get XDai USDC balance - async getUSDCBalance (wallet) { + async getUSDCBalance(wallet) { try { - const layer2Usdc = new Ethers.Contract(this.xUsdcAddr, TetherTokenArtifact.abi, wallet) - let layer2UsdcBalance = await layer2Usdc.balanceOf(wallet.address) - const layer2UsdcDecimals = await layer2Usdc.decimals() - return Ethers.utils.formatUnits(layer2UsdcBalance, layer2UsdcDecimals) + const layer2Usdc = new Ethers.Contract(this.xUsdcAddr, TetherTokenArtifact.abi, wallet); + const layer2UsdcBalance = await layer2Usdc.balanceOf(wallet.address); + const layer2UsdcDecimals = await layer2Usdc.decimals(); + return Ethers.utils.formatUnits(layer2UsdcBalance, layer2UsdcDecimals); } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error balance lookup' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error balance lookup'; + return reason; } } // get allowance - async getAllowance (wallet) { + async getAllowance(wallet) { // instantiate a contract and pass in provider for read-only access - const layer2Usdc = new Ethers.Contract(this.xUsdcAddr, TetherTokenArtifact.abi, wallet) + const layer2Usdc = new Ethers.Contract(this.xUsdcAddr, TetherTokenArtifact.abi, wallet); try { const allowanceForClearingHouse = await layer2Usdc.allowance( - wallet.address, - this.ClearingHouse - ) + wallet.address, + this.ClearingHouse, + ); - return Ethers.utils.formatUnits(allowanceForClearingHouse, DEFAULT_DECIMALS) + return Ethers.utils.formatUnits(allowanceForClearingHouse, DEFAULT_DECIMALS); } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error allowance lookup' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error allowance lookup'; + return reason; } } // approve - async approve (wallet, amount) { + async approve(wallet, amount) { try { // instantiate a contract and pass in wallet - const layer2Usdc = new Ethers.Contract(this.xUsdcAddr, TetherTokenArtifact.abi, wallet) - const tx = await layer2Usdc.approve(this.ClearingHouse, Ethers.utils.parseUnits(amount, DEFAULT_DECIMALS)) + const layer2Usdc = new Ethers.Contract(this.xUsdcAddr, TetherTokenArtifact.abi, wallet); + const tx = await layer2Usdc.approve(this.ClearingHouse, Ethers.utils.parseUnits(amount, DEFAULT_DECIMALS)); // TO-DO: We may want to supply custom gasLimit value above - return tx.hash + return tx.hash; } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error approval' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error approval'; + return reason; } } - //open Position + // open Position async openPosition(side, margin, levrg, pair, minBaseAmount, wallet) { try { - const quoteAssetAmount = { d: Ethers.utils.parseUnits(margin, DEFAULT_DECIMALS) } - const leverage = { d: Ethers.utils.parseUnits(levrg, DEFAULT_DECIMALS) } - const minBaseAssetAmount = { d: Ethers.utils.parseUnits(minBaseAmount, DEFAULT_DECIMALS) } - const clearingHouse = new Ethers.Contract(this.ClearingHouse, ClearingHouseArtifact.abi, wallet) + const quoteAssetAmount = { d: Ethers.utils.parseUnits(margin, DEFAULT_DECIMALS) }; + const leverage = { d: Ethers.utils.parseUnits(levrg, DEFAULT_DECIMALS) }; + const minBaseAssetAmount = { d: Ethers.utils.parseUnits(minBaseAmount, DEFAULT_DECIMALS) }; + const clearingHouse = new Ethers.Contract(this.ClearingHouse, ClearingHouseArtifact.abi, wallet); const tx = await clearingHouse.openPosition( this.amm[pair], side, quoteAssetAmount, leverage, minBaseAssetAmount, - { gasLimit: this.gasLimit } - ) - return tx + { gasLimit: this.gasLimit }, + ); + return tx; } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error opening position' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error opening position'; + return reason; } } - //close Position + // close Position async closePosition(wallet, pair, minimalQuote) { try { - const minimalQuoteAsset = { d: Ethers.utils.parseUnits(minimalQuote, DEFAULT_DECIMALS) } - const clearingHouse = new Ethers.Contract(this.ClearingHouse, ClearingHouseArtifact.abi, wallet) - const tx = await clearingHouse.closePosition(this.amm[pair], minimalQuoteAsset, { gasLimit: this.gasLimit } ) - return tx + const minimalQuoteAsset = { d: Ethers.utils.parseUnits(minimalQuote, DEFAULT_DECIMALS) }; + const clearingHouse = new Ethers.Contract(this.ClearingHouse, ClearingHouseArtifact.abi, wallet); + const tx = await clearingHouse.closePosition(this.amm[pair], minimalQuoteAsset, { gasLimit: this.gasLimit }); + return tx; } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error closing position' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error closing position'; + return reason; } } - //get active position - async getPosition(wallet, pair) { + // get active position + async getPosition(wallet, pair) { try { - const positionValues = {} - const clearingHouse = new Ethers.Contract(this.ClearingHouse, ClearingHouseArtifact.abi, wallet) - let premIndex = 0 + const positionValues = {}; + const clearingHouse = new Ethers.Contract(this.ClearingHouse, ClearingHouseArtifact.abi, wallet); + let premIndex = 0; await Promise.allSettled([clearingHouse.getPosition(this.amm[pair], - wallet.address), - clearingHouse.getLatestCumulativePremiumFraction(this.amm[pair]), - clearingHouse.getPositionNotionalAndUnrealizedPnl(this.amm[pair], - wallet.address, - Ethers.BigNumber.from(PNL_OPTION_SPOT_PRICE))]) - .then(values => {positionValues.openNotional = Ethers.utils.formatUnits(values[0].value.openNotional.d, DEFAULT_DECIMALS); - positionValues.size = Ethers.utils.formatUnits(values[0].value.size.d, DEFAULT_DECIMALS); - positionValues.margin = Ethers.utils.formatUnits(values[0].value.margin.d, DEFAULT_DECIMALS); - positionValues.cumulativePremiumFraction = Ethers.utils.formatUnits(values[0].value.lastUpdatedCumulativePremiumFraction.d, DEFAULT_DECIMALS); - premIndex = Ethers.utils.formatUnits(values[1].value.d, DEFAULT_DECIMALS); - positionValues.pnl = Ethers.utils.formatUnits(values[2].value.unrealizedPnl.d, DEFAULT_DECIMALS); - positionValues.positionNotional = Ethers.utils.formatUnits(values[2].value.positionNotional.d, DEFAULT_DECIMALS);}) + wallet.address), + clearingHouse.getLatestCumulativePremiumFraction(this.amm[pair]), + clearingHouse.getPositionNotionalAndUnrealizedPnl(this.amm[pair], + wallet.address, + Ethers.BigNumber.from(PNL_OPTION_SPOT_PRICE))]) + .then((values) => { + positionValues.openNotional = Ethers.utils.formatUnits(values[0].value.openNotional.d, DEFAULT_DECIMALS); + positionValues.size = Ethers.utils.formatUnits(values[0].value.size.d, DEFAULT_DECIMALS); + positionValues.margin = Ethers.utils.formatUnits(values[0].value.margin.d, DEFAULT_DECIMALS); + positionValues.cumulativePremiumFraction = Ethers.utils.formatUnits(values[0].value.lastUpdatedCumulativePremiumFraction.d, DEFAULT_DECIMALS); + premIndex = Ethers.utils.formatUnits(values[1].value.d, DEFAULT_DECIMALS); + positionValues.pnl = Ethers.utils.formatUnits(values[2].value.unrealizedPnl.d, DEFAULT_DECIMALS); + positionValues.positionNotional = Ethers.utils.formatUnits(values[2].value.positionNotional.d, DEFAULT_DECIMALS); + }); - positionValues.entryPrice = Math.abs(positionValues.openNotional / positionValues.size) - positionValues.fundingPayment = (premIndex - positionValues.cumulativePremiumFraction) * positionValues.size // * -1 - return positionValues + positionValues.entryPrice = Math.abs(positionValues.openNotional / positionValues.size); + positionValues.fundingPayment = (premIndex - positionValues.cumulativePremiumFraction) * positionValues.size; // * -1 + return positionValues; } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error getting active position' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error getting active position'; + return reason; } } - //get active margin + // get active margin async getActiveMargin(wallet) { try { - const clearingHouseViewer = new Ethers.Contract(this.ClearingHouseViewer, ClearingHouseViewerArtifact.abi, wallet) + const clearingHouseViewer = new Ethers.Contract(this.ClearingHouseViewer, ClearingHouseViewerArtifact.abi, wallet); const activeMargin = await clearingHouseViewer.getPersonalBalanceWithFundingPayment( - this.xUsdcAddr, - wallet.address) - return activeMargin / 1e18.toString() + this.xUsdcAddr, + wallet.address, + ); + return activeMargin / 1e18.toString(); } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error getting active position' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error getting active position'; + return reason; } } // get Price async getPrice(side, amount, pair) { try { - let price - this.cacheExpirary[pair] = Date.now() + UPDATE_PERIOD - this.pairAmountCache[pair] = amount - if (!this.priceCache.hasOwnProperty(pair)){ - const amm = new Ethers.Contract(this.amm[pair], AmmArtifact.abi, this.provider) - if (side === "buy") { - price = await amm.getInputPrice(0, {d: Ethers.utils.parseUnits(amount, DEFAULT_DECIMALS) }) - price = amount / Ethers.utils.formatUnits(price.d) - } else { - price = await amm.getOutputPrice(0, {d: Ethers.utils.parseUnits(amount, DEFAULT_DECIMALS) }) - price = Ethers.utils.formatUnits(price.d) / amount - } - } else { - if (side === "buy") { - price = this.priceCache[pair][0] - } else { price = this.priceCache[pair][1] } - } - return price + let price; + this.cacheExpirary[pair] = Date.now() + UPDATE_PERIOD; + this.pairAmountCache[pair] = amount; + if (!this.priceCache.hasOwnProperty(pair)) { + const amm = new Ethers.Contract(this.amm[pair], AmmArtifact.abi, this.provider); + if (side === 'buy') { + price = await amm.getInputPrice(0, { d: Ethers.utils.parseUnits(amount, DEFAULT_DECIMALS) }); + price = amount / Ethers.utils.formatUnits(price.d); + } else { + price = await amm.getOutputPrice(0, { d: Ethers.utils.parseUnits(amount, DEFAULT_DECIMALS) }); + price = Ethers.utils.formatUnits(price.d) / amount; + } + } else if (side === 'buy') { + price = this.priceCache[pair][0]; + } else { price = this.priceCache[pair][1]; } + return price; } catch (err) { - console.log(err) - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error getting Price' - return reason + console.log(err); + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error getting Price'; + return reason; } } // get getFundingRate async getFundingRate(pair) { try { - let funding = {} - const amm = new Ethers.Contract(this.amm[pair], AmmArtifact.abi, this.provider) + const funding = {}; + const amm = new Ethers.Contract(this.amm[pair], AmmArtifact.abi, this.provider); await Promise.allSettled([amm.getUnderlyingTwapPrice(3600), - amm.getTwapPrice(3600), - amm.nextFundingTime()]) - .then(values => {funding.indexPrice = parseFloat(Ethers.utils.formatUnits(values[0].value.d)); - funding.markPrice = parseFloat(Ethers.utils.formatUnits(values[1].value.d)); - funding.nextFundingTime = parseInt(values[2].value.toString());}) + amm.getTwapPrice(3600), + amm.nextFundingTime()]) + .then((values) => { + funding.indexPrice = parseFloat(Ethers.utils.formatUnits(values[0].value.d)); + funding.markPrice = parseFloat(Ethers.utils.formatUnits(values[1].value.d)); + funding.nextFundingTime = parseInt(values[2].value.toString()); + }); - funding.rate = ((funding.markPrice - funding.indexPrice) / 24) / funding.indexPrice - return funding + funding.rate = ((funding.markPrice - funding.indexPrice) / 24) / funding.indexPrice; + return funding; } catch (err) { - console.log(err) - logger.error(err)() - let reason - err.reason ? reason = err.reason : reason = 'error getting fee' - return reason + console.log(err); + logger.error(err)(); + let reason; + err.reason ? reason = err.reason : reason = 'error getting fee'; + return reason; } } - } diff --git a/src/services/terra.js b/src/services/terra.js index 38dac2e..613f284 100644 --- a/src/services/terra.js +++ b/src/services/terra.js @@ -1,10 +1,12 @@ +import { + LCDClient, Coin, MsgSwap, MnemonicKey, isTxError, +} from '@terra-money/terra.js'; +import BigNumber from 'bignumber.js'; import { logger } from './logger'; -import { LCDClient, Coin, MsgSwap, StdTx, StdFee, Dec, MnemonicKey, isTxError, Coins } from '@terra-money/terra.js' -import BigNumber from 'bignumber.js' import { getHummingbotMemo } from './utils'; -const debug = require('debug')('router') -require('dotenv').config() +const debug = require('debug')('router'); +require('dotenv').config(); // constants const TERRA_TOKENS = { @@ -13,304 +15,305 @@ const TERRA_TOKENS = { ukrw: { symbol: 'KRT' }, usdr: { symbol: 'SDT' }, umnt: { symbol: 'MNT' }, -} -const DENOM_UNIT = BigNumber('1e+6') -const TOBIN_TAX = 0.0025 // a Tobin Tax (set at 0.25%) for spot-converting Terra<>Terra swaps -const MIN_SPREAD = 0.02 // a minimum spread (set at 2%) for Terra<>Luna swaps -const GAS_PRICE = { uluna: 0.16 } -const GAS_ADJUSTMENT = 1.4 +}; +const DENOM_UNIT = BigNumber('1e+6'); +const TOBIN_TAX = 0.0025; // a Tobin Tax (set at 0.25%) for spot-converting Terra<>Terra swaps +const MIN_SPREAD = 0.02; // a minimum spread (set at 2%) for Terra<>Luna swaps +const GAS_PRICE = { uluna: 0.16 }; +const GAS_ADJUSTMENT = 1.4; export default class Terra { - constructor () { + constructor() { this.lcdUrl = process.env.TERRA_LCD_URL; - this.network = process.env.TERRA_CHAIN; - this.tokens = TERRA_TOKENS - this.denomUnitMultiplier = DENOM_UNIT - this.tobinTax = TOBIN_TAX - this.minSpread = MIN_SPREAD - this.memo = getHummingbotMemo() + this.network = process.env.TERRA_CHAIN; + this.tokens = TERRA_TOKENS; + this.denomUnitMultiplier = DENOM_UNIT; + this.tobinTax = TOBIN_TAX; + this.minSpread = MIN_SPREAD; + this.memo = getHummingbotMemo(); try { - this.lcd = this.connect() + this.lcd = this.connect(); this.lcd.market.parameters().catch(() => { - throw new Error('Connection error') - }) + throw new Error('Connection error'); + }); // set gas & fee - this.lcd.config.gasAdjustment = GAS_ADJUSTMENT - this.lcd.config.gasPrices = GAS_PRICE + this.lcd.config.gasAdjustment = GAS_ADJUSTMENT; + this.lcd.config.gasPrices = GAS_PRICE; } catch (err) { - logger.error(err) - throw Error(`Connection failed: ${this.network}`) + logger.error(err); + throw Error(`Connection failed: ${this.network}`); } } // connect Terra LCD - connect () { + connect() { try { const lcd = new LCDClient({ URL: this.lcdUrl, chainID: this.network, - }) - lcd.config.gasAdjustment = GAS_ADJUSTMENT - lcd.config.gasPrices = GAS_PRICE - return lcd + }); + lcd.config.gasAdjustment = GAS_ADJUSTMENT; + lcd.config.gasPrices = GAS_PRICE; + return lcd; } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error Terra LCD connect' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error Terra LCD connect'; + return reason; } } // get Token Denom - getTokenDenom (symbol) { + getTokenDenom(symbol) { try { - let denom + let denom; Object.keys(TERRA_TOKENS).forEach((item) => { if (TERRA_TOKENS[item].symbol === symbol) { - denom = item + denom = item; } - }) - return denom + }); + return denom; } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error Terra Denom lookup' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error Terra Denom lookup'; + return reason; } } // get Token Symbol - getTokenSymbol (denom) { + getTokenSymbol(denom) { try { - const symbol = TERRA_TOKENS[denom].symbol - return symbol + const { symbol } = TERRA_TOKENS[denom]; + return symbol; } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error Terra Denom lookup' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error Terra Denom lookup'; + return reason; } } - getTxAttributes (attributes) { - let attrib = {} + getTxAttributes(attributes) { + const attrib = {}; attributes.forEach((item) => { - attrib[item.key] = item.value - }) - return attrib + attrib[item.key] = item.value; + }); + return attrib; } - async getEstimateFee (tx) { + async getEstimateFee(tx) { try { - const fee = await this.lcd.tx.estimateFee(tx) - return fee + const fee = await this.lcd.tx.estimateFee(tx); + return fee; } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error Terra estimate fee lookup' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error Terra estimate fee lookup'; + return reason; } } - async getExchangeRate (denom) { + async getExchangeRate(denom) { try { - const exchangeRates = await this.lcd.oracle.exchangeRates() - return exchangeRates.get(denom) + const exchangeRates = await this.lcd.oracle.exchangeRates(); + return exchangeRates.get(denom); } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error Terra exchange rate lookup' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error Terra exchange rate lookup'; + return reason; } } - async getTxFee () { + async getTxFee() { try { - const lunaFee = GAS_PRICE.uluna * GAS_ADJUSTMENT - let feeList = { uluna: lunaFee } - await this.lcd.oracle.exchangeRates().then(rates => { - Object.keys(rates._coins).forEach(key => { - feeList[key] = rates._coins[key].amount * lunaFee - }) - }) - debug('lunaFee', lunaFee, feeList) - - return feeList + const lunaFee = GAS_PRICE.uluna * GAS_ADJUSTMENT; + const feeList = { uluna: lunaFee }; + await this.lcd.oracle.exchangeRates().then((rates) => { + Object.keys(rates._coins).forEach((key) => { + feeList[key] = rates._coins[key].amount * lunaFee; + }); + }); + debug('lunaFee', lunaFee, feeList); + + return feeList; } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error Terra exchange rate lookup' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error Terra exchange rate lookup'; + return reason; } } // get Terra Swap Rate - async getSwapRate (baseToken, quoteToken, amount, tradeType) { + async getSwapRate(baseToken, quoteToken, amount, tradeType) { try { - let exchangeRate, offerCoin, offerDenom, swapDenom, cost, costAmount, offer - let swaps = {} + let exchangeRate; let offerCoin; let offerDenom; let swapDenom; let cost; let costAmount; let + offer; + const swaps = {}; if (tradeType.toLowerCase() === 'sell') { // sell base - offerDenom = this.getTokenDenom(baseToken) - swapDenom = this.getTokenDenom(quoteToken) + offerDenom = this.getTokenDenom(baseToken); + swapDenom = this.getTokenDenom(quoteToken); offerCoin = new Coin(offerDenom, amount * DENOM_UNIT); - await this.lcd.market.swapRate(offerCoin, swapDenom).then(swapCoin => { - offer = { amount: amount } + await this.lcd.market.swapRate(offerCoin, swapDenom).then((swapCoin) => { + offer = { amount }; exchangeRate = { amount: (swapCoin.amount / DENOM_UNIT) / amount, - token: quoteToken - } - costAmount = amount * exchangeRate.amount + token: quoteToken, + }; + costAmount = amount * exchangeRate.amount; cost = { amount: costAmount, - token: quoteToken - } - }) + token: quoteToken, + }; + }); } else { // buy base - offerDenom = this.getTokenDenom(quoteToken) - swapDenom = this.getTokenDenom(baseToken) + offerDenom = this.getTokenDenom(quoteToken); + swapDenom = this.getTokenDenom(baseToken); offerCoin = new Coin(offerDenom, 1 * DENOM_UNIT); - await this.lcd.market.swapRate(offerCoin, swapDenom).then(swapCoin => { + await this.lcd.market.swapRate(offerCoin, swapDenom).then((swapCoin) => { exchangeRate = { amount: (amount / parseInt(swapCoin.amount) * DENOM_UNIT) / amount, // adjusted amount - token: quoteToken - } - costAmount = amount * exchangeRate.amount + token: quoteToken, + }; + costAmount = amount * exchangeRate.amount; cost = { amount: costAmount, - token: quoteToken - } - offer = { amount: cost.amount } - }) + token: quoteToken, + }; + offer = { amount: cost.amount }; + }); } - let txFee - await this.getTxFee().then(fee => { + let txFee; + await this.getTxFee().then((fee) => { // fee in quote - txFee = { amount: parseFloat(fee[this.getTokenDenom(quoteToken)]), token: quoteToken } - }) - - swaps.offer = offer - swaps.price = exchangeRate - swaps.cost = cost - swaps.txFee = txFee - debug('swaps', swaps) - return swaps + txFee = { amount: parseFloat(fee[this.getTokenDenom(quoteToken)]), token: quoteToken }; + }); + + swaps.offer = offer; + swaps.price = exchangeRate; + swaps.cost = cost; + swaps.txFee = txFee; + debug('swaps', swaps); + return swaps; } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = 'error swap rate lookup' - return reason + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = 'error swap rate lookup'; + return reason; } } // Swap tokens - async swapTokens (baseToken, quoteToken, amount, tradeType, gasPrice, gasAdjustment, secret) { - let swapResult + async swapTokens(baseToken, quoteToken, amount, tradeType, gasPrice, gasAdjustment, secret) { + let swapResult; try { // connect to lcd - const lcd = this.connect() + const lcd = this.connect(); const mk = new MnemonicKey({ mnemonic: secret, }); - let wallet + let wallet; try { wallet = lcd.wallet(mk); } catch (err) { - logger.error(err) - throw Error('Wallet access error') + logger.error(err); + throw Error('Wallet access error'); } - const address = wallet.key.accAddress + const address = wallet.key.accAddress; // get the current swap rate - const baseDenom = this.getTokenDenom(baseToken) - const quoteDenom = this.getTokenDenom(quoteToken) + const baseDenom = this.getTokenDenom(baseToken); + const quoteDenom = this.getTokenDenom(quoteToken); - let offerDenom, swapDenom - let swaps, txAttributes - let tokenSwap = {} + let offerDenom; let + swapDenom; + let swaps; let + txAttributes; + const tokenSwap = {}; if (tradeType.toLowerCase() === 'sell') { - offerDenom = baseDenom - swapDenom = quoteDenom + offerDenom = baseDenom; + swapDenom = quoteDenom; } else { - offerDenom = quoteDenom - swapDenom = baseDenom + offerDenom = quoteDenom; + swapDenom = baseDenom; } await this.getSwapRate(baseToken, quoteToken, amount, tradeType, secret).then((rate) => { - swaps = rate - }) + swaps = rate; + }); - const offerAmount = parseInt((swaps.offer.amount) * DENOM_UNIT) - const offerCoin = new Coin(offerDenom, offerAmount) + const offerAmount = parseInt((swaps.offer.amount) * DENOM_UNIT); + const offerCoin = new Coin(offerDenom, offerAmount); // Create and Sign Transaction const msgSwap = new MsgSwap(address, offerCoin, swapDenom); - let txOptions + let txOptions; if (gasPrice !== null && gasPrice !== null) { // ignore gasAdjustment when gasPrice is not set txOptions = { msgs: [msgSwap], gasPrices: { uluna: parseFloat(gasPrice) }, - gasAdjustment: gasAdjustment, - memo: this.memo - } + gasAdjustment, + memo: this.memo, + }; } else { txOptions = { msgs: [msgSwap], - memo: this.memo - } + memo: this.memo, + }; } - await wallet.createAndSignTx(txOptions).then(tx => lcd.tx.broadcast(tx)).then((txResult) => { - swapResult = txResult + await wallet.createAndSignTx(txOptions).then((tx) => lcd.tx.broadcast(tx)).then((txResult) => { + swapResult = txResult; - const swapSuccess = !isTxError(txResult) + const swapSuccess = !isTxError(txResult); if (swapSuccess) { - tokenSwap.txSuccess = swapSuccess + tokenSwap.txSuccess = swapSuccess; } else { - tokenSwap.txSuccess = !swapSuccess + tokenSwap.txSuccess = !swapSuccess; throw new Error(`encountered an error while running the transaction: ${txResult.code} ${txResult.codespace}`); } - const txHash = txResult.txhash - const events = JSON.parse(txResult.raw_log)[0].events - const swap = events.find(obj => { - return obj.type === 'swap' - }) - txAttributes = this.getTxAttributes(swap.attributes) - const offer = Coin.fromString(txAttributes.offer) - const ask = Coin.fromString(txAttributes.swap_coin) - const fee = Coin.fromString(txAttributes.swap_fee) - - tokenSwap.expectedIn = { + const txHash = txResult.txhash; + const { events } = JSON.parse(txResult.raw_log)[0]; + const swap = events.find((obj) => obj.type === 'swap'); + txAttributes = this.getTxAttributes(swap.attributes); + const offer = Coin.fromString(txAttributes.offer); + const ask = Coin.fromString(txAttributes.swap_coin); + const fee = Coin.fromString(txAttributes.swap_fee); + + tokenSwap.expectedIn = { amount: parseFloat(offer.amount) / DENOM_UNIT, - token: TERRA_TOKENS[offer.denom].symbol - } + token: TERRA_TOKENS[offer.denom].symbol, + }; tokenSwap.expectedOut = { amount: parseFloat(ask.amount) / DENOM_UNIT, - token: TERRA_TOKENS[ask.denom].symbol - } + token: TERRA_TOKENS[ask.denom].symbol, + }; tokenSwap.fee = { amount: parseFloat(fee.amount) / DENOM_UNIT, - token: TERRA_TOKENS[fee.denom].symbol - } - tokenSwap.txHash = txHash - }) - return tokenSwap + token: TERRA_TOKENS[fee.denom].symbol, + }; + tokenSwap.txHash = txHash; + }); + return tokenSwap; } catch (err) { - logger.error(err) - let reason - err.reason ? reason = err.reason : reason = swapResult - return { txSuccess: false, message: reason } + logger.error(err); + let reason; + err.reason ? reason = err.reason : reason = swapResult; + return { txSuccess: false, message: reason }; } } } diff --git a/src/services/uniswap.js b/src/services/uniswap.js index 8fe7bbb..9298b54 100644 --- a/src/services/uniswap.js +++ b/src/services/uniswap.js @@ -1,35 +1,35 @@ import { logger } from './logger'; -const debug = require('debug')('router') -const math = require('mathjs') -const uni = require('@uniswap/sdk') -const ethers = require('ethers') -const proxyArtifact = require('../static/uniswap_v2_router_abi.json') -const routeTokens = require('../static/uniswap_route_tokens.json') +const debug = require('debug')('router'); +const math = require('mathjs'); +const uni = require('@uniswap/sdk'); +const ethers = require('ethers'); +const proxyArtifact = require('../static/uniswap_v2_router_abi.json'); +const routeTokens = require('../static/uniswap_route_tokens.json'); // constants -const ROUTER = process.env.UNISWAP_ROUTER +const ROUTER = process.env.UNISWAP_ROUTER; const GAS_LIMIT = process.env.UNISWAP_GAS_LIMIT || 150688; const TTL = process.env.UNISWAP_TTL || 300; -const UPDATE_PERIOD = process.env.UNISWAP_UPDATE_PERIOD || 300000; // stop updating pair after 5 minutes from last request +const UPDATE_PERIOD = process.env.UNISWAP_UPDATE_PERIOD || 300000; // stop updating pair after 5 minutes from last request export default class Uniswap { - constructor (network = 'mainnet') { - this.providerUrl = process.env.ETHEREUM_RPC_URL - this.network = process.env.ETHEREUM_CHAIN - this.provider = new ethers.providers.JsonRpcProvider(this.providerUrl) + constructor(network = 'mainnet') { + this.providerUrl = process.env.ETHEREUM_RPC_URL; + this.network = process.env.ETHEREUM_CHAIN; + this.provider = new ethers.providers.JsonRpcProvider(this.providerUrl); this.router = ROUTER; - this.slippage = math.fraction(process.env.UNISWAP_ALLOWED_SLIPPAGE) - this.allowedSlippage = new uni.Percent(this.slippage.n, (this.slippage.d * 100)) - this.pairsCacheTime = process.env.UNISWAP_PAIRS_CACHE_TIME - this.gasLimit = GAS_LIMIT - this.expireTokenPairUpdate = UPDATE_PERIOD - this.zeroReserveCheckInterval = process.env.UNISWAP_NO_RESERVE_CHECK_INTERVAL - this.zeroReservePairs = {} // No reserve pairs - this.tokenList = {} - this.pairs = [] - this.tokenSwapList = {} - this.cachedRoutes = {} + this.slippage = math.fraction(process.env.UNISWAP_ALLOWED_SLIPPAGE); + this.allowedSlippage = new uni.Percent(this.slippage.n, (this.slippage.d * 100)); + this.pairsCacheTime = process.env.UNISWAP_PAIRS_CACHE_TIME; + this.gasLimit = GAS_LIMIT; + this.expireTokenPairUpdate = UPDATE_PERIOD; + this.zeroReserveCheckInterval = process.env.UNISWAP_NO_RESERVE_CHECK_INTERVAL; + this.zeroReservePairs = {}; // No reserve pairs + this.tokenList = {}; + this.pairs = []; + this.tokenSwapList = {}; + this.cachedRoutes = {}; switch (network) { case 'mainnet': @@ -39,45 +39,44 @@ export default class Uniswap { this.chainID = uni.ChainId.KOVAN; break; default: - const err = `Invalid network ${network}` - logger.error(err) - throw Error(err) + const err = `Invalid network ${network}`; + logger.error(err); + throw Error(err); } } - async fetch_route(tIn, tOut){ - var route, pair, pairOne, pairTwo + async fetch_route(tIn, tOut) { + let route; + let pair; - try { - pair = await uni.Fetcher.fetchPairData(tIn, tOut); - route = new uni.Route([pair], tIn, tOut); - } - catch(err) { - logger.error(err); - } - return route; + try { + pair = await uni.Fetcher.fetchPairData(tIn, tOut); + route = new uni.Route([pair], tIn, tOut); + } catch (err) { + logger.error(err); + } + return route; } - - generate_tokens(){ - for (let token of routeTokens[this.network]){ - this.tokenList[token["address"]] = new uni.Token(this.chainID, token["address"], token["decimals"], token["symbol"], token["name"]); + generate_tokens() { + for (const token of routeTokens[this.network]) { + this.tokenList[token.address] = new uni.Token(this.chainID, token.address, token.decimals, token.symbol, token.name); } } - async extend_update_pairs(tokens=[]){ - for (let token of tokens){ - if (!this.tokenList.hasOwnProperty(token)){ - this.tokenList[token] = await uni.Fetcher.fetchTokenData(this.chainID, token); - } - this.tokenSwapList[token] = Date.now() + this.expireTokenPairUpdate; + async extend_update_pairs(tokens = []) { + for (const token of tokens) { + if (!this.tokenList.hasOwnProperty(token)) { + this.tokenList[token] = await uni.Fetcher.fetchTokenData(this.chainID, token); } + this.tokenSwapList[token] = Date.now() + this.expireTokenPairUpdate; + } } - async update_pairs(){ + async update_pairs() { // Remove banned pairs after ban period - if (Object.keys(this.zeroReservePairs).length > 0){ - for (let pair in this.zeroReservePairs){ + if (Object.keys(this.zeroReservePairs).length > 0) { + for (const pair in this.zeroReservePairs) { if (this.zeroReservePairs[pair] <= Date.now()) { delete this.zeroReservePairs[pair]; // delete this.tokenList[token]; @@ -86,132 +85,132 @@ export default class Uniswap { } // Generate all possible pair combinations of tokens // This is done by generating an upper triangular matrix or right triangular matrix - if (Object.keys(this.tokenSwapList).length > 0){ - for (let token in this.tokenSwapList){ + if (Object.keys(this.tokenSwapList).length > 0) { + for (const token in this.tokenSwapList) { if (this.tokenSwapList[token] <= Date.now()) { delete this.tokenSwapList[token]; // delete this.tokenList[token]; } } - let tokens = Object.keys(this.tokenList); - var firstToken, secondToken, position; - let length = tokens.length; - let pairs = []; - let pairAddressRequests = []; - let pairAddressResponses = []; - for (firstToken = 0; firstToken < length; firstToken++){ - for (secondToken = firstToken + 1; secondToken < length; secondToken++){ - try{ - let pairString = this.tokenList[tokens[firstToken]].address + '-' + this.tokenList[tokens[secondToken]].address; - if (!this.zeroReservePairs.hasOwnProperty(pairString)){ + const tokens = Object.keys(this.tokenList); + let firstToken; let secondToken; let + position; + const length = tokens.length; + const pairs = []; + const pairAddressRequests = []; + const pairAddressResponses = []; + for (firstToken = 0; firstToken < length; firstToken++) { + for (secondToken = firstToken + 1; secondToken < length; secondToken++) { + try { + const pairString = `${this.tokenList[tokens[firstToken]].address}-${this.tokenList[tokens[secondToken]].address}`; + if (!this.zeroReservePairs.hasOwnProperty(pairString)) { pairs.push(pairString); pairAddressRequests.push(uni.Fetcher.fetchPairData(this.tokenList[tokens[firstToken]], this.tokenList[tokens[secondToken]])); } - } - catch(err) { + } catch (err) { logger.error(err); } } } - await Promise.allSettled(pairAddressRequests).then(values => { for (position = 0; position < pairAddressRequests.length; position++) { - if (values[position].status === "fulfilled"){pairAddressResponses.push(values[position].value)} - else {this.zeroReservePairs[pairs[position]] = Date.now() + this.zeroReserveCheckInterval;}}}) + await Promise.allSettled(pairAddressRequests).then((values) => { + for (position = 0; position < pairAddressRequests.length; position++) { + if (values[position].status === 'fulfilled') { pairAddressResponses.push(values[position].value); } else { this.zeroReservePairs[pairs[position]] = Date.now() + this.zeroReserveCheckInterval; } + } + }); this.pairs = pairAddressResponses; } setTimeout(this.update_pairs.bind(this), 1000); } - async priceSwapIn (tokenIn, tokenOut, tokenInAmount) { + async priceSwapIn(tokenIn, tokenOut, tokenInAmount) { await this.extend_update_pairs([tokenIn, tokenOut]); const tIn = this.tokenList[tokenIn]; const tOut = this.tokenList[tokenOut]; const tokenAmountIn = new uni.TokenAmount(tIn, ethers.utils.parseUnits(tokenInAmount, tIn.decimals)); - if (this.pairs.length === 0){ + if (this.pairs.length === 0) { const route = await this.fetch_route(tIn, tOut); const trade = uni.Trade.exactIn(route, tokenAmountIn); - if ( trade !== undefined ){ + if (trade !== undefined) { const expectedAmount = trade.minimumAmountOut(this.allowedSlippage); this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade; - return { trade, expectedAmount } + return { trade, expectedAmount }; } - return "Can't find route to swap, kindly update " + return "Can't find route to swap, kindly update "; } - const trade = uni.Trade.bestTradeExactIn(this.pairs, tokenAmountIn, this.tokenList[tokenOut], { maxHops: 5 })[0]; - if (trade === undefined){trade = this.cachedRoutes[tIn.symbol + tOut.Symbol];} - else{this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade;} + let trade = uni.Trade.bestTradeExactIn(this.pairs, tokenAmountIn, this.tokenList[tokenOut], { maxHops: 5 })[0]; + if (trade === undefined) { trade = this.cachedRoutes[tIn.symbol + tOut.Symbol]; } else { this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade; } const expectedAmount = trade.minimumAmountOut(this.allowedSlippage); - return { trade, expectedAmount } + return { trade, expectedAmount }; } - async priceSwapOut (tokenIn, tokenOut, tokenOutAmount) { + async priceSwapOut(tokenIn, tokenOut, tokenOutAmount) { await this.extend_update_pairs([tokenIn, tokenOut]); const tOut = this.tokenList[tokenOut]; const tIn = this.tokenList[tokenIn]; const tokenAmountOut = new uni.TokenAmount(tOut, ethers.utils.parseUnits(tokenOutAmount, tOut.decimals)); - if (this.pairs.length === 0){ + if (this.pairs.length === 0) { const route = await this.fetch_route(tIn, tOut); const trade = uni.Trade.exactOut(route, tokenAmountOut); - if ( trade !== undefined ){ + if (trade !== undefined) { const expectedAmount = trade.maximumAmountIn(this.allowedSlippage); this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade; - return { trade, expectedAmount } + return { trade, expectedAmount }; } - return + return; } - const trade = uni.Trade.bestTradeExactOut(this.pairs, this.tokenList[tokenIn], tokenAmountOut, { maxHops: 5 })[0]; - if (trade === undefined){trade = this.cachedRoutes[tIn.symbol + tOut.Symbol];} - else{this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade;} + let trade = uni.Trade.bestTradeExactOut(this.pairs, this.tokenList[tokenIn], tokenAmountOut, { maxHops: 5 })[0]; + if (trade === undefined) { trade = this.cachedRoutes[tIn.symbol + tOut.Symbol]; } else { this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade; } const expectedAmount = trade.maximumAmountIn(this.allowedSlippage); - return { trade, expectedAmount } + return { trade, expectedAmount }; } - async swapExactIn (wallet, trade, tokenAddress, gasPrice) { + async swapExactIn(wallet, trade, tokenAddress, gasPrice) { const result = uni.Router.swapCallParameters( trade, { ttl: TTL, recipient: wallet.address, - allowedSlippage: this.allowedSlippage - } - ) + allowedSlippage: this.allowedSlippage, + }, + ); - const contract = new ethers.Contract(this.router, proxyArtifact.abi, wallet) - const tx = await contract.[result.methodName]( + const contract = new ethers.Contract(this.router, proxyArtifact.abi, wallet); + const tx = await contract[result.methodName]( ...result.args, { gasPrice: gasPrice * 1e9, gasLimit: GAS_LIMIT, - value: result.value - } - ) + value: result.value, + }, + ); debug(`Tx Hash: ${tx.hash}`); - return tx + return tx; } - async swapExactOut (wallet, trade, tokenAddress, gasPrice) { + async swapExactOut(wallet, trade, tokenAddress, gasPrice) { const result = uni.Router.swapCallParameters( trade, { ttl: TTL, recipient: wallet.address, - allowedSlippage: this.allowedSlippage - } - ) + allowedSlippage: this.allowedSlippage, + }, + ); - const contract = new ethers.Contract(this.router, proxyArtifact.abi, wallet) - const tx = await contract.[result.methodName]( + const contract = new ethers.Contract(this.router, proxyArtifact.abi, wallet); + const tx = await contract[result.methodName]( ...result.args, { gasPrice: gasPrice * 1e9, gasLimit: GAS_LIMIT, - value: result.value - } - ) + value: result.value, + }, + ); debug(`Tx Hash: ${tx.hash}`); - return tx + return tx; } } diff --git a/src/services/utils.js b/src/services/utils.js index 23182cc..430936b 100644 --- a/src/services/utils.js +++ b/src/services/utils.js @@ -1,8 +1,8 @@ /* Hummingbot Utils */ -const lodash = require('lodash') -const moment = require('moment') +const lodash = require('lodash'); +const moment = require('moment'); export const statusMessages = { ssl_cert_required: 'SSL Certificate required', @@ -12,74 +12,75 @@ export const statusMessages = { invalid_token_symbol: 'Invalid Token Symbol', insufficient_reserves: 'Insufficient Liquidity Reserves', page_not_found: 'Page not found. Invalid path', -} +}; -export const latency = (startTime, endTime) => parseFloat((endTime - startTime) / 1000) +export const latency = (startTime, endTime) => parseFloat((endTime - startTime) / 1000); export const isValidParams = (params) => { - const values = Object.values(params) - for (let i = 0; i < values.length; i++) { // DO NOT use forEach, it returns callback without breaking the loop + const values = Object.values(params); + // DO NOT use forEach, it returns callback without breaking the loop + for (let i = 0; i < values.length; i++) { if (typeof values[i] === 'undefined') { - throw new Error('Invalid input params') + throw new Error('Invalid input params'); } } - return true -} + return true; +}; export const isValidData = (data, format) => { if (typeof data !== 'undefined' && Object.keys(data).length !== 0 && lodash.isEqual(Object.keys(data).sort(), format.sort())) { - return true + return true; } - return false -} + return false; +}; export const getParamData = (data, format = null) => { - const dataObject = {} + const dataObject = {}; if (format !== null) { if (isValidData(data, format)) { - format.forEach((key, index) => { - dataObject[key] = data[key] - }) + format.forEach((key, _index) => { + dataObject[key] = data[key]; + }); } } else { - Object.keys(data).forEach((key, index) => { - dataObject[key] = data[key] - }) + Object.keys(data).forEach((key, _index) => { + dataObject[key] = data[key]; + }); } - return dataObject -} + return dataObject; +}; export const splitParamData = (param, separator = ',') => { - const dataArray = param.split(separator) - return dataArray -} + const dataArray = param.split(separator); + return dataArray; +}; export const getSymbols = (tradingPair) => { - const symbols = tradingPair.split('-') + const symbols = tradingPair.split('-'); const baseQuotePair = { base: symbols[0].toUpperCase(), - quote: symbols[1].toUpperCase() - } - return baseQuotePair -} + quote: symbols[1].toUpperCase(), + }; + return baseQuotePair; +}; export const reportConnectionError = (res, error) => { res.json({ error: error.errno, code: error.code, - }) -} + }); +}; export const strToDecimal = (str) => parseInt(str) / 100; export const getHummingbotMemo = () => { - const prefix = 'hbot' - const clientId = process.env.HUMMINGBOT_INSTANCE_ID + const prefix = 'hbot'; + const clientId = process.env.HUMMINGBOT_INSTANCE_ID; if ((typeof clientId !== 'undefined' && clientId != null) && clientId !== '') { - return [prefix, clientId].join('-') + return [prefix, clientId].join('-'); } - return prefix -} + return prefix; +}; export const loadConfig = () => { const config = { @@ -87,7 +88,7 @@ export const loadConfig = () => { ethereum_chain: process.env.ETHEREUM_CHAIN, exchange_proxy: process.env.EXCHANGE_PROXY, ethereum_token_list_url: process.env.ETHEREUM_TOKEN_LIST_URL, - enable_eth_gas_station: process.env.ENABLE_ETH_GAS_STATION != null ? (process.env.ENABLE_ETH_GAS_STATION.toLowerCase() == 'true') : false, + enable_eth_gas_station: process.env.ENABLE_ETH_GAS_STATION != null ? (process.env.ENABLE_ETH_GAS_STATION.toLowerCase() === 'true') : false, eth_gas_station_gas_level: process.env.ETH_GAS_STATION_GAS_LEVEL, eth_gas_station_refresh_time: process.env.ETH_GAS_STATION_REFRESH_TIME != null ? parseFloat(process.env.ETH_GAS_STATION_REFRESH_TIME) : null, manual_gas_price: process.env.MANUAL_GAS_PRICE != null ? parseFloat(process.env.MANUAL_GAS_PRICE) : null, @@ -95,16 +96,16 @@ export const loadConfig = () => { balancer_max_swaps: process.env.BALANCER_MAX_SWAPS != null ? parseInt(process.env.BALANCER_MAX_SWAPS) : null, uniswap_router: process.env.UNISWAP_ROUTER, terra_lcd_url: process.env.TERRA_LCD_URL, - terra_chain: process.env.TERRA_CHAIN - } - return config -} + terra_chain: process.env.TERRA_CHAIN, + }; + return config; +}; export const getLocalDate = () => { - const gmtOffset = process.env.GMT_OFFSET - let newDate = moment().format('YYYY-MM-DD hh:mm:ss').trim() + const gmtOffset = process.env.GMT_OFFSET; + let newDate = moment().format('YYYY-MM-DD hh:mm:ss').trim(); if (typeof gmtOffset !== 'undefined' && gmtOffset !== null && gmtOffset !== '') { - newDate = moment().utcOffset(gmtOffset, false).format('YYYY-MM-DD hh:mm:ss').trim() + newDate = moment().utcOffset(gmtOffset, false).format('YYYY-MM-DD hh:mm:ss').trim(); } - return newDate -} + return newDate; +}; diff --git a/yarn.lock b/yarn.lock index a3a5e0c..d7394f6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,401 +2,439 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" - integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== +"@babel/code-frame@7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== dependencies: "@babel/highlight" "^7.10.4" -"@babel/compat-data@^7.10.4", "@babel/compat-data@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.11.0.tgz#e9f73efe09af1355b723a7f39b11bad637d7c99c" - integrity sha512-TPSvJfv73ng0pfnEOh17bYMPQbI95+nGWc71Ss4vZdRBHTDqmM9Z8ZV4rYz8Ks7sfzc95n30k6ODIq5UGnXcYQ== +"@babel/code-frame@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" + integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== dependencies: - browserslist "^4.12.0" - invariant "^2.2.4" - semver "^5.5.0" + "@babel/highlight" "^7.12.13" + +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.4": + version "7.14.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.4.tgz#45720fe0cecf3fd42019e1d12cc3d27fadc98d58" + integrity sha512-i2wXrWQNkH6JplJQGn3Rd2I4Pij8GdHkXwHMxm+zV5YG/Jci+bCNrWZEWC4o+umiDkRrRs4dVzH3X4GP7vyjQQ== "@babel/core@^7.11.6": - version "7.11.6" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.6.tgz#3a9455dc7387ff1bac45770650bc13ba04a15651" - integrity sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.6" - "@babel/helper-module-transforms" "^7.11.0" - "@babel/helpers" "^7.10.4" - "@babel/parser" "^7.11.5" - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.11.5" - "@babel/types" "^7.11.5" + version "7.14.3" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.3.tgz#5395e30405f0776067fbd9cf0884f15bfb770a38" + integrity sha512-jB5AmTKOCSJIZ72sd78ECEhuPiDMKlQdDI/4QRI6lzYATx5SSogS1oQA2AoPecRCknm30gHi2l+QVvNUu3wZAg== + dependencies: + "@babel/code-frame" "^7.12.13" + "@babel/generator" "^7.14.3" + "@babel/helper-compilation-targets" "^7.13.16" + "@babel/helper-module-transforms" "^7.14.2" + "@babel/helpers" "^7.14.0" + "@babel/parser" "^7.14.3" + "@babel/template" "^7.12.13" + "@babel/traverse" "^7.14.2" + "@babel/types" "^7.14.2" convert-source-map "^1.7.0" debug "^4.1.0" - gensync "^1.0.0-beta.1" + gensync "^1.0.0-beta.2" json5 "^2.1.2" - lodash "^4.17.19" - resolve "^1.3.2" - semver "^5.4.1" + semver "^6.3.0" source-map "^0.5.0" -"@babel/generator@^7.11.5", "@babel/generator@^7.11.6": - version "7.11.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.6.tgz#b868900f81b163b4d464ea24545c61cbac4dc620" - integrity sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA== +"@babel/generator@^7.14.2", "@babel/generator@^7.14.3": + version "7.14.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.14.3.tgz#0c2652d91f7bddab7cccc6ba8157e4f40dcedb91" + integrity sha512-bn0S6flG/j0xtQdz3hsjJ624h3W0r3llttBMfyHX3YrZ/KtLYr15bjA0FXkgW7FpvrDuTuElXeVjiKlYRpnOFA== dependencies: - "@babel/types" "^7.11.5" + "@babel/types" "^7.14.2" jsesc "^2.5.1" source-map "^0.5.0" -"@babel/helper-annotate-as-pure@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" - integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3" - integrity sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-compilation-targets@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz#804ae8e3f04376607cc791b9d47d540276332bd2" - integrity sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ== - dependencies: - "@babel/compat-data" "^7.10.4" - browserslist "^4.12.0" - invariant "^2.2.4" - levenary "^1.1.1" - semver "^5.5.0" - -"@babel/helper-create-class-features-plugin@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz#9f61446ba80e8240b0a5c85c6fdac8459d6f259d" - integrity sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A== - dependencies: - "@babel/helper-function-name" "^7.10.4" - "@babel/helper-member-expression-to-functions" "^7.10.5" - "@babel/helper-optimise-call-expression" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-replace-supers" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.10.4" - -"@babel/helper-create-regexp-features-plugin@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8" - integrity sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g== +"@babel/helper-annotate-as-pure@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz#0f58e86dfc4bb3b1fcd7db806570e177d439b6ab" + integrity sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw== dependencies: - "@babel/helper-annotate-as-pure" "^7.10.4" - "@babel/helper-regex" "^7.10.4" - regexpu-core "^4.7.0" + "@babel/types" "^7.12.13" -"@babel/helper-define-map@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz#b53c10db78a640800152692b13393147acb9bb30" - integrity sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ== +"@babel/helper-builder-binary-assignment-operator-visitor@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz#6bc20361c88b0a74d05137a65cac8d3cbf6f61fc" + integrity sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA== dependencies: - "@babel/helper-function-name" "^7.10.4" - "@babel/types" "^7.10.5" - lodash "^4.17.19" + "@babel/helper-explode-assignable-expression" "^7.12.13" + "@babel/types" "^7.12.13" -"@babel/helper-explode-assignable-expression@^7.10.4": - version "7.11.4" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.11.4.tgz#2d8e3470252cc17aba917ede7803d4a7a276a41b" - integrity sha512-ux9hm3zR4WV1Y3xXxXkdG/0gxF9nvI0YVmKVhvK9AfMoaQkemL3sJpXw+Xbz65azo8qJiEz2XVDUpK3KYhH3ZQ== +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.16", "@babel/helper-compilation-targets@^7.14.4": + version "7.14.4" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.14.4.tgz#33ebd0ffc34248051ee2089350a929ab02f2a516" + integrity sha512-JgdzOYZ/qGaKTVkn5qEDV/SXAh8KcyUVkCoSWGN8T3bwrgd6m+/dJa2kVGi6RJYJgEYPBdZ84BZp9dUjNWkBaA== dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-function-name@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" - integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== - dependencies: - "@babel/helper-get-function-arity" "^7.10.4" - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-get-function-arity@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" - integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-hoist-variables@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e" - integrity sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-member-expression-to-functions@^7.10.4", "@babel/helper-member-expression-to-functions@^7.10.5": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df" - integrity sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q== - dependencies: - "@babel/types" "^7.11.0" - -"@babel/helper-module-imports@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" - integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-module-transforms@^7.10.4", "@babel/helper-module-transforms@^7.10.5", "@babel/helper-module-transforms@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359" - integrity sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg== - dependencies: - "@babel/helper-module-imports" "^7.10.4" - "@babel/helper-replace-supers" "^7.10.4" - "@babel/helper-simple-access" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/template" "^7.10.4" - "@babel/types" "^7.11.0" - lodash "^4.17.19" - -"@babel/helper-optimise-call-expression@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" - integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" - integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== - -"@babel/helper-regex@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0" - integrity sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg== - dependencies: - lodash "^4.17.19" - -"@babel/helper-remap-async-to-generator@^7.10.4": - version "7.11.4" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.11.4.tgz#4474ea9f7438f18575e30b0cac784045b402a12d" - integrity sha512-tR5vJ/vBa9wFy3m5LLv2faapJLnDFxNWff2SAYkSE4rLUdbp7CdObYFgI7wK4T/Mj4UzpjPwzR8Pzmr5m7MHGA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.10.4" - "@babel/helper-wrap-function" "^7.10.4" - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-replace-supers@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf" - integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.10.4" - "@babel/helper-optimise-call-expression" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-simple-access@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461" - integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw== - dependencies: - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-skip-transparent-expression-wrappers@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz#eec162f112c2f58d3af0af125e3bb57665146729" - integrity sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q== - dependencies: - "@babel/types" "^7.11.0" - -"@babel/helper-split-export-declaration@^7.10.4", "@babel/helper-split-export-declaration@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" - integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== - dependencies: - "@babel/types" "^7.11.0" - -"@babel/helper-validator-identifier@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" - integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== - -"@babel/helper-wrap-function@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87" - integrity sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug== - dependencies: - "@babel/helper-function-name" "^7.10.4" - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helpers@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044" - integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA== - dependencies: - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" + "@babel/compat-data" "^7.14.4" + "@babel/helper-validator-option" "^7.12.17" + browserslist "^4.16.6" + semver "^6.3.0" -"@babel/highlight@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" - integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== - dependencies: - "@babel/helper-validator-identifier" "^7.10.4" +"@babel/helper-create-class-features-plugin@^7.13.0", "@babel/helper-create-class-features-plugin@^7.14.0", "@babel/helper-create-class-features-plugin@^7.14.3": + version "7.14.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.14.4.tgz#abf888d836a441abee783c75229279748705dc42" + integrity sha512-idr3pthFlDCpV+p/rMgGLGYIVtazeatrSOQk8YzO2pAepIjQhCN3myeihVg58ax2bbbGK9PUE1reFi7axOYIOw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.12.13" + "@babel/helper-function-name" "^7.14.2" + "@babel/helper-member-expression-to-functions" "^7.13.12" + "@babel/helper-optimise-call-expression" "^7.12.13" + "@babel/helper-replace-supers" "^7.14.4" + "@babel/helper-split-export-declaration" "^7.12.13" + +"@babel/helper-create-regexp-features-plugin@^7.12.13": + version "7.14.3" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.3.tgz#149aa6d78c016e318c43e2409a0ae9c136a86688" + integrity sha512-JIB2+XJrb7v3zceV2XzDhGIB902CmKGSpSl4q2C6agU9SNLG/2V1RtFRGPG1Ajh9STj3+q6zJMOC+N/pp2P9DA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.12.13" + regexpu-core "^4.7.1" + +"@babel/helper-define-polyfill-provider@^0.2.2": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz#0525edec5094653a282688d34d846e4c75e9c0b6" + integrity sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew== + dependencies: + "@babel/helper-compilation-targets" "^7.13.0" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/traverse" "^7.13.0" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + +"@babel/helper-explode-assignable-expression@^7.12.13": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz#17b5c59ff473d9f956f40ef570cf3a76ca12657f" + integrity sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA== + dependencies: + "@babel/types" "^7.13.0" + +"@babel/helper-function-name@^7.12.13", "@babel/helper-function-name@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.14.2.tgz#397688b590760b6ef7725b5f0860c82427ebaac2" + integrity sha512-NYZlkZRydxw+YT56IlhIcS8PAhb+FEUiOzuhFTfqDyPmzAhRge6ua0dQYT/Uh0t/EDHq05/i+e5M2d4XvjgarQ== + dependencies: + "@babel/helper-get-function-arity" "^7.12.13" + "@babel/template" "^7.12.13" + "@babel/types" "^7.14.2" + +"@babel/helper-get-function-arity@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583" + integrity sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg== + dependencies: + "@babel/types" "^7.12.13" + +"@babel/helper-hoist-variables@^7.13.0": + version "7.13.16" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.16.tgz#1b1651249e94b51f8f0d33439843e33e39775b30" + integrity sha512-1eMtTrXtrwscjcAeO4BVK+vvkxaLJSPFz1w1KLawz6HLNi9bPFGBNwwDyVfiu1Tv/vRRFYfoGaKhmAQPGPn5Wg== + dependencies: + "@babel/traverse" "^7.13.15" + "@babel/types" "^7.13.16" + +"@babel/helper-member-expression-to-functions@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz#dfe368f26d426a07299d8d6513821768216e6d72" + integrity sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw== + dependencies: + "@babel/types" "^7.13.12" + +"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977" + integrity sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA== + dependencies: + "@babel/types" "^7.13.12" + +"@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.14.0", "@babel/helper-module-transforms@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.14.2.tgz#ac1cc30ee47b945e3e0c4db12fa0c5389509dfe5" + integrity sha512-OznJUda/soKXv0XhpvzGWDnml4Qnwp16GN+D/kZIdLsWoHj05kyu8Rm5kXmMef+rVJZ0+4pSGLkeixdqNUATDA== + dependencies: + "@babel/helper-module-imports" "^7.13.12" + "@babel/helper-replace-supers" "^7.13.12" + "@babel/helper-simple-access" "^7.13.12" + "@babel/helper-split-export-declaration" "^7.12.13" + "@babel/helper-validator-identifier" "^7.14.0" + "@babel/template" "^7.12.13" + "@babel/traverse" "^7.14.2" + "@babel/types" "^7.14.2" + +"@babel/helper-optimise-call-expression@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea" + integrity sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA== + dependencies: + "@babel/types" "^7.12.13" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af" + integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ== + +"@babel/helper-remap-async-to-generator@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz#376a760d9f7b4b2077a9dd05aa9c3927cadb2209" + integrity sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.12.13" + "@babel/helper-wrap-function" "^7.13.0" + "@babel/types" "^7.13.0" + +"@babel/helper-replace-supers@^7.12.13", "@babel/helper-replace-supers@^7.13.12", "@babel/helper-replace-supers@^7.14.4": + version "7.14.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.14.4.tgz#b2ab16875deecfff3ddfcd539bc315f72998d836" + integrity sha512-zZ7uHCWlxfEAAOVDYQpEf/uyi1dmeC7fX4nCf2iz9drnCwi1zvwXL3HwWWNXUQEJ1k23yVn3VbddiI9iJEXaTQ== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.13.12" + "@babel/helper-optimise-call-expression" "^7.12.13" + "@babel/traverse" "^7.14.2" + "@babel/types" "^7.14.4" + +"@babel/helper-simple-access@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz#dd6c538afb61819d205a012c31792a39c7a5eaf6" + integrity sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA== + dependencies: + "@babel/types" "^7.13.12" + +"@babel/helper-skip-transparent-expression-wrappers@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz#462dc63a7e435ade8468385c63d2b84cce4b3cbf" + integrity sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA== + dependencies: + "@babel/types" "^7.12.1" + +"@babel/helper-split-export-declaration@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz#e9430be00baf3e88b0e13e6f9d4eaf2136372b05" + integrity sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg== + dependencies: + "@babel/types" "^7.12.13" + +"@babel/helper-validator-identifier@^7.12.11", "@babel/helper-validator-identifier@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" + integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== + +"@babel/helper-validator-option@^7.12.17": + version "7.12.17" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" + integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw== + +"@babel/helper-wrap-function@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz#bdb5c66fda8526ec235ab894ad53a1235c79fcc4" + integrity sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA== + dependencies: + "@babel/helper-function-name" "^7.12.13" + "@babel/template" "^7.12.13" + "@babel/traverse" "^7.13.0" + "@babel/types" "^7.13.0" + +"@babel/helpers@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.14.0.tgz#ea9b6be9478a13d6f961dbb5f36bf75e2f3b8f62" + integrity sha512-+ufuXprtQ1D1iZTO/K9+EBRn+qPWMJjZSw/S0KlFrxCw4tkrzv9grgpDHkY9MeQTjTY8i2sp7Jep8DfU6tN9Mg== + dependencies: + "@babel/template" "^7.12.13" + "@babel/traverse" "^7.14.0" + "@babel/types" "^7.14.0" + +"@babel/highlight@^7.10.4", "@babel/highlight@^7.12.13": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.0.tgz#3197e375711ef6bf834e67d0daec88e4f46113cf" + integrity sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg== + dependencies: + "@babel/helper-validator-identifier" "^7.14.0" chalk "^2.0.0" js-tokens "^4.0.0" "@babel/node@^7.10.5": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/node/-/node-7.10.5.tgz#30866322aa2c0251a9bdd73d07a9167bd1f4ed64" - integrity sha512-suosS7zZ2roj+fYVCnDuVezUbRc0sdoyF0Gj/1FzWxD4ebbGiBGtL5qyqHH4NO34B5m4vWWYWgyNhSsrqS8vwA== + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/node/-/node-7.14.2.tgz#d860c10306020d18e3fd0327c63bfaf2dbfc7470" + integrity sha512-QB/C+Kl6gIYpTjZ/hcZj+chkiAVGcgSHuR849cdNvNJBz4VztO2775/o2ge8imB94EAsLcgkrdWH/3+UIVv1TA== dependencies: - "@babel/register" "^7.10.5" + "@babel/register" "^7.13.16" commander "^4.0.1" core-js "^3.2.1" - lodash "^4.17.19" node-environment-flags "^1.0.5" regenerator-runtime "^0.13.4" - resolve "^1.13.1" v8flags "^3.1.1" -"@babel/parser@^7.10.4", "@babel/parser@^7.11.5": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037" - integrity sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q== - -"@babel/plugin-proposal-async-generator-functions@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz#3491cabf2f7c179ab820606cec27fed15e0e8558" - integrity sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-remap-async-to-generator" "^7.10.4" - "@babel/plugin-syntax-async-generators" "^7.8.0" - -"@babel/plugin-proposal-class-properties@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807" - integrity sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-proposal-dynamic-import@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz#ba57a26cb98b37741e9d5bca1b8b0ddf8291f17e" - integrity sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" +"@babel/parser@^7.12.13", "@babel/parser@^7.14.2", "@babel/parser@^7.14.3": + version "7.14.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.4.tgz#a5c560d6db6cd8e6ed342368dea8039232cbab18" + integrity sha512-ArliyUsWDUqEGfWcmzpGUzNfLxTdTp6WU4IuP6QFSp9gGfWS6boxFCkJSJ/L4+RG8z/FnIU3WxCk6hPL9SSWeA== -"@babel/plugin-proposal-export-namespace-from@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz#570d883b91031637b3e2958eea3c438e62c05f54" - integrity sha512-aNdf0LY6/3WXkhh0Fdb6Zk9j1NMD8ovj3F6r0+3j837Pn1S1PdNtcwJ5EG9WkVPNHPxyJDaxMaAOVq4eki0qbg== +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.13.12": + version "7.13.12" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.13.12.tgz#a3484d84d0b549f3fc916b99ee4783f26fabad2a" + integrity sha512-d0u3zWKcoZf379fOeJdr1a5WPDny4aOFZ6hlfKivgK0LY7ZxNfoaHL2fWwdGtHyVvra38FC+HVYkO+byfSA8AQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" + "@babel/plugin-proposal-optional-chaining" "^7.13.12" -"@babel/plugin-proposal-json-strings@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz#593e59c63528160233bd321b1aebe0820c2341db" - integrity sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw== +"@babel/plugin-proposal-async-generator-functions@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.2.tgz#3a2085abbf5d5f962d480dbc81347385ed62eb1e" + integrity sha512-b1AM4F6fwck4N8ItZ/AtC4FP/cqZqmKRQ4FaTDutwSYyjuhtvsGEMLK4N/ztV/ImP40BjIDyMgBQAeAMsQYVFQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-remap-async-to-generator" "^7.13.0" + "@babel/plugin-syntax-async-generators" "^7.8.4" -"@babel/plugin-proposal-logical-assignment-operators@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.11.0.tgz#9f80e482c03083c87125dee10026b58527ea20c8" - integrity sha512-/f8p4z+Auz0Uaf+i8Ekf1iM7wUNLcViFUGiPxKeXvxTSl63B875YPiVdUDdem7hREcI0E0kSpEhS8tF5RphK7Q== +"@babel/plugin-proposal-class-properties@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz#146376000b94efd001e57a40a88a525afaab9f37" + integrity sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/helper-create-class-features-plugin" "^7.13.0" + "@babel/helper-plugin-utils" "^7.13.0" -"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz#02a7e961fc32e6d5b2db0649e01bf80ddee7e04a" - integrity sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw== +"@babel/plugin-proposal-class-static-block@^7.14.3": + version "7.14.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.14.3.tgz#5a527e2cae4a4753119c3a3e7f64ecae8ccf1360" + integrity sha512-HEjzp5q+lWSjAgJtSluFDrGGosmwTgKwCXdDQZvhKsRlwv3YdkUEqxNrrjesJd+B9E9zvr1PVPVBvhYZ9msjvQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/helper-create-class-features-plugin" "^7.14.3" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-class-static-block" "^7.12.13" -"@babel/plugin-proposal-numeric-separator@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz#ce1590ff0a65ad12970a609d78855e9a4c1aef06" - integrity sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA== +"@babel/plugin-proposal-dynamic-import@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.2.tgz#01ebabd7c381cff231fa43e302939a9de5be9d9f" + integrity sha512-oxVQZIWFh91vuNEMKltqNsKLFWkOIyJc95k2Gv9lWVyDfPUQGSSlbDEgWuJUU1afGE9WwlzpucMZ3yDRHIItkA== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" -"@babel/plugin-proposal-object-rest-spread@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz#bd81f95a1f746760ea43b6c2d3d62b11790ad0af" - integrity sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA== +"@babel/plugin-proposal-export-namespace-from@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.2.tgz#62542f94aa9ce8f6dba79eec698af22112253791" + integrity sha512-sRxW3z3Zp3pFfLAgVEvzTFutTXax837oOatUIvSG9o5gRj9mKwm3br1Se5f4QalTQs9x4AzlA/HrCWbQIHASUQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-transform-parameters" "^7.10.4" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" -"@babel/plugin-proposal-optional-catch-binding@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz#31c938309d24a78a49d68fdabffaa863758554dd" - integrity sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g== +"@babel/plugin-proposal-json-strings@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.2.tgz#830b4e2426a782e8b2878fbfe2cba85b70cbf98c" + integrity sha512-w2DtsfXBBJddJacXMBhElGEYqCZQqN99Se1qeYn8DVLB33owlrlLftIbMzn5nz1OITfDVknXF433tBrLEAOEjA== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-json-strings" "^7.8.3" -"@babel/plugin-proposal-optional-chaining@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz#de5866d0646f6afdaab8a566382fe3a221755076" - integrity sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA== +"@babel/plugin-proposal-logical-assignment-operators@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.2.tgz#222348c080a1678e0e74ea63fe76f275882d1fd7" + integrity sha512-1JAZtUrqYyGsS7IDmFeaem+/LJqujfLZ2weLR9ugB0ufUPjzf8cguyVT1g5im7f7RXxuLq1xUxEzvm68uYRtGg== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-skip-transparent-expression-wrappers" "^7.11.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-proposal-private-methods@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz#b160d972b8fdba5c7d111a145fc8c421fc2a6909" - integrity sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw== +"@babel/plugin-proposal-nullish-coalescing-operator@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.2.tgz#425b11dc62fc26939a2ab42cbba680bdf5734546" + integrity sha512-ebR0zU9OvI2N4qiAC38KIAK75KItpIPTpAtd2r4OZmMFeKbKJpUFLYP2EuDut82+BmYi8sz42B+TfTptJ9iG5Q== dependencies: - "@babel/helper-create-class-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" -"@babel/plugin-proposal-unicode-property-regex@^7.10.4", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz#4483cda53041ce3413b7fe2f00022665ddfaa75d" - integrity sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA== +"@babel/plugin-proposal-numeric-separator@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.2.tgz#82b4cc06571143faf50626104b335dd71baa4f9e" + integrity sha512-DcTQY9syxu9BpU3Uo94fjCB3LN9/hgPS8oUL7KrSW3bA2ePrKZZPJcc5y0hoJAM9dft3pGfErtEUvxXQcfLxUg== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-syntax-async-generators@^7.8.0": +"@babel/plugin-proposal-object-rest-spread@^7.14.4": + version "7.14.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.4.tgz#0e2b4de419915dc0b409378e829412e2031777c4" + integrity sha512-AYosOWBlyyXEagrPRfLJ1enStufsr7D1+ddpj8OLi9k7B6+NdZ0t/9V7Fh+wJ4g2Jol8z2JkgczYqtWrZd4vbA== + dependencies: + "@babel/compat-data" "^7.14.4" + "@babel/helper-compilation-targets" "^7.14.4" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.14.2" + +"@babel/plugin-proposal-optional-catch-binding@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.2.tgz#150d4e58e525b16a9a1431bd5326c4eed870d717" + integrity sha512-XtkJsmJtBaUbOxZsNk0Fvrv8eiqgneug0A6aqLFZ4TSkar2L5dSXWcnUKHgmjJt49pyB/6ZHvkr3dPgl9MOWRQ== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.13.12", "@babel/plugin-proposal-optional-chaining@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.2.tgz#df8171a8b9c43ebf4c1dabe6311b432d83e1b34e" + integrity sha512-qQByMRPwMZJainfig10BoaDldx/+VDtNcrA7qdNaEOAj6VXud+gfrkA8j4CRAU5HjnWREXqIpSpH30qZX1xivA== + dependencies: + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-proposal-private-methods@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.13.0.tgz#04bd4c6d40f6e6bbfa2f57e2d8094bad900ef787" + integrity sha512-MXyyKQd9inhx1kDYPkFRVOBXQ20ES8Pto3T7UZ92xj2mY0EVD8oAVzeyYuVfy/mxAdTSIayOvg+aVzcHV2bn6Q== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.13.0" + "@babel/helper-plugin-utils" "^7.13.0" + +"@babel/plugin-proposal-private-property-in-object@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.14.0.tgz#b1a1f2030586b9d3489cc26179d2eb5883277636" + integrity sha512-59ANdmEwwRUkLjB7CRtwJxxwtjESw+X2IePItA+RGQh+oy5RmpCh/EvVVvh5XQc3yxsm5gtv0+i9oBZhaDNVTg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.12.13" + "@babel/helper-create-class-features-plugin" "^7.14.0" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/plugin-syntax-private-property-in-object" "^7.14.0" + +"@babel/plugin-proposal-unicode-property-regex@^7.12.13", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz#bebde51339be829c17aaaaced18641deb62b39ba" + integrity sha512-XyJmZidNfofEkqFV5VC/bLabGmO5QzenPO/YOfGuEbgU+2sSwMmio3YLb4WtBgcmmdwZHyVyv8on77IUjQ5Gvg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.12.13" + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz#6644e6a0baa55a61f9e3231f6c9eeb6ee46c124c" - integrity sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA== +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.12.13.tgz#8e3d674b0613e67975ceac2776c97b60cafc5c9c" + integrity sha512-ZmKQ0ZXR0nYpHZIIuj9zE7oIqCx2hw9TKi+lIo73NNrMPAZGHfS92/VRV0ZmPj6H2ffBgyFHXvJ5NYsNeEaP2A== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-syntax-dynamic-import@^7.8.0": +"@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== @@ -410,7 +448,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-json-strings@^7.8.0": +"@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== @@ -424,7 +462,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== @@ -438,360 +476,369 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-object-rest-spread@^7.8.0": +"@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-optional-catch-binding@^7.8.0": +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-optional-chaining@^7.8.0": +"@babel/plugin-syntax-optional-chaining@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz#4bbeb8917b54fcf768364e0a81f560e33a3ef57d" - integrity sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ== +"@babel/plugin-syntax-private-property-in-object@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.0.tgz#762a4babec61176fec6c88480dec40372b140c0b" + integrity sha512-bda3xF8wGl5/5btF794utNOL0Jw+9jE5C1sLZcoK7c4uonE/y3iQiyG+KbkF3WBV/paX58VCpjhxLPkdj5Fe4w== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.13.0" -"@babel/plugin-transform-arrow-functions@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz#e22960d77e697c74f41c501d44d73dbf8a6a64cd" - integrity sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA== +"@babel/plugin-syntax-top-level-await@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz#c5f0fa6e249f5b739727f923540cf7a806130178" + integrity sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-async-to-generator@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz#41a5017e49eb6f3cda9392a51eef29405b245a37" - integrity sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ== +"@babel/plugin-transform-arrow-functions@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz#10a59bebad52d637a027afa692e8d5ceff5e3dae" + integrity sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg== dependencies: - "@babel/helper-module-imports" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-remap-async-to-generator" "^7.10.4" + "@babel/helper-plugin-utils" "^7.13.0" -"@babel/plugin-transform-block-scoped-functions@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz#1afa595744f75e43a91af73b0d998ecfe4ebc2e8" - integrity sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA== +"@babel/plugin-transform-async-to-generator@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz#8e112bf6771b82bf1e974e5e26806c5c99aa516f" + integrity sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-remap-async-to-generator" "^7.13.0" -"@babel/plugin-transform-block-scoping@^7.10.4": - version "7.11.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.11.1.tgz#5b7efe98852bef8d652c0b28144cd93a9e4b5215" - integrity sha512-00dYeDE0EVEHuuM+26+0w/SCL0BH2Qy7LwHuI4Hi4MH5gkC8/AqMN5uWFJIsoXZrAphiMm1iXzBw6L2T+eA0ew== +"@babel/plugin-transform-block-scoped-functions@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz#a9bf1836f2a39b4eb6cf09967739de29ea4bf4c4" + integrity sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-classes@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz#405136af2b3e218bc4a1926228bc917ab1a0adc7" - integrity sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA== +"@babel/plugin-transform-block-scoping@^7.14.4": + version "7.14.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.14.4.tgz#caf140b0b2e2462c509553d140e6d0abefb61ed8" + integrity sha512-5KdpkGxsZlTk+fPleDtGKsA+pon28+ptYmMO8GBSa5fHERCJWAzj50uAfCKBqq42HO+Zot6JF1x37CRprwmN4g== dependencies: - "@babel/helper-annotate-as-pure" "^7.10.4" - "@babel/helper-define-map" "^7.10.4" - "@babel/helper-function-name" "^7.10.4" - "@babel/helper-optimise-call-expression" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-replace-supers" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.10.4" + "@babel/helper-plugin-utils" "^7.13.0" + +"@babel/plugin-transform-classes@^7.14.4": + version "7.14.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.4.tgz#a83c15503fc71a0f99e876fdce7dadbc6575ec3a" + integrity sha512-p73t31SIj6y94RDVX57rafVjttNr8MvKEgs5YFatNB/xC68zM3pyosuOEcQmYsYlyQaGY9R7rAULVRcat5FKJQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.12.13" + "@babel/helper-function-name" "^7.14.2" + "@babel/helper-optimise-call-expression" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-replace-supers" "^7.14.4" + "@babel/helper-split-export-declaration" "^7.12.13" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz#9ded83a816e82ded28d52d4b4ecbdd810cdfc0eb" - integrity sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw== +"@babel/plugin-transform-computed-properties@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz#845c6e8b9bb55376b1fa0b92ef0bdc8ea06644ed" + integrity sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.13.0" -"@babel/plugin-transform-destructuring@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz#70ddd2b3d1bea83d01509e9bb25ddb3a74fc85e5" - integrity sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA== +"@babel/plugin-transform-destructuring@^7.14.4": + version "7.14.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.4.tgz#acbec502e9951f30f4441eaca1d2f29efade59ed" + integrity sha512-JyywKreTCGTUsL1OKu1A3ms/R1sTP0WxbpXlALeGzF53eB3bxtNkYdMj9SDgK7g6ImPy76J5oYYKoTtQImlhQA== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.13.0" -"@babel/plugin-transform-dotall-regex@^7.10.4", "@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz#469c2062105c1eb6a040eaf4fac4b488078395ee" - integrity sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA== +"@babel/plugin-transform-dotall-regex@^7.12.13", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz#3f1601cc29905bfcb67f53910f197aeafebb25ad" + integrity sha512-foDrozE65ZFdUC2OfgeOCrEPTxdB3yjqxpXh8CH+ipd9CHd4s/iq81kcUpyH8ACGNEPdFqbtzfgzbT/ZGlbDeQ== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-create-regexp-features-plugin" "^7.12.13" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-duplicate-keys@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz#697e50c9fee14380fe843d1f306b295617431e47" - integrity sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA== +"@babel/plugin-transform-duplicate-keys@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.13.tgz#6f06b87a8b803fd928e54b81c258f0a0033904de" + integrity sha512-NfADJiiHdhLBW3pulJlJI2NB0t4cci4WTZ8FtdIuNc2+8pslXdPtRRAEWqUY+m9kNOk2eRYbTAOipAxlrOcwwQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-exponentiation-operator@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz#5ae338c57f8cf4001bdb35607ae66b92d665af2e" - integrity sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw== +"@babel/plugin-transform-exponentiation-operator@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz#4d52390b9a273e651e4aba6aee49ef40e80cd0a1" + integrity sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.12.13" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-for-of@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz#c08892e8819d3a5db29031b115af511dbbfebae9" - integrity sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ== +"@babel/plugin-transform-for-of@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz#c799f881a8091ac26b54867a845c3e97d2696062" + integrity sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.13.0" -"@babel/plugin-transform-function-name@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz#6a467880e0fc9638514ba369111811ddbe2644b7" - integrity sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg== +"@babel/plugin-transform-function-name@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz#bb024452f9aaed861d374c8e7a24252ce3a50051" + integrity sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ== dependencies: - "@babel/helper-function-name" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-function-name" "^7.12.13" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-literals@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz#9f42ba0841100a135f22712d0e391c462f571f3c" - integrity sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ== +"@babel/plugin-transform-literals@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz#2ca45bafe4a820197cf315794a4d26560fe4bdb9" + integrity sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-member-expression-literals@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz#b1ec44fcf195afcb8db2c62cd8e551c881baf8b7" - integrity sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw== +"@babel/plugin-transform-member-expression-literals@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz#5ffa66cd59b9e191314c9f1f803b938e8c081e40" + integrity sha512-kxLkOsg8yir4YeEPHLuO2tXP9R/gTjpuTOjshqSpELUN3ZAg2jfDnKUvzzJxObun38sw3wm4Uu69sX/zA7iRvg== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-modules-amd@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz#1b9cddaf05d9e88b3aad339cb3e445c4f020a9b1" - integrity sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw== +"@babel/plugin-transform-modules-amd@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.2.tgz#6622806fe1a7c07a1388444222ef9535f2ca17b0" + integrity sha512-hPC6XBswt8P3G2D1tSV2HzdKvkqOpmbyoy+g73JG0qlF/qx2y3KaMmXb1fLrpmWGLZYA0ojCvaHdzFWjlmV+Pw== dependencies: - "@babel/helper-module-transforms" "^7.10.5" - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-module-transforms" "^7.14.2" + "@babel/helper-plugin-utils" "^7.13.0" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-commonjs@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz#66667c3eeda1ebf7896d41f1f16b17105a2fbca0" - integrity sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w== +"@babel/plugin-transform-modules-commonjs@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.14.0.tgz#52bc199cb581e0992edba0f0f80356467587f161" + integrity sha512-EX4QePlsTaRZQmw9BsoPeyh5OCtRGIhwfLquhxGp5e32w+dyL8htOcDwamlitmNFK6xBZYlygjdye9dbd9rUlQ== dependencies: - "@babel/helper-module-transforms" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-simple-access" "^7.10.4" + "@babel/helper-module-transforms" "^7.14.0" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-simple-access" "^7.13.12" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-systemjs@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz#6270099c854066681bae9e05f87e1b9cadbe8c85" - integrity sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw== +"@babel/plugin-transform-modules-systemjs@^7.13.8": + version "7.13.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.13.8.tgz#6d066ee2bff3c7b3d60bf28dec169ad993831ae3" + integrity sha512-hwqctPYjhM6cWvVIlOIe27jCIBgHCsdH2xCJVAYQm7V5yTMoilbVMi9f6wKg0rpQAOn6ZG4AOyvCqFF/hUh6+A== dependencies: - "@babel/helper-hoist-variables" "^7.10.4" - "@babel/helper-module-transforms" "^7.10.5" - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-hoist-variables" "^7.13.0" + "@babel/helper-module-transforms" "^7.13.0" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-validator-identifier" "^7.12.11" babel-plugin-dynamic-import-node "^2.3.3" -"@babel/plugin-transform-modules-umd@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz#9a8481fe81b824654b3a0b65da3df89f3d21839e" - integrity sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA== +"@babel/plugin-transform-modules-umd@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.0.tgz#2f8179d1bbc9263665ce4a65f305526b2ea8ac34" + integrity sha512-nPZdnWtXXeY7I87UZr9VlsWme3Y0cfFFE41Wbxz4bbaexAjNMInXPFUpRRUJ8NoMm0Cw+zxbqjdPmLhcjfazMw== dependencies: - "@babel/helper-module-transforms" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-module-transforms" "^7.14.0" + "@babel/helper-plugin-utils" "^7.13.0" -"@babel/plugin-transform-named-capturing-groups-regex@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz#78b4d978810b6f3bcf03f9e318f2fc0ed41aecb6" - integrity sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA== +"@babel/plugin-transform-named-capturing-groups-regex@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.13.tgz#2213725a5f5bbbe364b50c3ba5998c9599c5c9d9" + integrity sha512-Xsm8P2hr5hAxyYblrfACXpQKdQbx4m2df9/ZZSQ8MAhsadw06+jW7s9zsSw6he+mJZXRlVMyEnVktJo4zjk1WA== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.4" + "@babel/helper-create-regexp-features-plugin" "^7.12.13" -"@babel/plugin-transform-new-target@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz#9097d753cb7b024cb7381a3b2e52e9513a9c6888" - integrity sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw== +"@babel/plugin-transform-new-target@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.13.tgz#e22d8c3af24b150dd528cbd6e685e799bf1c351c" + integrity sha512-/KY2hbLxrG5GTQ9zzZSc3xWiOy379pIETEhbtzwZcw9rvuaVV4Fqy7BYGYOWZnaoXIQYbbJ0ziXLa/sKcGCYEQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-object-super@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz#d7146c4d139433e7a6526f888c667e314a093894" - integrity sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ== +"@babel/plugin-transform-object-super@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz#b4416a2d63b8f7be314f3d349bd55a9c1b5171f7" + integrity sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-replace-supers" "^7.10.4" + "@babel/helper-plugin-utils" "^7.12.13" + "@babel/helper-replace-supers" "^7.12.13" -"@babel/plugin-transform-parameters@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz#59d339d58d0b1950435f4043e74e2510005e2c4a" - integrity sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw== +"@babel/plugin-transform-parameters@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.2.tgz#e4290f72e0e9e831000d066427c4667098decc31" + integrity sha512-NxoVmA3APNCC1JdMXkdYXuQS+EMdqy0vIwyDHeKHiJKRxmp1qGSdb0JLEIoPRhkx6H/8Qi3RJ3uqOCYw8giy9A== dependencies: - "@babel/helper-get-function-arity" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.13.0" -"@babel/plugin-transform-property-literals@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz#f6fe54b6590352298785b83edd815d214c42e3c0" - integrity sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g== +"@babel/plugin-transform-property-literals@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz#4e6a9e37864d8f1b3bc0e2dce7bf8857db8b1a81" + integrity sha512-nqVigwVan+lR+g8Fj8Exl0UQX2kymtjcWfMOYM1vTYEKujeyv2SkMgazf2qNcK7l4SDiKyTA/nHCPqL4e2zo1A== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-regenerator@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63" - integrity sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw== +"@babel/plugin-transform-regenerator@^7.13.15": + version "7.13.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.13.15.tgz#e5eb28945bf8b6563e7f818945f966a8d2997f39" + integrity sha512-Bk9cOLSz8DiurcMETZ8E2YtIVJbFCPGW28DJWUakmyVWtQSm6Wsf0p4B4BfEr/eL2Nkhe/CICiUiMOCi1TPhuQ== dependencies: regenerator-transform "^0.14.2" -"@babel/plugin-transform-reserved-words@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz#8f2682bcdcef9ed327e1b0861585d7013f8a54dd" - integrity sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ== +"@babel/plugin-transform-reserved-words@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.13.tgz#7d9988d4f06e0fe697ea1d9803188aa18b472695" + integrity sha512-xhUPzDXxZN1QfiOy/I5tyye+TRz6lA7z6xaT4CLOjPRMVg1ldRf0LHw0TDBpYL4vG78556WuHdyO9oi5UmzZBg== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-shorthand-properties@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz#9fd25ec5cdd555bb7f473e5e6ee1c971eede4dd6" - integrity sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q== +"@babel/plugin-transform-shorthand-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz#db755732b70c539d504c6390d9ce90fe64aff7ad" + integrity sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-spread@^7.11.0": - version "7.11.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz#fa84d300f5e4f57752fe41a6d1b3c554f13f17cc" - integrity sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw== +"@babel/plugin-transform-spread@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz#84887710e273c1815ace7ae459f6f42a5d31d5fd" + integrity sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-skip-transparent-expression-wrappers" "^7.11.0" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" -"@babel/plugin-transform-sticky-regex@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz#8f3889ee8657581130a29d9cc91d7c73b7c4a28d" - integrity sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ== +"@babel/plugin-transform-sticky-regex@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz#760ffd936face73f860ae646fb86ee82f3d06d1f" + integrity sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/helper-regex" "^7.10.4" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-template-literals@^7.10.4": - version "7.10.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz#78bc5d626a6642db3312d9d0f001f5e7639fde8c" - integrity sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw== +"@babel/plugin-transform-template-literals@^7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz#a36049127977ad94438dee7443598d1cefdf409d" + integrity sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw== dependencies: - "@babel/helper-annotate-as-pure" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.13.0" -"@babel/plugin-transform-typeof-symbol@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz#9509f1a7eec31c4edbffe137c16cc33ff0bc5bfc" - integrity sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA== +"@babel/plugin-transform-typeof-symbol@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz#785dd67a1f2ea579d9c2be722de8c84cb85f5a7f" + integrity sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-unicode-escapes@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz#feae523391c7651ddac115dae0a9d06857892007" - integrity sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg== +"@babel/plugin-transform-unicode-escapes@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz#840ced3b816d3b5127dd1d12dcedc5dead1a5e74" + integrity sha512-0bHEkdwJ/sN/ikBHfSmOXPypN/beiGqjo+o4/5K+vxEFNPRPdImhviPakMKG4x96l85emoa0Z6cDflsdBusZbw== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/plugin-transform-unicode-regex@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz#e56d71f9282fac6db09c82742055576d5e6d80a8" - integrity sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A== +"@babel/plugin-transform-unicode-regex@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz#b52521685804e155b1202e83fc188d34bb70f5ac" + integrity sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-create-regexp-features-plugin" "^7.12.13" + "@babel/helper-plugin-utils" "^7.12.13" "@babel/preset-env@^7.11.5": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.11.5.tgz#18cb4b9379e3e92ffea92c07471a99a2914e4272" - integrity sha512-kXqmW1jVcnB2cdueV+fyBM8estd5mlNfaQi6lwLgRwCby4edpavgbFhiBNjmWA3JpB/yZGSISa7Srf+TwxDQoA== - dependencies: - "@babel/compat-data" "^7.11.0" - "@babel/helper-compilation-targets" "^7.10.4" - "@babel/helper-module-imports" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - "@babel/plugin-proposal-async-generator-functions" "^7.10.4" - "@babel/plugin-proposal-class-properties" "^7.10.4" - "@babel/plugin-proposal-dynamic-import" "^7.10.4" - "@babel/plugin-proposal-export-namespace-from" "^7.10.4" - "@babel/plugin-proposal-json-strings" "^7.10.4" - "@babel/plugin-proposal-logical-assignment-operators" "^7.11.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.4" - "@babel/plugin-proposal-numeric-separator" "^7.10.4" - "@babel/plugin-proposal-object-rest-spread" "^7.11.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.10.4" - "@babel/plugin-proposal-optional-chaining" "^7.11.0" - "@babel/plugin-proposal-private-methods" "^7.10.4" - "@babel/plugin-proposal-unicode-property-regex" "^7.10.4" - "@babel/plugin-syntax-async-generators" "^7.8.0" - "@babel/plugin-syntax-class-properties" "^7.10.4" - "@babel/plugin-syntax-dynamic-import" "^7.8.0" + version "7.14.4" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.14.4.tgz#73fc3228c59727e5e974319156f304f0d6685a2d" + integrity sha512-GwMMsuAnDtULyOtuxHhzzuSRxFeP0aR/LNzrHRzP8y6AgDNgqnrfCCBm/1cRdTU75tRs28Eh76poHLcg9VF0LA== + dependencies: + "@babel/compat-data" "^7.14.4" + "@babel/helper-compilation-targets" "^7.14.4" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/helper-validator-option" "^7.12.17" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.13.12" + "@babel/plugin-proposal-async-generator-functions" "^7.14.2" + "@babel/plugin-proposal-class-properties" "^7.13.0" + "@babel/plugin-proposal-class-static-block" "^7.14.3" + "@babel/plugin-proposal-dynamic-import" "^7.14.2" + "@babel/plugin-proposal-export-namespace-from" "^7.14.2" + "@babel/plugin-proposal-json-strings" "^7.14.2" + "@babel/plugin-proposal-logical-assignment-operators" "^7.14.2" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.14.2" + "@babel/plugin-proposal-numeric-separator" "^7.14.2" + "@babel/plugin-proposal-object-rest-spread" "^7.14.4" + "@babel/plugin-proposal-optional-catch-binding" "^7.14.2" + "@babel/plugin-proposal-optional-chaining" "^7.14.2" + "@babel/plugin-proposal-private-methods" "^7.13.0" + "@babel/plugin-proposal-private-property-in-object" "^7.14.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.12.13" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.12.13" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-syntax-json-strings" "^7.8.3" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.0" - "@babel/plugin-syntax-top-level-await" "^7.10.4" - "@babel/plugin-transform-arrow-functions" "^7.10.4" - "@babel/plugin-transform-async-to-generator" "^7.10.4" - "@babel/plugin-transform-block-scoped-functions" "^7.10.4" - "@babel/plugin-transform-block-scoping" "^7.10.4" - "@babel/plugin-transform-classes" "^7.10.4" - "@babel/plugin-transform-computed-properties" "^7.10.4" - "@babel/plugin-transform-destructuring" "^7.10.4" - "@babel/plugin-transform-dotall-regex" "^7.10.4" - "@babel/plugin-transform-duplicate-keys" "^7.10.4" - "@babel/plugin-transform-exponentiation-operator" "^7.10.4" - "@babel/plugin-transform-for-of" "^7.10.4" - "@babel/plugin-transform-function-name" "^7.10.4" - "@babel/plugin-transform-literals" "^7.10.4" - "@babel/plugin-transform-member-expression-literals" "^7.10.4" - "@babel/plugin-transform-modules-amd" "^7.10.4" - "@babel/plugin-transform-modules-commonjs" "^7.10.4" - "@babel/plugin-transform-modules-systemjs" "^7.10.4" - "@babel/plugin-transform-modules-umd" "^7.10.4" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.10.4" - "@babel/plugin-transform-new-target" "^7.10.4" - "@babel/plugin-transform-object-super" "^7.10.4" - "@babel/plugin-transform-parameters" "^7.10.4" - "@babel/plugin-transform-property-literals" "^7.10.4" - "@babel/plugin-transform-regenerator" "^7.10.4" - "@babel/plugin-transform-reserved-words" "^7.10.4" - "@babel/plugin-transform-shorthand-properties" "^7.10.4" - "@babel/plugin-transform-spread" "^7.11.0" - "@babel/plugin-transform-sticky-regex" "^7.10.4" - "@babel/plugin-transform-template-literals" "^7.10.4" - "@babel/plugin-transform-typeof-symbol" "^7.10.4" - "@babel/plugin-transform-unicode-escapes" "^7.10.4" - "@babel/plugin-transform-unicode-regex" "^7.10.4" - "@babel/preset-modules" "^0.1.3" - "@babel/types" "^7.11.5" - browserslist "^4.12.0" - core-js-compat "^3.6.2" - invariant "^2.2.2" - levenary "^1.1.1" - semver "^5.5.0" - -"@babel/preset-modules@^0.1.3": + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.0" + "@babel/plugin-syntax-top-level-await" "^7.12.13" + "@babel/plugin-transform-arrow-functions" "^7.13.0" + "@babel/plugin-transform-async-to-generator" "^7.13.0" + "@babel/plugin-transform-block-scoped-functions" "^7.12.13" + "@babel/plugin-transform-block-scoping" "^7.14.4" + "@babel/plugin-transform-classes" "^7.14.4" + "@babel/plugin-transform-computed-properties" "^7.13.0" + "@babel/plugin-transform-destructuring" "^7.14.4" + "@babel/plugin-transform-dotall-regex" "^7.12.13" + "@babel/plugin-transform-duplicate-keys" "^7.12.13" + "@babel/plugin-transform-exponentiation-operator" "^7.12.13" + "@babel/plugin-transform-for-of" "^7.13.0" + "@babel/plugin-transform-function-name" "^7.12.13" + "@babel/plugin-transform-literals" "^7.12.13" + "@babel/plugin-transform-member-expression-literals" "^7.12.13" + "@babel/plugin-transform-modules-amd" "^7.14.2" + "@babel/plugin-transform-modules-commonjs" "^7.14.0" + "@babel/plugin-transform-modules-systemjs" "^7.13.8" + "@babel/plugin-transform-modules-umd" "^7.14.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.12.13" + "@babel/plugin-transform-new-target" "^7.12.13" + "@babel/plugin-transform-object-super" "^7.12.13" + "@babel/plugin-transform-parameters" "^7.14.2" + "@babel/plugin-transform-property-literals" "^7.12.13" + "@babel/plugin-transform-regenerator" "^7.13.15" + "@babel/plugin-transform-reserved-words" "^7.12.13" + "@babel/plugin-transform-shorthand-properties" "^7.12.13" + "@babel/plugin-transform-spread" "^7.13.0" + "@babel/plugin-transform-sticky-regex" "^7.12.13" + "@babel/plugin-transform-template-literals" "^7.13.0" + "@babel/plugin-transform-typeof-symbol" "^7.12.13" + "@babel/plugin-transform-unicode-escapes" "^7.12.13" + "@babel/plugin-transform-unicode-regex" "^7.12.13" + "@babel/preset-modules" "^0.1.4" + "@babel/types" "^7.14.4" + babel-plugin-polyfill-corejs2 "^0.2.0" + babel-plugin-polyfill-corejs3 "^0.2.0" + babel-plugin-polyfill-regenerator "^0.2.0" + core-js-compat "^3.9.0" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.4": version "0.1.4" resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg== @@ -802,55 +849,53 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" -"@babel/register@^7.10.5": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.11.5.tgz#79becf89e0ddd0fba8b92bc279bc0f5d2d7ce2ea" - integrity sha512-CAml0ioKX+kOAvBQDHa/+t1fgOt3qkTIz0TrRtRAT6XY0m5qYZXR85k6/sLCNPMGhYDlCFHCYuU0ybTJbvlC6w== +"@babel/register@^7.13.16": + version "7.13.16" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.13.16.tgz#ae3ab0b55c8ec28763877383c454f01521d9a53d" + integrity sha512-dh2t11ysujTwByQjXNgJ48QZ2zcXKQVdV8s0TbeMI0flmtGWCdTwK9tJiACHXPLmncm5+ktNn/diojA45JE4jg== dependencies: + clone-deep "^4.0.1" find-cache-dir "^2.0.0" - lodash "^4.17.19" make-dir "^2.1.0" pirates "^4.0.0" source-map-support "^0.5.16" -"@babel/runtime@^7.8.4": - version "7.11.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" - integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== +"@babel/runtime@^7.14.0", "@babel/runtime@^7.8.4": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.14.0.tgz#46794bc20b612c5f75e62dd071e24dfd95f1cbe6" + integrity sha512-JELkvo/DlpNdJ7dlyw/eY7E0suy5i5GQH+Vlxaq1nsNJ+H7f4Vtv3jMeCEgRhZZQFXTjldYfQgv2qmM6M1v5wA== dependencies: regenerator-runtime "^0.13.4" -"@babel/template@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" - integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/parser" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/traverse@^7.10.4", "@babel/traverse@^7.11.5": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.5.tgz#be777b93b518eb6d76ee2e1ea1d143daa11e61c3" - integrity sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.5" - "@babel/helper-function-name" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/parser" "^7.11.5" - "@babel/types" "^7.11.5" +"@babel/template@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327" + integrity sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA== + dependencies: + "@babel/code-frame" "^7.12.13" + "@babel/parser" "^7.12.13" + "@babel/types" "^7.12.13" + +"@babel/traverse@^7.13.0", "@babel/traverse@^7.13.15", "@babel/traverse@^7.14.0", "@babel/traverse@^7.14.2": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.2.tgz#9201a8d912723a831c2679c7ebbf2fe1416d765b" + integrity sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA== + dependencies: + "@babel/code-frame" "^7.12.13" + "@babel/generator" "^7.14.2" + "@babel/helper-function-name" "^7.14.2" + "@babel/helper-split-export-declaration" "^7.12.13" + "@babel/parser" "^7.14.2" + "@babel/types" "^7.14.2" debug "^4.1.0" globals "^11.1.0" - lodash "^4.17.19" -"@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.11.5", "@babel/types@^7.4.4": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d" - integrity sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q== +"@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.16", "@babel/types@^7.14.0", "@babel/types@^7.14.2", "@babel/types@^7.14.4", "@babel/types@^7.4.4": + version "7.14.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.4.tgz#bfd6980108168593b38b3eb48a24aa026b919bc0" + integrity sha512-lCj4aIs0xUefJFQnwwQv2Bxg7Omd6bgquZ6LGC+gGMh6/s5qDVfjuCMlDmYQ15SLsWHd9n+X3E75lKIhl5Lkiw== dependencies: - "@babel/helper-validator-identifier" "^7.10.4" - lodash "^4.17.19" + "@babel/helper-validator-identifier" "^7.14.0" to-fast-properties "^2.0.0" "@balancer-labs/sor@^0.3.3": @@ -870,10 +915,10 @@ enabled "2.0.x" kuler "^2.0.0" -"@eslint/eslintrc@^0.1.3": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.1.3.tgz#7d1a2b2358552cc04834c0979bd4275362e37085" - integrity sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA== +"@eslint/eslintrc@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.1.tgz#442763b88cecbe3ee0ec7ca6d6dd6168550cbf14" + integrity sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ== dependencies: ajv "^6.12.4" debug "^4.1.1" @@ -882,347 +927,352 @@ ignore "^4.0.6" import-fresh "^3.2.1" js-yaml "^3.13.1" - lodash "^4.17.19" minimatch "^3.0.4" strip-json-comments "^3.1.1" -"@ethersproject/abi@^5.0.5": - version "5.0.5" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.5.tgz#6e7bbf9d014791334233ba18da85331327354aa1" - integrity sha512-FNx6UMm0LnmCMFzN3urohFwZpjbUHPvc/O60h4qkF4yiJxLJ/G7QOSPjkHQ/q/QibagR4S7OKQawRy0NcvWa9w== - dependencies: - "@ethersproject/address" "^5.0.4" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/constants" "^5.0.4" - "@ethersproject/hash" "^5.0.4" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/strings" "^5.0.4" - -"@ethersproject/abstract-provider@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.0.4.tgz#ef12df8cb5e66d0d47b567ad6ed642d682043773" - integrity sha512-EOCHUTS8jOE3WZlA1pq9b/vQwKDyDzMy4gXeAv0wZecH1kwUkD0++x8avxeSYoWI+aJn62P1FVV9B6r9pM56kQ== - dependencies: - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/networks" "^5.0.3" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/transactions" "^5.0.5" - "@ethersproject/web" "^5.0.6" - -"@ethersproject/abstract-signer@^5.0.4": - version "5.0.5" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.0.5.tgz#d1cdea6b0b82fb8e4a83f6899ba84d3dc3bb6e66" - integrity sha512-nwSZKtCTKhJADlW42c+a//lWxQlnA7jYLTnabJ3YCfgGU6ic9jnT9nRDlAyT1U3kCMeqPL7fTcKbdWCVrM0xsw== - dependencies: - "@ethersproject/abstract-provider" "^5.0.4" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - -"@ethersproject/address@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.0.4.tgz#8669bcbd02f4b64f4cede0a10e84df6d964ec9d3" - integrity sha512-CIjAeG6zNehbpJTi0sgwUvaH2ZICiAV9XkCBaFy5tjuEVFpQNeqd6f+B7RowcNO7Eut+QbhcQ5CVLkmP5zhL9A== - dependencies: - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/rlp" "^5.0.3" - bn.js "^4.4.0" - -"@ethersproject/base64@^5.0.3": - version "5.0.3" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.0.3.tgz#d0aaa32c9ab08e2d62a6238581607ab6e929297e" - integrity sha512-sFq+/UwGCQsLxMvp7yO7yGWni87QXoV3C3IfjqUSY2BHkbZbCDm+PxZviUkiKf+edYZ2Glp0XnY7CgKSYUN9qw== - dependencies: - "@ethersproject/bytes" "^5.0.4" - -"@ethersproject/basex@^5.0.3": - version "5.0.3" - resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.0.3.tgz#f8c9bc449a089131f52cfa8698cf77bc22e27e32" - integrity sha512-EvoER+OXsMAZlvbC0M/9UTxjvbBvTccYCI+uCAhXw+eS1+SUdD4v7ekAFpVX78rPLrLZB1vChKMm6vPHIu3WRA== - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/properties" "^5.0.3" - -"@ethersproject/bignumber@^5.0.7": - version "5.0.7" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.0.7.tgz#720b3e3df3e125a99669ee869478106d0afe7b76" - integrity sha512-wwKgDJ+KA7IpgJwc8Fc0AjKIRuDskKA2cque29/+SgII9/1K/38JpqVNPKIovkLwTC2DDofIyzHcxeaKpMFouQ== - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - bn.js "^4.4.0" - -"@ethersproject/bytes@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.0.4.tgz#328d9d929a3e970964ecf5d62e12568a187189f1" - integrity sha512-9R6A6l9JN8x1U4s1dJCR+9h3MZTT3xQofr/Xx8wbDvj6NnY4CbBB0o8ZgHXvR74yV90pY2EzCekpkMBJnRzkSw== - dependencies: - "@ethersproject/logger" "^5.0.5" - -"@ethersproject/constants@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.0.4.tgz#9ddaa5f3c738a94e5adc4b3f71b36206fa5cdf88" - integrity sha512-Df32lcXDHPgZRPgp1dgmByNbNe4Ki1QoXR+wU61on5nggQGTqWR1Bb7pp9VtI5Go9kyE/JflFc4Te6o9MvYt8A== - dependencies: - "@ethersproject/bignumber" "^5.0.7" - -"@ethersproject/contracts@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.0.4.tgz#27a2d7e3a7eef9bd8d006824ac2a74157b523988" - integrity sha512-gfOZNgLiO9e1D/hmQ4sEyqoolw6jDFVfqirGJv3zyFKNyX+lAXLN7YAZnnWVmp4GU1jiMtSqQKjpWp7r6ihs3Q== - dependencies: - "@ethersproject/abi" "^5.0.5" - "@ethersproject/abstract-provider" "^5.0.4" - "@ethersproject/abstract-signer" "^5.0.4" - "@ethersproject/address" "^5.0.4" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/constants" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - -"@ethersproject/hash@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.0.4.tgz#385642786405d236f3d2f1acdfaf250ab519cdac" - integrity sha512-VCs/bFBU8AQFhHcT1cQH6x7a4zjulR6fJmAOcPxUgrN7bxOQ7QkpBKF+YCDJhFtkLdaljIsr/r831TuWU4Ysfg== - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/strings" "^5.0.4" - -"@ethersproject/hdnode@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.0.4.tgz#9c07a87781b24b9cae3507fe9404361c5870f1b7" - integrity sha512-eHmpNLvasfB4xbmQUvKXOsGF4ekjIKJH/eZm7fc6nIdMci9u5ERooSSRLjs9Dsa5QuJf6YD4DbqeJsT71n47iw== - dependencies: - "@ethersproject/abstract-signer" "^5.0.4" - "@ethersproject/basex" "^5.0.3" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/pbkdf2" "^5.0.3" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/sha2" "^5.0.3" - "@ethersproject/signing-key" "^5.0.4" - "@ethersproject/strings" "^5.0.4" - "@ethersproject/transactions" "^5.0.5" - "@ethersproject/wordlists" "^5.0.4" - -"@ethersproject/json-wallets@^5.0.6": - version "5.0.6" - resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.0.6.tgz#c6c1818dcab18ecf3f37fa59ca504b9bc162d559" - integrity sha512-BPCfyGdwOUSp6+xA59IaZ/2pUWrUOL5Z9HuCh8YLsJzkuyBJQN0j+z/PmhIiZ7X8ilhuE+pRUwXb42U/R39fig== - dependencies: - "@ethersproject/abstract-signer" "^5.0.4" - "@ethersproject/address" "^5.0.4" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/hdnode" "^5.0.4" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/pbkdf2" "^5.0.3" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/random" "^5.0.3" - "@ethersproject/strings" "^5.0.4" - "@ethersproject/transactions" "^5.0.5" +"@ethersproject/abi@5.3.0", "@ethersproject/abi@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.3.0.tgz#00f0647d906edcd32c50b16ab9c98f83e208dcf1" + integrity sha512-NaT4UacjOwca8qCG/gv8k+DgTcWu49xlrvdhr/p8PTFnoS8e3aMWqjI3znFME5Txa/QWXDrg2/heufIUue9rtw== + dependencies: + "@ethersproject/address" "^5.3.0" + "@ethersproject/bignumber" "^5.3.0" + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/constants" "^5.3.0" + "@ethersproject/hash" "^5.3.0" + "@ethersproject/keccak256" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + "@ethersproject/properties" "^5.3.0" + "@ethersproject/strings" "^5.3.0" + +"@ethersproject/abstract-provider@5.3.0", "@ethersproject/abstract-provider@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.3.0.tgz#f4c0ae4a4cef9f204d7781de805fd44b72756c81" + integrity sha512-1+MLhGP1GwxBDBNwMWVmhCsvKwh4gK7oIfOrmlmePNeskg1NhIrYssraJBieaFNHUYfKEd/1DjiVZMw8Qu5Cxw== + dependencies: + "@ethersproject/bignumber" "^5.3.0" + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + "@ethersproject/networks" "^5.3.0" + "@ethersproject/properties" "^5.3.0" + "@ethersproject/transactions" "^5.3.0" + "@ethersproject/web" "^5.3.0" + +"@ethersproject/abstract-signer@5.3.0", "@ethersproject/abstract-signer@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.3.0.tgz#05172b653e15b535ed5854ef5f6a72f4b441052d" + integrity sha512-w8IFwOYqiPrtvosPuArZ3+QPR2nmdVTRrVY8uJYL3NNfMmQfTy3V3l2wbzX47UUlNbPJY+gKvzJAyvK1onZxJg== + dependencies: + "@ethersproject/abstract-provider" "^5.3.0" + "@ethersproject/bignumber" "^5.3.0" + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + "@ethersproject/properties" "^5.3.0" + +"@ethersproject/address@5.3.0", "@ethersproject/address@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.3.0.tgz#e53b69eacebf332e8175de814c5e6507d6932518" + integrity sha512-29TgjzEBK+gUEUAOfWCG7s9IxLNLCqvr+oDSk6L9TXD0VLvZJKhJV479tKQqheVA81OeGxfpdxYtUVH8hqlCvA== + dependencies: + "@ethersproject/bignumber" "^5.3.0" + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/keccak256" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + "@ethersproject/rlp" "^5.3.0" + +"@ethersproject/base64@5.3.0", "@ethersproject/base64@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.3.0.tgz#b831fb35418b42ad24d943c557259062b8640824" + integrity sha512-JIqgtOmgKcbc2sjGWTXyXktqUhvFUDte8fPVsAaOrcPiJf6YotNF+nsrOYGC9pbHBEGSuSBp3QR0varkO8JHEw== + dependencies: + "@ethersproject/bytes" "^5.3.0" + +"@ethersproject/basex@5.3.0", "@ethersproject/basex@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.3.0.tgz#02dea3ab8559ae625c6d548bc11773432255c916" + integrity sha512-8J4nS6t/SOnoCgr3DF5WCSRLC5YwTKYpZWJqeyYQLX+86TwPhtzvHXacODzcDII9tWKhVg6g0Bka8JCBWXsCiQ== + dependencies: + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/properties" "^5.3.0" + +"@ethersproject/bignumber@5.3.0", "@ethersproject/bignumber@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.3.0.tgz#74ab2ec9c3bda4e344920565720a6ee9c794e9db" + integrity sha512-5xguJ+Q1/zRMgHgDCaqAexx/8DwDVLRemw2i6uR8KyGjwGdXI8f32QZZ1cKGucBN6ekJvpUpHy6XAuQnTv0mPA== + dependencies: + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + bn.js "^4.11.9" + +"@ethersproject/bytes@5.3.0", "@ethersproject/bytes@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.3.0.tgz#473e0da7f831d535b2002be05e6f4ca3729a1bc9" + integrity sha512-rqLJjdVqCcn7glPer7Fxh87PRqlnRScVAoxcIP3PmOUNApMWJ6yRdOFfo2KvPAdO7Le3yEI1o0YW+Yvr7XCYvw== + dependencies: + "@ethersproject/logger" "^5.3.0" + +"@ethersproject/constants@5.3.0", "@ethersproject/constants@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.3.0.tgz#a5d6d86c0eec2c64c3024479609493b9afb3fc77" + integrity sha512-4y1feNOwEpgjAfiCFWOHznvv6qUF/H6uI0UKp8xdhftb+H+FbKflXg1pOgH5qs4Sr7EYBL+zPyPb+YD5g1aEyw== + dependencies: + "@ethersproject/bignumber" "^5.3.0" + +"@ethersproject/contracts@5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.3.0.tgz#ad699a3abaae30bfb6422cf31813a663b2d4099c" + integrity sha512-eDyQ8ltykvyQqnGZxb/c1e0OnEtzqXhNNC4BX8nhYBCaoBrYYuK/1fLmyEvc5+XUMoxNhwpYkoSSwvPLci7/Zg== + dependencies: + "@ethersproject/abi" "^5.3.0" + "@ethersproject/abstract-provider" "^5.3.0" + "@ethersproject/abstract-signer" "^5.3.0" + "@ethersproject/address" "^5.3.0" + "@ethersproject/bignumber" "^5.3.0" + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/constants" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + "@ethersproject/properties" "^5.3.0" + "@ethersproject/transactions" "^5.3.0" + +"@ethersproject/hash@5.3.0", "@ethersproject/hash@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.3.0.tgz#f65e3bf3db3282df4da676db6cfa049535dd3643" + integrity sha512-gAFZSjUPQ32CIfoKSMtMEQ+IO0kQxqhwz9fCIFt2DtAq2u4pWt8mL9Z5P0r6KkLcQU8LE9FmuPPyd+JvBzmr1w== + dependencies: + "@ethersproject/abstract-signer" "^5.3.0" + "@ethersproject/address" "^5.3.0" + "@ethersproject/bignumber" "^5.3.0" + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/keccak256" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + "@ethersproject/properties" "^5.3.0" + "@ethersproject/strings" "^5.3.0" + +"@ethersproject/hdnode@5.3.0", "@ethersproject/hdnode@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.3.0.tgz#26fed65ffd5c25463fddff13f5fb4e5617553c94" + integrity sha512-zLmmtLNoDMGoYRdjOab01Zqkvp+TmZyCGDAMQF1Bs3yZyBs/kzTNi1qJjR1jVUcPP5CWGtjFwY8iNG8oNV9J8g== + dependencies: + "@ethersproject/abstract-signer" "^5.3.0" + "@ethersproject/basex" "^5.3.0" + "@ethersproject/bignumber" "^5.3.0" + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + "@ethersproject/pbkdf2" "^5.3.0" + "@ethersproject/properties" "^5.3.0" + "@ethersproject/sha2" "^5.3.0" + "@ethersproject/signing-key" "^5.3.0" + "@ethersproject/strings" "^5.3.0" + "@ethersproject/transactions" "^5.3.0" + "@ethersproject/wordlists" "^5.3.0" + +"@ethersproject/json-wallets@5.3.0", "@ethersproject/json-wallets@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.3.0.tgz#7b1a5ff500c12aa8597ae82c8939837b0449376e" + integrity sha512-/xwbqaIb5grUIGNmeEaz8GdcpmDr++X8WT4Jqcclnxow8PXCUHFeDxjf3O+nSuoqOYG/Ds0+BI5xuQKbva6Xkw== + dependencies: + "@ethersproject/abstract-signer" "^5.3.0" + "@ethersproject/address" "^5.3.0" + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/hdnode" "^5.3.0" + "@ethersproject/keccak256" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + "@ethersproject/pbkdf2" "^5.3.0" + "@ethersproject/properties" "^5.3.0" + "@ethersproject/random" "^5.3.0" + "@ethersproject/strings" "^5.3.0" + "@ethersproject/transactions" "^5.3.0" aes-js "3.0.0" scrypt-js "3.0.1" -"@ethersproject/keccak256@^5.0.3": - version "5.0.3" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.0.3.tgz#f094a8fca3bb913c044593c4f382be424292e588" - integrity sha512-VhW3mgZMBZlETV6AyOmjNeNG+Pg68igiKkPpat8/FZl0CKnfgQ+KZQZ/ee1vT+X0IUM8/djqnei6btmtbA27Ug== +"@ethersproject/keccak256@5.3.0", "@ethersproject/keccak256@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.3.0.tgz#fb5cd36bdfd6fa02e2ea84964078a9fc6bd731be" + integrity sha512-Gv2YqgIUmRbYVNIibafT0qGaeGYLIA/EdWHJ7JcVxVSs2vyxafGxOJ5VpSBHWeOIsE6OOaCelYowhuuTicgdFQ== dependencies: - "@ethersproject/bytes" "^5.0.4" + "@ethersproject/bytes" "^5.3.0" js-sha3 "0.5.7" -"@ethersproject/logger@^5.0.5": - version "5.0.5" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.0.5.tgz#e3ba3d0bcf9f5be4da5f043b1e328eb98b80002f" - integrity sha512-gJj72WGzQhUtCk6kfvI8elTaPOQyMvrMghp/nbz0ivTo39fZ7IjypFh/ySDeUSdBNplAwhzWKKejQhdpyefg/w== - -"@ethersproject/networks@^5.0.3": - version "5.0.3" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.0.3.tgz#c4ebe56e79ca399247382627e50a022aa68ece55" - integrity sha512-Gjpejul6XFetJXyvHCd37IiCC00203kYGU9sMaRMZcAcYKszCkbOeo/Q7Mmdr/fS7YBbB5iTOahDJWiRLu/b7A== - dependencies: - "@ethersproject/logger" "^5.0.5" - -"@ethersproject/pbkdf2@^5.0.3": - version "5.0.3" - resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.0.3.tgz#f9eca284a458cd11179d407884c595412d8d2775" - integrity sha512-asc+YgJn7v7GKWYXGz3GM1d9XYI2HvdCw1cLEow2niEC9BfYA29rr1exz100zISk95GIU1YP2zV//zHsMtWE5Q== - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/sha2" "^5.0.3" - -"@ethersproject/properties@^5.0.3": - version "5.0.3" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.0.3.tgz#991aef39a5f87d4645cee76cec4df868bfb08be6" - integrity sha512-wLCSrbywkQgTO6tIF9ZdKsH9AIxPEqAJF/z5xcPkz1DK4mMAZgAXRNw1MrKYhyb+7CqNHbj3vxenNKFavGY/IA== - dependencies: - "@ethersproject/logger" "^5.0.5" - -"@ethersproject/providers@^5.0.8": - version "5.0.9" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.0.9.tgz#88b48596dcfb0848a89da3160d2e2a055fc899f6" - integrity sha512-UtGrlJxekFNV7lriPOxQbnYminyiwTgjHMPX83pG7N/W/t+PekQK8V9rdlvMr2bRyGgafHml0ZZMaTV4FxiBYg== - dependencies: - "@ethersproject/abstract-provider" "^5.0.4" - "@ethersproject/abstract-signer" "^5.0.4" - "@ethersproject/address" "^5.0.4" - "@ethersproject/basex" "^5.0.3" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/constants" "^5.0.4" - "@ethersproject/hash" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/networks" "^5.0.3" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/random" "^5.0.3" - "@ethersproject/rlp" "^5.0.3" - "@ethersproject/sha2" "^5.0.3" - "@ethersproject/strings" "^5.0.4" - "@ethersproject/transactions" "^5.0.5" - "@ethersproject/web" "^5.0.6" +"@ethersproject/logger@5.3.0", "@ethersproject/logger@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.3.0.tgz#7a69fa1d4ca0d4b7138da1627eb152f763d84dd0" + integrity sha512-8bwJ2gxJGkZZnpQSq5uSiZSJjyVTWmlGft4oH8vxHdvO1Asy4TwVepAhPgxIQIMxXZFUNMych1YjIV4oQ4I7dA== + +"@ethersproject/networks@5.3.0", "@ethersproject/networks@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.3.0.tgz#d8ad06eb107c69fb8651f4c81ddd0e88944fdfea" + integrity sha512-XGbD9MMgqrR7SYz8o6xVgdG+25v7YT5vQG8ZdlcLj2I7elOBM7VNeQrnxfSN7rWQNcqu2z80OM29gGbQz+4Low== + dependencies: + "@ethersproject/logger" "^5.3.0" + +"@ethersproject/pbkdf2@5.3.0", "@ethersproject/pbkdf2@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.3.0.tgz#8adbb41489c3c9f319cc44bc7d3e6095fd468dc8" + integrity sha512-Q9ChVU6gBFiex0FSdtzo4b0SAKz3ZYcYVFLrEWHL0FnHvNk3J3WgAtRNtBQGQYn/T5wkoTdZttMbfBkFlaiWcA== + dependencies: + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/sha2" "^5.3.0" + +"@ethersproject/properties@5.3.0", "@ethersproject/properties@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.3.0.tgz#feef4c4babeb7c10a6b3449575016f4ad2c092b2" + integrity sha512-PaHxJyM5/bfusk6vr3yP//JMnm4UEojpzuWGTmtL5X4uNhNnFNvlYilZLyDr4I9cTkIbipCMsAuIcXWsmdRnEw== + dependencies: + "@ethersproject/logger" "^5.3.0" + +"@ethersproject/providers@5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.3.0.tgz#bccb49f1073a7d56e24f49abb14bb281c9b08636" + integrity sha512-HtL+DEbzPcRyfrkrMay7Rk/4he+NbUpzI/wHXP4Cqtra82nQOnqqCgTQc4HbdDrl75WVxG/JRMFhyneIPIMZaA== + dependencies: + "@ethersproject/abstract-provider" "^5.3.0" + "@ethersproject/abstract-signer" "^5.3.0" + "@ethersproject/address" "^5.3.0" + "@ethersproject/basex" "^5.3.0" + "@ethersproject/bignumber" "^5.3.0" + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/constants" "^5.3.0" + "@ethersproject/hash" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + "@ethersproject/networks" "^5.3.0" + "@ethersproject/properties" "^5.3.0" + "@ethersproject/random" "^5.3.0" + "@ethersproject/rlp" "^5.3.0" + "@ethersproject/sha2" "^5.3.0" + "@ethersproject/strings" "^5.3.0" + "@ethersproject/transactions" "^5.3.0" + "@ethersproject/web" "^5.3.0" bech32 "1.1.4" - ws "7.2.3" - -"@ethersproject/random@^5.0.3": - version "5.0.3" - resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.0.3.tgz#ec16546fffdc10b9082f1207bd3a09f54cbcf5e6" - integrity sha512-pEhWRbgNeAY1oYk4nIsEtCTh9TtLsivIDbOX11n+DLZLYM3c8qCLxThXtsHwVsMs1JHClZr5auYC4YxtVVzO/A== - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - -"@ethersproject/rlp@^5.0.3": - version "5.0.3" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.0.3.tgz#841a5edfdf725f92155fe74424f5510c9043c13a" - integrity sha512-Hz4yyA/ilGafASAqtTlLWkA/YqwhQmhbDAq2LSIp1AJNx+wtbKWFAKSckpeZ+WG/xZmT+fw5OFKK7a5IZ4DR5g== - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - -"@ethersproject/sha2@^5.0.3": - version "5.0.3" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.0.3.tgz#52c16edc1135d0ec7d242d88eed035dae72800c0" - integrity sha512-B1U9UkgxhUlC1J4sFUL2GwTo33bM2i/aaD3aiYdTh1FEXtGfqYA89KN1DJ83n+Em8iuvyiBRk6u30VmgqlHeHA== - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - hash.js "1.1.3" - -"@ethersproject/signing-key@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.0.4.tgz#a5334ce8a52d4e9736dc8fb6ecc384704ecf8783" - integrity sha512-I6pJoga1IvhtjYK5yXzCjs4ZpxrVbt9ZRAlpEw0SW9UuV020YfJH5EIVEGR2evdRceS3nAQIggqbsXSkP8Y1Dg== - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - elliptic "6.5.3" - -"@ethersproject/solidity@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.0.4.tgz#67022cbfb50cb73b72d1739178537a9e798945bf" - integrity sha512-cUq1l8A+AgRkIItRoztC98Qx7b0bMNMzKX817fszDuGNsT2POAyP5knvuEt4Fx4IBcJREXoOjsGYFfjyK5Sa+w== - dependencies: - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/sha2" "^5.0.3" - "@ethersproject/strings" "^5.0.4" - -"@ethersproject/strings@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.0.4.tgz#67cda604eee3ffcc004cb9f3bd03516e1c7b09a0" - integrity sha512-azXFHaNkDXzefhr4LVVzzDMFwj3kH9EOKlATu51HjxabQafuUyVLPFgmxRFmCynnAi0Bmmp7nr+qK1pVDgRDLQ== - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/constants" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - -"@ethersproject/transactions@^5.0.5": - version "5.0.5" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.0.5.tgz#9a966f9ef4817b1752265d4efee0f1e9fd6aeaad" - integrity sha512-1Ga/QmbcB74DItggP8/DK1tggu4ErEvwTkIwIlUXUcvIAuRNXXE7kgQhlp+w1xA/SAQFhv56SqCoyqPiiLCvVA== - dependencies: - "@ethersproject/address" "^5.0.4" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/constants" "^5.0.4" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/rlp" "^5.0.3" - "@ethersproject/signing-key" "^5.0.4" - -"@ethersproject/units@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.0.4.tgz#e08876b54e1f6b362a841dcd986496a425875735" - integrity sha512-80d6skjDgiHLdbKOA9FVpzyMEPwbif40PbGd970JvcecVf48VjB09fUu37d6duG8DhRVyefRdX8nuVQLzcGGPw== - dependencies: - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/constants" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - -"@ethersproject/wallet@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.0.4.tgz#b414ae2870fc0ea10808330f0ab3c5a1ac9e34e1" - integrity sha512-h/3mdy6HZVketHbs6ZP/WjHDz+rtTIE3qZrko2MVeafjgDcYWaHcVmhsPq4LGqxginhr191a4dkJDNeQrQZWOw== - dependencies: - "@ethersproject/abstract-provider" "^5.0.4" - "@ethersproject/abstract-signer" "^5.0.4" - "@ethersproject/address" "^5.0.4" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/hash" "^5.0.4" - "@ethersproject/hdnode" "^5.0.4" - "@ethersproject/json-wallets" "^5.0.6" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/random" "^5.0.3" - "@ethersproject/signing-key" "^5.0.4" - "@ethersproject/transactions" "^5.0.5" - "@ethersproject/wordlists" "^5.0.4" - -"@ethersproject/web@^5.0.6": - version "5.0.7" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.0.7.tgz#ab8ccffa9cee9469a8b49af8b8fee30e384e59d8" - integrity sha512-BM8FdGrzdcULYaOIyMXDKvxv+qOwGne8FKpPxUrifZIWAWPrq/y+oBOZlzadIKsP3wvYbAcMN2CgOLO1E3yIfw== - dependencies: - "@ethersproject/base64" "^5.0.3" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/strings" "^5.0.4" - -"@ethersproject/wordlists@^5.0.4": - version "5.0.4" - resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.0.4.tgz#76a7e1dfd95aea645f6be2c1932b3f89b7f0c4ce" - integrity sha512-z/NsGqdYFvpeG6vPLxuD0pYNR5lLhQAy+oLVqg6G0o1c/OoL5J/a0iDOAFvnacQphc3lMP52d1LEX3YGoy2oBQ== - dependencies: - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/hash" "^5.0.4" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/strings" "^5.0.4" + ws "7.4.6" + +"@ethersproject/random@5.3.0", "@ethersproject/random@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.3.0.tgz#7c46bf36e50cb0d0550bc8c666af8e1d4496dc1a" + integrity sha512-A5SL/4inutSwt3Fh2OD0x2gz+x6GHmuUnIPkR7zAiTidMD2N8F6tZdMF1hlQKWVCcVMWhEQg8mWijhEzm6BBYw== + dependencies: + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + +"@ethersproject/rlp@5.3.0", "@ethersproject/rlp@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.3.0.tgz#7cb93a7b5dfa69163894153c9d4b0d936f333188" + integrity sha512-oI0joYpsRanl9guDubaW+1NbcpK0vJ3F/6Wpcanzcnqq+oaW9O5E98liwkEDPcb16BUTLIJ+ZF8GPIHYxJ/5Pw== + dependencies: + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + +"@ethersproject/sha2@5.3.0", "@ethersproject/sha2@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.3.0.tgz#209f9a1649f7d2452dcd5e5b94af43b7f3f42366" + integrity sha512-r5ftlwKcocYEuFz2JbeKOT5SAsCV4m1RJDsTOEfQ5L67ZC7NFDK5i7maPdn1bx4nPhylF9VAwxSrQ1esmwzylg== + dependencies: + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + hash.js "1.1.7" + +"@ethersproject/signing-key@5.3.0", "@ethersproject/signing-key@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.3.0.tgz#a96c88f8173e1abedfa35de32d3e5db7c48e5259" + integrity sha512-+DX/GwHAd0ok1bgedV1cKO0zfK7P/9aEyNoaYiRsGHpCecN7mhLqcdoUiUzE7Uz86LBsxm5ssK0qA1kBB47fbQ== + dependencies: + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + "@ethersproject/properties" "^5.3.0" + bn.js "^4.11.9" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/solidity@5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.3.0.tgz#2a0b00b4aaaef99a080ddea13acab1fa35cd4a93" + integrity sha512-uLRBaNUiISHbut94XKewJgQh6UmydWTBp71I7I21pkjVXfZO2dJ5EOo3jCnumJc01M4LOm79dlNNmF3oGIvweQ== + dependencies: + "@ethersproject/bignumber" "^5.3.0" + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/keccak256" "^5.3.0" + "@ethersproject/sha2" "^5.3.0" + "@ethersproject/strings" "^5.3.0" + +"@ethersproject/strings@5.3.0", "@ethersproject/strings@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.3.0.tgz#a6b640aab56a18e0909f657da798eef890968ff0" + integrity sha512-j/AzIGZ503cvhuF2ldRSjB0BrKzpsBMtCieDtn4TYMMZMQ9zScJn9wLzTQl/bRNvJbBE6TOspK0r8/Ngae/f2Q== + dependencies: + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/constants" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + +"@ethersproject/transactions@5.3.0", "@ethersproject/transactions@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.3.0.tgz#49b86f2bafa4d0bdf8e596578fc795ee47c50458" + integrity sha512-cdfK8VVyW2oEBCXhURG0WQ6AICL/r6Gmjh0e4Bvbv6MCn/GBd8FeBH3rtl7ho+AW50csMKeGv3m3K1HSHB2jMQ== + dependencies: + "@ethersproject/address" "^5.3.0" + "@ethersproject/bignumber" "^5.3.0" + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/constants" "^5.3.0" + "@ethersproject/keccak256" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + "@ethersproject/properties" "^5.3.0" + "@ethersproject/rlp" "^5.3.0" + "@ethersproject/signing-key" "^5.3.0" + +"@ethersproject/units@5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.3.0.tgz#c4d1493532ad3d4ddf6e2bc4f8c94a2db933a8f5" + integrity sha512-BkfccZGwfJ6Ob+AelpIrgAzuNhrN2VLp3AILnkqTOv+yBdsc83V4AYf25XC/u0rHnWl6f4POaietPwlMqP2vUg== + dependencies: + "@ethersproject/bignumber" "^5.3.0" + "@ethersproject/constants" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + +"@ethersproject/wallet@5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.3.0.tgz#91946b470bd279e39ade58866f21f92749d062af" + integrity sha512-boYBLydG6671p9QoG6EinNnNzbm7DNOjVT20eV8J6HQEq4aUaGiA2CytF2vK+2rOEWbzhZqoNDt6AlkE1LlsTg== + dependencies: + "@ethersproject/abstract-provider" "^5.3.0" + "@ethersproject/abstract-signer" "^5.3.0" + "@ethersproject/address" "^5.3.0" + "@ethersproject/bignumber" "^5.3.0" + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/hash" "^5.3.0" + "@ethersproject/hdnode" "^5.3.0" + "@ethersproject/json-wallets" "^5.3.0" + "@ethersproject/keccak256" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + "@ethersproject/properties" "^5.3.0" + "@ethersproject/random" "^5.3.0" + "@ethersproject/signing-key" "^5.3.0" + "@ethersproject/transactions" "^5.3.0" + "@ethersproject/wordlists" "^5.3.0" + +"@ethersproject/web@5.3.0", "@ethersproject/web@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.3.0.tgz#7959c403f6476c61515008d8f92da51c553a8ee1" + integrity sha512-Ni6/DHnY6k/TD41LEkv0RQDx4jqWz5e/RZvrSecsxGYycF+MFy2z++T/yGc2peRunLOTIFwEksgEGGlbwfYmhQ== + dependencies: + "@ethersproject/base64" "^5.3.0" + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + "@ethersproject/properties" "^5.3.0" + "@ethersproject/strings" "^5.3.0" + +"@ethersproject/wordlists@5.3.0", "@ethersproject/wordlists@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.3.0.tgz#45a0205f5178c1de33d316cb2ab7ed5eac3c06c5" + integrity sha512-JcwumCZcsUxgWpiFU/BRy6b4KlTRdOmYvOKZcAw/3sdF93/pZyPW5Od2hFkHS8oWp4xS06YQ+qHqQhdcxdHafQ== + dependencies: + "@ethersproject/bytes" "^5.3.0" + "@ethersproject/hash" "^5.3.0" + "@ethersproject/logger" "^5.3.0" + "@ethersproject/properties" "^5.3.0" + "@ethersproject/strings" "^5.3.0" "@perp/contract@^1.0.6": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@perp/contract/-/contract-1.0.6.tgz#b423738d095a15fccd17de7bc46a531482a45d18" - integrity sha512-5exstpCstXpXSLaxY/hTVT3BtRF8UVJ2JgGN8abiFSKBg+aaQdBZ4qvsOzr4HQ0fkZSOlURL/JnOUDV04UrD5A== + version "1.1.0" + resolved "https://registry.yarnpkg.com/@perp/contract/-/contract-1.1.0.tgz#c1f2aa73e74bdf083560258ffc16e2fbcf632003" + integrity sha512-79O3DoGYtC6Nu9TnzC6aUTwCuEfe3+CIZr9a27Uh26MQ0jHkCq2Rc4sz35k3ChuN9zL2ZmrsAR+mO785QGZFpw== "@sindresorhus/is@^0.14.0": version "0.14.0" @@ -1237,23 +1287,22 @@ defer-to-connect "^1.0.1" "@terra-money/terra.js@^0.5.8": - version "0.5.8" - resolved "https://registry.yarnpkg.com/@terra-money/terra.js/-/terra.js-0.5.8.tgz#effd51631c596e67b782819dca924241d1903597" - integrity sha512-a+WqEgnxCIz0hCW/EhqF47TublEqPX/NdL5xNwve3sNFTjK7AqHcpVUS79hubimPy9HlDDZCSCF8YAXXJ7xfCQ== + version "0.5.13" + resolved "https://registry.yarnpkg.com/@terra-money/terra.js/-/terra.js-0.5.13.tgz#fbbfb00d32b7cdad8807ea8ee40b3a71a0deca50" + integrity sha512-v2B+VqVar6gryTfpHsusmDn2WIRT23xnTKsxFn6G20WIN5XCeRQa84cnAlZHuNP9w5ejuvRmoHX0Wg6g1DJo3g== dependencies: axios "^0.20.0" bech32 "^1.1.4" bip32 "^2.0.6" bip39 "^3.0.2" + bufferutil "^4.0.1" crypto-js "3.3.0" - decimal.js "^10.2.0" + decimal.js "^10.2.1" post-message-stream "^3.0.0" secp256k1 "^4.0.2" - -"@types/color-name@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" - integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + tmp "^0.2.1" + utf-8-validate "^5.0.2" + ws "^7.3.1" "@types/json5@^0.0.29": version "0.0.29" @@ -1301,31 +1350,41 @@ accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn-jsx@^5.2.0: +acorn-jsx@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== acorn@^7.4.0: - version "7.4.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c" - integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w== + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== aes-js@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0= -ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.4: - version "6.12.5" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da" - integrity sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag== +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^8.0.1: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.5.0.tgz#695528274bcb5afc865446aa275484049a18ae4b" + integrity sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + ansi-align@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" @@ -1348,25 +1407,24 @@ ansi-regex@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== -ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" -ansi-styles@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" - integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: - "@types/color-name" "^1.1.1" color-convert "^2.0.1" anymatch@~3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" - integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" @@ -1391,23 +1449,20 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" -array-filter@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" - integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM= - array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= -array-includes@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" - integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== +array-includes@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.3.tgz#c7f619b382ad2afaf5326cddfdc0afc61af7690a" + integrity sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A== dependencies: + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.17.0" + es-abstract "^1.18.0-next.2" + get-intrinsic "^1.1.1" is-string "^1.0.5" array-uniq@1.0.2: @@ -1415,30 +1470,29 @@ array-uniq@1.0.2: resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.2.tgz#5fcc373920775723cfd64d65c64bef53bf9eba6d" integrity sha1-X8w3OSB3VyPP1k1lxkvvU7+eum0= -array.prototype.flat@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" - integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== +array.prototype.flat@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz#6ef638b43312bd401b4c6199fdec7e2dc9e9a123" + integrity sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg== dependencies: + call-bind "^1.0.0" define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" + es-abstract "^1.18.0-next.1" -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== async@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== -available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5" - integrity sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ== - dependencies: - array-filter "^1.0.0" +available-typed-arrays@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.4.tgz#9e0ae84ecff20caae6a94a1c3bc39b955649b7a9" + integrity sha512-SA5mXJWrId1TaQjfxUYghbqQ/hYioKmLJvPJyDuYRtXXenFNMjj4hSSt1Cf1xsuXSXrtxrVC5Ot4eU6cOtBDdA== axios@^0.20.0: version "0.20.0" @@ -1461,10 +1515,34 @@ babel-plugin-dynamic-import-node@^2.3.3: dependencies: object.assign "^4.1.0" +babel-plugin-polyfill-corejs2@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz#e9124785e6fd94f94b618a7954e5693053bf5327" + integrity sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ== + dependencies: + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.2.2" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.2.tgz#7424a1682ee44baec817327710b1b094e5f8f7f5" + integrity sha512-l1Cf8PKk12eEk5QP/NQ6TH8A1pee6wWDJ96WjxrMXFLHLOBFzYM4moG80HFgduVhTqAFez4alnZKEhP/bYHg0A== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.2.2" + core-js-compat "^3.9.1" + +babel-plugin-polyfill-regenerator@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz#b310c8d642acada348c1fa3b3e6ce0e851bee077" + integrity sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.2.2" + balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base-x@^3.0.2: version "3.0.8" @@ -1484,14 +1562,14 @@ big.js@^5.2.2: integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== bignumber.js@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.0.tgz#805880f84a329b5eac6e7cb6f8274b6d82bdf075" - integrity sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A== + version "9.0.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.1.tgz#8d7ba124c882bfd8e43260c67475518d0689e4e5" + integrity sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA== binary-extensions@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9" - integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ== + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== bindings@^1.3.0: version "1.5.0" @@ -1514,19 +1592,19 @@ bip32@^2.0.6: wif "^2.0.6" bip39@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/bip39/-/bip39-3.0.2.tgz#2baf42ff3071fc9ddd5103de92e8f80d9257ee32" - integrity sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ== + version "3.0.4" + resolved "https://registry.yarnpkg.com/bip39/-/bip39-3.0.4.tgz#5b11fed966840b5e1b8539f0f54ab6392969b2a0" + integrity sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw== dependencies: "@types/node" "11.11.6" create-hash "^1.1.0" pbkdf2 "^3.0.9" randombytes "^2.0.1" -bn.js@^4.11.8, bn.js@^4.4.0: - version "4.11.9" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" - integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw== +bn.js@^4.11.8, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== body-parser@1.19.0, body-parser@^1.19.0: version "1.19.0" @@ -1573,20 +1651,21 @@ braces@~3.0.2: dependencies: fill-range "^7.0.1" -brorand@^1.0.1: +brorand@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= -browserslist@^4.12.0, browserslist@^4.8.5: - version "4.14.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.3.tgz#381f9e7f13794b2eb17e1761b4f118e8ae665a53" - integrity sha512-GcZPC5+YqyPO4SFnz48/B0YaCwS47Q9iPChRGi6t7HhflKBcINzFrJvRfC+jp30sRMKxF+d4EHGs27Z0XP1NaQ== +browserslist@^4.16.6: + version "4.16.6" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2" + integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ== dependencies: - caniuse-lite "^1.0.30001131" - electron-to-chromium "^1.3.570" - escalade "^3.1.0" - node-releases "^1.1.61" + caniuse-lite "^1.0.30001219" + colorette "^1.2.2" + electron-to-chromium "^1.3.723" + escalade "^3.1.1" + node-releases "^1.1.71" bs58@^4.0.0: version "4.0.1" @@ -1609,6 +1688,13 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +bufferutil@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.3.tgz#66724b756bed23cd7c28c4d306d7994f9943cc6b" + integrity sha512-yEYTwGndELGvfXsImMBLop58eaGW+YdONi1fNjTINSY98tmMmFijBG6WXgdkfuLNt4imzQNtIE+eBp1PVpMCSw== + dependencies: + node-gyp-build "^4.2.0" + bytes@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" @@ -1627,6 +1713,14 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -1637,10 +1731,10 @@ camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -caniuse-lite@^1.0.30001131: - version "1.0.30001133" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001133.tgz#ec564c5495311299eb05245e252d589a84acd95e" - integrity sha512-s3XAUFaC/ntDb1O3lcw9K8MPeOW7KO3z9+GzAoBxfz1B0VdacXPMKgFUtG4KIsgmnbexmi013s9miVu4h+qMHw== +caniuse-lite@^1.0.30001219: + version "1.0.30001233" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001233.tgz#b7cb4a377a4b12ed240d2fa5c792951a06e5f2c4" + integrity sha512-BmkbxLfStqiPA7IEzQpIk0UFZFf3A4E6fzjPJ6OR+bFC2L8ES9J8zGA/asoi47p8XDVkev+WJo2I2Nc8c/34Yg== capture-console@^1.0.1: version "1.0.1" @@ -1669,17 +1763,17 @@ chalk@^3.0.0: supports-color "^7.1.0" chalk@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + version "4.1.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" + integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== dependencies: ansi-styles "^4.1.0" supports-color "^7.1.0" chokidar@^3.2.2: - version "3.4.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.2.tgz#38dc8e658dec3809741eb3ef7bb0a47fe424232d" - integrity sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A== + version "3.5.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" + integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== dependencies: anymatch "~3.1.1" braces "~3.0.2" @@ -1687,9 +1781,9 @@ chokidar@^3.2.2: is-binary-path "~2.1.0" is-glob "~4.0.1" normalize-path "~3.0.0" - readdirp "~3.4.0" + readdirp "~3.5.0" optionalDependencies: - fsevents "~2.1.2" + fsevents "~2.3.1" ci-info@^2.0.0: version "2.0.0" @@ -1709,6 +1803,15 @@ cli-boxes@^2.2.0: resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + clone-response@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" @@ -1741,9 +1844,9 @@ color-name@^1.0.0, color-name@~1.1.4: integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== color-string@^1.5.2: - version "1.5.4" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.4.tgz#dd51cd25cfee953d138fe4002372cc3d0e504cb6" - integrity sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw== + version "1.5.5" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.5.tgz#65474a8f0e7439625f3d27a6a19d89fc45223014" + integrity sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg== dependencies: color-name "^1.0.0" simple-swizzle "^0.2.2" @@ -1756,6 +1859,11 @@ color@3.0.x: color-convert "^1.9.1" color-string "^1.5.2" +colorette@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" + integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== + colors@^1.2.1: version "1.4.0" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" @@ -1779,10 +1887,10 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= -complex.js@^2.0.11: - version "2.0.12" - resolved "https://registry.yarnpkg.com/complex.js/-/complex.js-2.0.12.tgz#fa4df97d8928e5f7b6a86b35bdeecc3a3eda8a22" - integrity sha512-oQX99fwL6LrTVg82gDY1dIWXy6qZRnRL35N+YhIX0N7tSwsa0KFy6IEMHTNuCW4mP7FS7MEqZ/2I/afzYwPldw== +complex.js@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/complex.js/-/complex.js-2.0.13.tgz#00cf7ba082565e164813b7bbbb0ced5d2aba172a" + integrity sha512-UEWd3G3/kd3lJmsdLsDh9qfinJlujL4hIFn3Vo4/G5eqehPsgCHf2CLhFs77tVkOp2stt/jbNit7Q1XFANFltA== concat-map@0.0.1: version "0.0.1" @@ -1801,10 +1909,10 @@ configstore@^5.0.1: write-file-atomic "^3.0.0" xdg-basedir "^4.0.0" -contains-path@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" - integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= +confusing-browser-globals@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz#30d1e7f3d1b882b25ec4933d1d1adac353d20a59" + integrity sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA== content-disposition@0.5.3: version "0.5.3" @@ -1835,18 +1943,18 @@ cookie@0.4.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== -core-js-compat@^3.6.2: - version "3.6.5" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c" - integrity sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng== +core-js-compat@^3.9.0, core-js-compat@^3.9.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.13.1.tgz#05444caa8f153be0c67db03cf8adb8ec0964e58e" + integrity sha512-mdrcxc0WznfRd8ZicEZh1qVeJ2mu6bwQFh8YVUK48friy/FOwFV5EJj9/dlh+nMQ74YusdVfBFDuomKgUspxWQ== dependencies: - browserslist "^4.8.5" + browserslist "^4.16.6" semver "7.0.0" core-js@^3.2.1: - version "3.6.5" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a" - integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== + version "3.13.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.13.1.tgz#30303fabd53638892062d8b4e802cac7599e9fb7" + integrity sha512-JqveUc4igkqwStL2RTRn/EPFGBOfEZHxJl/8ej1mXJR75V3go2mFF4bmUYkEIT1rveHKnkUlcJX/c+f1TyIovQ== core-util-is@~1.0.0: version "1.0.2" @@ -1877,9 +1985,9 @@ create-hmac@^1.1.4, create-hmac@^1.1.7: sha.js "^2.4.8" cross-fetch@^3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.0.6.tgz#3a4040bc8941e653e0e9cf17f29ebcd177d3365c" - integrity sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ== + version "3.1.4" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39" + integrity sha512-1eAtFWdIubi6T4XPy6ei9iUFoKpUkIF971QLN8lIvvvwueI65+Nw5haMNKUwfJxabqlIIDODJKGrQ66gxC0PbQ== dependencies: node-fetch "2.6.1" @@ -1909,17 +2017,17 @@ debug@2.6.9, debug@^2.2.0, debug@^2.6.9: dependencies: ms "2.0.0" -debug@^3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== +debug@^3.2.6, debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" - integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg== + version "4.3.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== dependencies: ms "2.1.2" @@ -1928,11 +2036,6 @@ decimal.js-light@^2.5.0: resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934" integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg== -decimal.js@^10.2.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.0.tgz#39466113a9e036111d02f82489b5fd6b0b5ed231" - integrity sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw== - decimal.js@^10.2.1: version "10.2.1" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3" @@ -1977,13 +2080,12 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= -doctrine@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" - integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== dependencies: esutils "^2.0.2" - isarray "^1.0.0" doctrine@^3.0.0: version "3.0.0" @@ -2000,9 +2102,9 @@ dot-prop@^5.2.0: is-obj "^2.0.0" dotenv@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" - integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== + version "8.6.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" + integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== duplexer3@^0.1.4: version "0.1.4" @@ -2014,23 +2116,23 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.3.570: - version "1.3.570" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.570.tgz#3f5141cc39b4e3892a276b4889980dabf1d29c7f" - integrity sha512-Y6OCoVQgFQBP5py6A/06+yWxUZHDlNr/gNDGatjH8AZqXl8X0tE4LfjLJsXGz/JmWJz8a6K7bR1k+QzZ+k//fg== +electron-to-chromium@^1.3.723: + version "1.3.745" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.745.tgz#b54c2baa0e01658288d6835d9f19727fd480de63" + integrity sha512-ZZCx4CS3kYT3BREYiIXocDqlNPT56KfdTS1Ogo4yvxRriBqiEXCDTLIQZT/zNVtby91xTWMMxW2NBiXh8bpLHw== -elliptic@6.5.3, elliptic@^6.4.0, elliptic@^6.5.2: - version "6.5.3" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" - integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw== +elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.2: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== dependencies: - bn.js "^4.4.0" - brorand "^1.0.1" + bn.js "^4.11.9" + brorand "^1.1.0" hash.js "^1.0.0" - hmac-drbg "^1.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" emoji-regex@^7.0.1: version "7.0.3" @@ -2073,47 +2175,34 @@ enquirer@^2.3.5: dependencies: ansi-colors "^4.1.1" -error-ex@^1.2.0: +error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.4, es-abstract@^1.17.5: - version "1.17.6" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a" - integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw== - dependencies: - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.0" - is-regex "^1.1.0" - object-inspect "^1.7.0" - object-keys "^1.1.1" - object.assign "^4.1.0" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^1.0.1" - -es-abstract@^1.18.0-next.0: - version "1.18.0-next.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.0.tgz#b302834927e624d8e5837ed48224291f2c66e6fc" - integrity sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ== +es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2: + version "1.18.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.3.tgz#25c4c3380a27aa203c44b2b685bba94da31b63e0" + integrity sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw== dependencies: + call-bind "^1.0.2" es-to-primitive "^1.2.1" function-bind "^1.1.1" + get-intrinsic "^1.1.1" has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.2.0" - is-negative-zero "^2.0.0" - is-regex "^1.1.1" - object-inspect "^1.8.0" + has-symbols "^1.0.2" + is-callable "^1.2.3" + is-negative-zero "^2.0.1" + is-regex "^1.1.3" + is-string "^1.0.6" + object-inspect "^1.10.3" object-keys "^1.1.1" - object.assign "^4.1.0" - string.prototype.trimend "^1.0.1" - string.prototype.trimstart "^1.0.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" es-to-primitive@^1.2.1: version "1.2.1" @@ -2124,10 +2213,10 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -escalade@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.0.tgz#e8e2d7c7a8b76f6ee64c2181d6b8151441602d4e" - integrity sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig== +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== escape-goat@^2.0.0: version "2.1.1" @@ -2149,6 +2238,20 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-airbnb-base@^14.2.1: + version "14.2.1" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz#8a2eb38455dc5a312550193b319cdaeef042cd1e" + integrity sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA== + dependencies: + confusing-browser-globals "^1.0.10" + object.assign "^4.1.2" + object.entries "^1.1.2" + eslint-config-standard@^14.1.1: version "14.1.1" resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea" @@ -2162,12 +2265,12 @@ eslint-import-resolver-node@^0.3.4: debug "^2.6.9" resolve "^1.13.1" -eslint-module-utils@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6" - integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA== +eslint-module-utils@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz#b51be1e473dd0de1c5ea638e22429c2490ea8233" + integrity sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A== dependencies: - debug "^2.6.9" + debug "^3.2.7" pkg-dir "^2.0.0" eslint-plugin-es@^3.0.0: @@ -2178,23 +2281,25 @@ eslint-plugin-es@^3.0.0: eslint-utils "^2.0.0" regexpp "^3.0.0" -eslint-plugin-import@^2.22.1: - version "2.22.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz#0896c7e6a0cf44109a2d97b95903c2bb689d7702" - integrity sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw== +eslint-plugin-import@^2.23.3: + version "2.23.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz#8dceb1ed6b73e46e50ec9a5bb2411b645e7d3d97" + integrity sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ== dependencies: - array-includes "^3.1.1" - array.prototype.flat "^1.2.3" - contains-path "^0.1.0" + array-includes "^3.1.3" + array.prototype.flat "^1.2.4" debug "^2.6.9" - doctrine "1.5.0" + doctrine "^2.1.0" eslint-import-resolver-node "^0.3.4" - eslint-module-utils "^2.6.0" + eslint-module-utils "^2.6.1" + find-up "^2.0.0" has "^1.0.3" + is-core-module "^2.4.0" minimatch "^3.0.4" - object.values "^1.1.1" - read-pkg-up "^2.0.0" - resolve "^1.17.0" + object.values "^1.1.3" + pkg-up "^2.0.0" + read-pkg-up "^3.0.0" + resolve "^1.20.0" tsconfig-paths "^3.9.0" eslint-plugin-node@^11.1.0: @@ -2210,14 +2315,14 @@ eslint-plugin-node@^11.1.0: semver "^6.1.0" eslint-plugin-promise@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a" - integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw== + version "4.3.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz#61485df2a359e03149fdafc0a68b0e030ad2ac45" + integrity sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ== eslint-plugin-standard@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz#ff0519f7ffaff114f76d1bd7c3996eef0f6e20b4" - integrity sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ== + version "4.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.1.0.tgz#0c3bf3a67e853f8bbbc580fb4945fbf16f41b7c5" + integrity sha512-ZL7+QRixjTR6/528YNGyDotyffm5OQst/sGxKDwGb9Uqs4In5Egi4+jbobhqJoyoCM6/7v/1A5fhQ7ScMtDjaQ== eslint-scope@^5.1.1: version "5.1.1" @@ -2239,29 +2344,36 @@ eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== -eslint@^7.10.0: - version "7.10.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.10.0.tgz#494edb3e4750fb791133ca379e786a8f648c72b9" - integrity sha512-BDVffmqWl7JJXqCjAK6lWtcQThZB/aP1HXSH1JKwGwv0LQEdvpR7qzNrUT487RM39B5goWuboFad5ovMBmD8yA== +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint@^7.27.0: + version "7.27.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.27.0.tgz#665a1506d8f95655c9274d84bd78f7166b07e9c7" + integrity sha512-JZuR6La2ZF0UD384lcbnd0Cgg6QJjiCwhMD6eU4h/VGPcVGwawNNzKU41tgokGXnfjOOyI6QIffthhJTPzzuRA== dependencies: - "@babel/code-frame" "^7.0.0" - "@eslint/eslintrc" "^0.1.3" + "@babel/code-frame" "7.12.11" + "@eslint/eslintrc" "^0.4.1" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.0.1" doctrine "^3.0.0" enquirer "^2.3.5" + escape-string-regexp "^4.0.0" eslint-scope "^5.1.1" eslint-utils "^2.1.0" - eslint-visitor-keys "^1.3.0" - espree "^7.3.0" - esquery "^1.2.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.4.0" esutils "^2.0.2" - file-entry-cache "^5.0.1" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" functional-red-black-tree "^1.0.1" glob-parent "^5.0.0" - globals "^12.1.0" + globals "^13.6.0" ignore "^4.0.6" import-fresh "^3.0.0" imurmurhash "^0.1.4" @@ -2269,7 +2381,7 @@ eslint@^7.10.0: js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" - lodash "^4.17.19" + lodash.merge "^4.6.2" minimatch "^3.0.4" natural-compare "^1.4.0" optionator "^0.9.1" @@ -2278,17 +2390,17 @@ eslint@^7.10.0: semver "^7.2.1" strip-ansi "^6.0.0" strip-json-comments "^3.1.0" - table "^5.2.3" + table "^6.0.9" text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^7.3.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.0.tgz#dc30437cf67947cf576121ebd780f15eeac72348" - integrity sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw== +espree@^7.3.0, espree@^7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== dependencies: acorn "^7.4.0" - acorn-jsx "^5.2.0" + acorn-jsx "^5.3.1" eslint-visitor-keys "^1.3.0" esprima@^4.0.0: @@ -2296,10 +2408,10 @@ esprima@^4.0.0: resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.2.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" - integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== dependencies: estraverse "^5.1.0" @@ -2331,45 +2443,45 @@ etag@~1.8.1: integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= ethers@^5.0.14: - version "5.0.14" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.0.14.tgz#fc33613ff3c1eb04c481f32083f2be315079e2a2" - integrity sha512-6WkoYwAURTr/4JiSZlrMJ9mm3pBv/bWrOu7sVXdLGw9QU4cp/GDZVrKKnh5GafMTzanuNBJoaEanPCjsbe4Mig== - dependencies: - "@ethersproject/abi" "^5.0.5" - "@ethersproject/abstract-provider" "^5.0.4" - "@ethersproject/abstract-signer" "^5.0.4" - "@ethersproject/address" "^5.0.4" - "@ethersproject/base64" "^5.0.3" - "@ethersproject/basex" "^5.0.3" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/constants" "^5.0.4" - "@ethersproject/contracts" "^5.0.4" - "@ethersproject/hash" "^5.0.4" - "@ethersproject/hdnode" "^5.0.4" - "@ethersproject/json-wallets" "^5.0.6" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/networks" "^5.0.3" - "@ethersproject/pbkdf2" "^5.0.3" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/providers" "^5.0.8" - "@ethersproject/random" "^5.0.3" - "@ethersproject/rlp" "^5.0.3" - "@ethersproject/sha2" "^5.0.3" - "@ethersproject/signing-key" "^5.0.4" - "@ethersproject/solidity" "^5.0.4" - "@ethersproject/strings" "^5.0.4" - "@ethersproject/transactions" "^5.0.5" - "@ethersproject/units" "^5.0.4" - "@ethersproject/wallet" "^5.0.4" - "@ethersproject/web" "^5.0.6" - "@ethersproject/wordlists" "^5.0.4" + version "5.3.0" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.3.0.tgz#1ec14d09c461e8f2554b00cd080e94a3094e7e9d" + integrity sha512-myN+338S4sFQZvQ9trii7xit8Hu/LnUtjA0ROFOHpUreQc3fgLZEMNVqF3vM1u2D78DIIeG1TbuozVCVlXQWvQ== + dependencies: + "@ethersproject/abi" "5.3.0" + "@ethersproject/abstract-provider" "5.3.0" + "@ethersproject/abstract-signer" "5.3.0" + "@ethersproject/address" "5.3.0" + "@ethersproject/base64" "5.3.0" + "@ethersproject/basex" "5.3.0" + "@ethersproject/bignumber" "5.3.0" + "@ethersproject/bytes" "5.3.0" + "@ethersproject/constants" "5.3.0" + "@ethersproject/contracts" "5.3.0" + "@ethersproject/hash" "5.3.0" + "@ethersproject/hdnode" "5.3.0" + "@ethersproject/json-wallets" "5.3.0" + "@ethersproject/keccak256" "5.3.0" + "@ethersproject/logger" "5.3.0" + "@ethersproject/networks" "5.3.0" + "@ethersproject/pbkdf2" "5.3.0" + "@ethersproject/properties" "5.3.0" + "@ethersproject/providers" "5.3.0" + "@ethersproject/random" "5.3.0" + "@ethersproject/rlp" "5.3.0" + "@ethersproject/sha2" "5.3.0" + "@ethersproject/signing-key" "5.3.0" + "@ethersproject/solidity" "5.3.0" + "@ethersproject/strings" "5.3.0" + "@ethersproject/transactions" "5.3.0" + "@ethersproject/units" "5.3.0" + "@ethersproject/wallet" "5.3.0" + "@ethersproject/web" "5.3.0" + "@ethersproject/wordlists" "5.3.0" express-ipfilter@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/express-ipfilter/-/express-ipfilter-1.1.2.tgz#536e1b8922f00df45d6da8796b02a75b1033a20f" - integrity sha512-dm1G3sVxlSbcOWSxfUTCo20ySyNQXJ4hJD5fuQJFoZlhkQvpbuDGBlh8AbFm1GwX85EWvfyhekOkvcydaXkBkg== + version "1.2.0" + resolved "https://registry.yarnpkg.com/express-ipfilter/-/express-ipfilter-1.2.0.tgz#fbc1ad0be45dbd8ae929ceb5ed8e1c91b33a71a1" + integrity sha512-nPXKMuhqVjX7+Vny4XsrpdqlX4YAGcanE0gh5xzpfmNTsINGAgPnpk67kb0No3p1m4vGQQLU6hdaXRxsuGNlTA== dependencies: ip "~1.1.0" lodash "^4.17.11" @@ -2412,7 +2524,7 @@ express@^4.17.1: utils-merge "1.0.1" vary "~1.1.2" -fast-deep-equal@^3.1.1: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== @@ -2433,16 +2545,16 @@ fast-safe-stringify@^2.0.4: integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== fecha@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.0.tgz#3ffb6395453e3f3efff850404f0a59b6747f5f41" - integrity sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg== + version "4.2.1" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.1.tgz#0a83ad8f86ef62a091e22bb5a039cd03d23eecce" + integrity sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q== -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== dependencies: - flat-cache "^2.0.1" + flat-cache "^3.0.4" file-stream-rotator@^0.5.7: version "0.5.7" @@ -2499,19 +2611,18 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" + flatted "^3.1.0" + rimraf "^3.0.2" -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== +flatted@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469" + integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA== fn.name@1.x.x: version "1.1.0" @@ -2519,24 +2630,24 @@ fn.name@1.x.x: integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== follow-redirects@^1.10.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" - integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== + version "1.14.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43" + integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg== foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= -forwarded@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" - integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -fraction.js@^4.0.13: - version "4.0.13" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.0.13.tgz#3c1c315fa16b35c85fffa95725a36fa729c69dfe" - integrity sha512-E1fz2Xs9ltlUp+qbiyx9wmt2n9dRzPsS11Jtdb8D2o+cC7wr9xkkKsVKJuBX0ST+LVS+LhLO+SbLJNtfWcJvXA== +fraction.js@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.1.1.tgz#ac4e520473dae67012d618aab91eda09bcb400ff" + integrity sha512-MHOhvvxHTfRFpF1geTK9czMIZ6xclsEor2wkIGYYq+PxcQqT7vStJqjhe6S1TenZrMZzo+wlqOufBDVepUEgPg== fresh@0.5.2: version "0.5.2" @@ -2548,10 +2659,10 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@~2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" - integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== +fsevents@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== function-bind@^1.1.1: version "1.1.1" @@ -2563,10 +2674,19 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= -gensync@^1.0.0-beta.1: - version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" - integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" get-stream@^4.1.0: version "4.1.0" @@ -2583,16 +2703,16 @@ get-stream@^5.1.0: pump "^3.0.0" glob-parent@^5.0.0, glob-parent@~5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" - integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" glob@^7.1.3: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -2602,11 +2722,11 @@ glob@^7.1.3: path-is-absolute "^1.0.0" global-dirs@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.0.1.tgz#acdf3bb6685bcd55cb35e8a052266569e9469201" - integrity sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A== + version "2.1.0" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d" + integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ== dependencies: - ini "^1.3.5" + ini "1.3.7" globals@^11.1.0: version "11.12.0" @@ -2620,6 +2740,13 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" +globals@^13.6.0: + version "13.9.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.9.0.tgz#4bf2bf635b334a173fb1daf7c5e6b218ecdc06cb" + integrity sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA== + dependencies: + type-fest "^0.20.2" + got@^9.6.0: version "9.6.0" resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" @@ -2638,9 +2765,14 @@ got@^9.6.0: url-parse-lax "^3.0.0" graceful-fs@^4.1.2: - version "4.2.4" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" - integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== + version "4.2.6" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" + integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== + +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== has-flag@^3.0.0: version "3.0.0" @@ -2652,10 +2784,10 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" - integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== +has-symbols@^1.0.1, has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== has-yarn@^2.1.0: version "2.1.0" @@ -2678,15 +2810,7 @@ hash-base@^3.0.0: readable-stream "^3.6.0" safe-buffer "^5.2.0" -hash.js@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" - integrity sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.0" - -hash.js@^1.0.0, hash.js@^1.0.3: +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: version "1.1.7" resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== @@ -2695,11 +2819,11 @@ hash.js@^1.0.0, hash.js@^1.0.3: minimalistic-assert "^1.0.1" helmet@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/helmet/-/helmet-4.1.1.tgz#751f0e273d809ace9c172073e0003bed27d27a4a" - integrity sha512-Avg4XxSBrehD94mkRwEljnO+6RZx7AGfk8Wa6K1nxaU+hbXlFOhlOIMgPfFqOYQB/dBCsTpootTGuiOG+CHiQA== + version "4.6.0" + resolved "https://registry.yarnpkg.com/helmet/-/helmet-4.6.0.tgz#579971196ba93c5978eb019e4e8ec0e50076b4df" + integrity sha512-HVqALKZlR95ROkrnesdhbbZJFi/rIVSoNq6f3jA/9u6MIbTsPh3xZwihjeI5+DO/2sOV6HMHooXcEOuwskHpTg== -hmac-drbg@^1.0.0: +hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= @@ -2716,9 +2840,9 @@ homedir-polyfill@^1.0.1: parse-passwd "^1.0.0" hosted-git-info@^2.1.4: - version "2.8.8" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" - integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== http-cache-semantics@^4.0.0: version "4.1.0" @@ -2760,9 +2884,9 @@ iconv-lite@0.4.24: safer-buffer ">= 2.1.2 < 3" iconv-lite@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.2.tgz#ce13d1875b0c3a674bd6a04b7f76b01b1b6ded01" - integrity sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ== + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== dependencies: safer-buffer ">= 2.1.2 < 3.0.0" @@ -2782,9 +2906,9 @@ ignore@^5.1.1: integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== import-fresh@^3.0.0, import-fresh@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" - integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" @@ -2817,17 +2941,15 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.5, ini@~1.3.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== +ini@1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" + integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== -invariant@^2.2.2, invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" +ini@~1.3.0: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== ip6@0.0.4: version "0.0.4" @@ -2850,9 +2972,11 @@ ipaddr.js@1.9.1: integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== is-arguments@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3" - integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA== + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9" + integrity sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg== + dependencies: + call-bind "^1.0.0" is-arrayish@^0.2.1: version "0.2.1" @@ -2864,6 +2988,11 @@ is-arrayish@^0.3.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== +is-bigint@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.2.tgz#ffb381442503235ad245ea89e45b3dbff040ee5a" + integrity sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA== + is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -2871,10 +3000,17 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-callable@^1.1.4, is-callable@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.1.tgz#4d1e21a4f437509d25ce55f8184350771421c96d" - integrity sha512-wliAfSzx6V+6WfMOmus1xy0XvSgf/dlStkvTfq7F0g4bOIW0PSUbnyse3NhDwdyYS1ozfUtAAySqTws3z9Eqgg== +is-boolean-object@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.1.tgz#3c0878f035cb821228d350d2e1e36719716a3de8" + integrity sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng== + dependencies: + call-bind "^1.0.2" + +is-callable@^1.1.4, is-callable@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" + integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== is-ci@^2.0.0: version "2.0.0" @@ -2883,10 +3019,17 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" +is-core-module@^2.2.0, is-core-module@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1" + integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A== + dependencies: + has "^1.0.3" + is-date-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.4.tgz#550cfcc03afada05eea3dd30981c7b09551f73e5" + integrity sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A== is-extglob@^2.1.1: version "2.1.1" @@ -2904,9 +3047,9 @@ is-fullwidth-code-point@^3.0.0: integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== is-generator-function@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" - integrity sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw== + version "1.0.9" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.9.tgz#e5f82c2323673e7fcad3d12858c83c4039f6399c" + integrity sha512-ZJ34p1uvIfptHCN7sFTjGibB9/oBg17sHqzDLfuwhvmN/qLVvIQXRQ8licZQ35WJ8KuEQt/etnnzQFI9C9Ue/A== is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.1" @@ -2923,16 +3066,21 @@ is-installed-globally@^0.3.1: global-dirs "^2.0.1" is-path-inside "^3.0.1" -is-negative-zero@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461" - integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE= +is-negative-zero@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" + integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== is-npm@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== +is-number-object@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.5.tgz#6edfaeed7950cff19afedce9fbfca9ee6dd289eb" + integrity sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw== + is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -2944,16 +3092,24 @@ is-obj@^2.0.0: integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== is-path-inside@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017" - integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg== + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== -is-regex@^1.1.0, is-regex@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" - integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== dependencies: - has-symbols "^1.0.1" + isobject "^3.0.1" + +is-regex@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.3.tgz#d029f9aff6448b93ebbe3f33dac71511fdcbef9f" + integrity sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ== + dependencies: + call-bind "^1.0.2" + has-symbols "^1.0.2" is-stream@^1.0.1: version "1.1.0" @@ -2965,25 +3121,26 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== -is-string@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" - integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== +is-string@^1.0.5, is-string@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.6.tgz#3fe5d5992fb0d93404f32584d4b0179a71b54a5f" + integrity sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w== -is-symbol@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== dependencies: - has-symbols "^1.0.1" + has-symbols "^1.0.2" is-typed-array@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.3.tgz#a4ff5a5e672e1a55f99c7f54e59597af5c1df04d" - integrity sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ== + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.5.tgz#f32e6e096455e329eb7b423862456aa213f0eb4e" + integrity sha512-S+GRDgJlR3PyEbsX/Fobd9cqpZBuvUS+8asRqYDMLCb2qMzt1oz5m5oxQCxOgUDxiWsOVNi4yaF+/uvdlHlYug== dependencies: - available-typed-arrays "^1.0.0" - es-abstract "^1.17.4" + available-typed-arrays "^1.0.2" + call-bind "^1.0.2" + es-abstract "^1.18.0-next.2" foreach "^2.0.5" has-symbols "^1.0.1" @@ -2997,7 +3154,7 @@ is-yarn-global@^0.3.0: resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== -isarray@^1.0.0, isarray@~1.0.0: +isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= @@ -3007,6 +3164,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + isomorphic-fetch@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" @@ -3025,15 +3187,15 @@ js-sha3@0.5.7: resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" integrity sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc= -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: +js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.13.1: - version "3.14.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" - integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" esprima "^4.0.0" @@ -3058,11 +3220,21 @@ json-buffer@3.0.0: resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= +json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -3076,9 +3248,9 @@ json5@^1.0.1: minimist "^1.2.0" json5@^2.1.2: - version "2.1.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" - integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== dependencies: minimist "^1.2.5" @@ -3089,6 +3261,11 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + kuler@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" @@ -3101,18 +3278,6 @@ latest-version@^5.0.0: dependencies: package-json "^6.3.0" -leven@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - -levenary@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" - integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== - dependencies: - leven "^3.1.0" - levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -3121,14 +3286,14 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= dependencies: graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" + parse-json "^4.0.0" + pify "^3.0.0" strip-bom "^3.0.0" locate-path@^2.0.0: @@ -3147,6 +3312,16 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + lodash.isfunction@^3.0.8, lodash.isfunction@~3.0.8: version "3.0.9" resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" @@ -3157,10 +3332,20 @@ lodash.isnumber@^3.0.3: resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= -lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.20: - version "4.17.20" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" - integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= + +lodash@^4.17.11, lodash@^4.17.20: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== logform@^2.2.0: version "2.2.0" @@ -3173,13 +3358,6 @@ logform@^2.2.0: ms "^2.1.1" triple-beam "^1.3.0" -loose-envify@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" @@ -3190,6 +3368,13 @@ lowercase-keys@^2.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + make-dir@^2.0.0, make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" @@ -3206,14 +3391,15 @@ make-dir@^3.0.0: semver "^6.0.0" mathjs@^9.3.0: - version "9.3.0" - resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-9.3.0.tgz#59cc43b536b22616197e56da303604b430daa6ac" - integrity sha512-0kYW+TXgB8lCqUj5wHR2hqAO2twSbPRelSFgRJXiwAx4nM6FrIb43Jd6XhW7sVbwYB+9HCNiyg5Kn8VYeB7ilg== + version "9.4.1" + resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-9.4.1.tgz#df86a7996513e270b55f58082d42fac4aefba68b" + integrity sha512-zAepVEfVyv4C7PM8gZ5jDzC7bZscdIcqTKsNqiqmFP+0SFHFffWT84l2v3z2zT41n9Rmdn3aWR8/bpFlnNjC6g== dependencies: - complex.js "^2.0.11" + "@babel/runtime" "^7.14.0" + complex.js "^2.0.13" decimal.js "^10.2.1" escape-latex "^1.2.0" - fraction.js "^4.0.13" + fraction.js "^4.1.1" javascript-natural-sort "^0.7.1" seedrandom "^3.0.5" tiny-emitter "^2.1.0" @@ -3243,17 +3429,17 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -mime-db@1.44.0: - version "1.44.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" - integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== +mime-db@1.48.0: + version "1.48.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.48.0.tgz#e35b31045dd7eada3aaad537ed88a33afbef2d1d" + integrity sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ== mime-types@~2.1.24: - version "2.1.27" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" - integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== + version "2.1.31" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.31.tgz#a00d76b74317c61f9c2db2218b8e9f8e9c5c9e6b" + integrity sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg== dependencies: - mime-db "1.44.0" + mime-db "1.48.0" mime@1.6.0: version "1.6.0" @@ -3270,7 +3456,7 @@ minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== -minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: +minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= @@ -3287,13 +3473,6 @@ minimist@^1.2.0, minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== -mkdirp@^0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - moment@^2.11.2, moment@^2.29.1: version "2.29.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" @@ -3309,15 +3488,20 @@ ms@2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== -ms@2.1.2, ms@^2.1.1: +ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + nan@^2.13.2: - version "2.14.1" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" - integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== + version "2.14.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" + integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== natural-compare@^1.4.0: version "1.4.0" @@ -3365,15 +3549,15 @@ node-modules-regexp@^1.0.0: resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= -node-releases@^1.1.61: - version "1.1.61" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.61.tgz#707b0fca9ce4e11783612ba4a2fcba09047af16e" - integrity sha512-DD5vebQLg8jLCOzwupn954fbIiZht05DAZs0k2u8NStSe6h9XdsuIQL8hSRKYiU8WUQRznmSDrKGbv3ObOmC7g== +node-releases@^1.1.71: + version "1.1.72" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe" + integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw== nodemon@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.4.tgz#55b09319eb488d6394aa9818148c0c2d1c04c416" - integrity sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ== + version "2.0.7" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.7.tgz#6f030a0a0ebe3ea1ba2a38f71bf9bab4841ced32" + integrity sha512-XHzK69Awgnec9UzHr1kc8EomQh4sjTQ8oRf8TsGrSmHDx9/UmiGG9E/mM3BuTfNeFwdNBvrqQq/RHL0xIeyFOA== dependencies: chokidar "^3.2.2" debug "^3.2.6" @@ -3383,8 +3567,8 @@ nodemon@^2.0.4: semver "^5.7.1" supports-color "^5.5.0" touch "^3.1.0" - undefsafe "^2.0.2" - update-notifier "^4.0.0" + undefsafe "^2.0.3" + update-notifier "^4.1.0" nopt@~1.0.10: version "1.0.10" @@ -3409,52 +3593,61 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== normalize-url@^4.1.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" - integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ== + version "4.5.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" + integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== object-hash@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.1.1.tgz#9447d0279b4fcf80cff3259bf66a1dc73afabe09" - integrity sha512-VOJmgmS+7wvXf8CjbQmimtCnEx3IAoLxI3fp2fbWehxrWBcAQFbk+vcwb6vzR0VZv/eNCJ/27j151ZTwqW/JeQ== + version "2.2.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" + integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== -object-inspect@^1.7.0, object-inspect@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" - integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== +object-inspect@^1.10.3: + version "1.10.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.10.3.tgz#c2aa7d2d09f50c99375704f7a0adf24c5782d369" + integrity sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw== object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.1.tgz#303867a666cdd41936ecdedfb1f8f3e32a478cdd" - integrity sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA== +object.assign@^4.1.0, object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== dependencies: + call-bind "^1.0.0" define-properties "^1.1.3" - es-abstract "^1.18.0-next.0" has-symbols "^1.0.1" object-keys "^1.1.1" +object.entries@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.4.tgz#43ccf9a50bc5fd5b649d45ab1a579f24e088cafd" + integrity sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.2" + object.getownpropertydescriptors@^2.0.3: - version "2.1.0" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" - integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== + version "2.1.2" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz#1bd63aeacf0d5d2d2f31b5e393b03a7c601a23f7" + integrity sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ== dependencies: + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" + es-abstract "^1.18.0-next.2" -object.values@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" - integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== +object.values@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.4.tgz#0d273762833e816b693a637d30073e7051535b30" + integrity sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg== dependencies: + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" - function-bind "^1.1.1" - has "^1.0.3" + es-abstract "^1.18.2" on-finished@~2.3.0: version "2.3.0" @@ -3549,12 +3742,13 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= dependencies: - error-ex "^1.2.0" + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" parse-passwd@^1.0.0: version "1.0.0" @@ -3582,26 +3776,26 @@ path-key@^3.1.0: integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== dependencies: - pify "^2.0.0" + pify "^3.0.0" pbkdf2@^3.0.9: - version "3.1.1" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94" - integrity sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg== + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== dependencies: create-hash "^1.1.2" create-hmac "^1.1.4" @@ -3610,14 +3804,14 @@ pbkdf2@^3.0.9: sha.js "^2.4.8" picomatch@^2.0.4, picomatch@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== - -pify@^2.0.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= pify@^4.0.1: version "4.0.1" @@ -3645,6 +3839,13 @@ pkg-dir@^3.0.0: dependencies: find-up "^3.0.0" +pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" + integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= + dependencies: + find-up "^2.1.0" + post-message-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/post-message-stream/-/post-message-stream-3.0.0.tgz#90d9f54bd209e6b6f5d74795b87588205b547048" @@ -3673,11 +3874,11 @@ progress@^2.0.0: integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== proxy-addr@^2.0.4, proxy-addr@~2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" - integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== dependencies: - forwarded "~0.1.2" + forwarded "0.2.0" ipaddr.js "1.9.1" pstree.remy@^1.1.7: @@ -3699,9 +3900,9 @@ punycode@^2.1.0: integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== pupa@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.0.1.tgz#dbdc9ff48ffbea4a26a069b6f9f7abb051008726" - integrity sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA== + version "2.1.1" + resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" + integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== dependencies: escape-goat "^2.0.0" @@ -3757,22 +3958,22 @@ rc@^1.2.8: minimist "^1.2.0" strip-json-comments "~2.0.1" -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= +read-pkg-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" + integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= dependencies: find-up "^2.0.0" - read-pkg "^2.0.0" + read-pkg "^3.0.0" -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= dependencies: - load-json-file "^2.0.0" + load-json-file "^4.0.0" normalize-package-data "^2.3.2" - path-type "^2.0.0" + path-type "^3.0.0" readable-stream@^2.1.4, readable-stream@^2.3.7: version "2.3.7" @@ -3796,10 +3997,10 @@ readable-stream@^3.4.0, readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" -readdirp@~3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.4.0.tgz#9fdccdf9e9155805449221ac645e8303ab5b9ada" - integrity sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ== +readdirp@~3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" + integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== dependencies: picomatch "^2.2.1" @@ -3811,9 +4012,9 @@ regenerate-unicode-properties@^8.2.0: regenerate "^1.4.0" regenerate@^1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f" - integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A== + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== regenerator-runtime@^0.13.4: version "0.13.7" @@ -3832,7 +4033,7 @@ regexpp@^3.0.0, regexpp@^3.1.0: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== -regexpu-core@^4.7.0: +regexpu-core@^4.7.1: version "4.7.1" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6" integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ== @@ -3845,9 +4046,9 @@ regexpu-core@^4.7.0: unicode-match-property-value-ecmascript "^1.2.0" registry-auth-token@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.0.tgz#1d37dffda72bbecd0f581e4715540213a65eb7da" - integrity sha512-P+lWzPrsgfN+UEpDS3U8AQKg/UjZX6mQSJueZj3EK+vNESoqBSpBUD3gmu4sF9lOsjXWjF11dQKUqemf3veq1w== + version "4.2.1" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" + integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw== dependencies: rc "^1.2.8" @@ -3864,22 +4065,28 @@ regjsgen@^0.5.1: integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== regjsparser@^0.6.4: - version "0.6.4" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" - integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== + version "0.6.9" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.9.tgz#b489eef7c9a2ce43727627011429cf833a7183e6" + integrity sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ== dependencies: jsesc "~0.5.0" +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.10.0, resolve@^1.10.1, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2: - version "1.17.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" - integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== +resolve@^1.10.0, resolve@^1.10.1, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.20.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== dependencies: + is-core-module "^2.2.0" path-parse "^1.0.6" responselike@^1.0.2: @@ -3889,10 +4096,10 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" @@ -3945,7 +4152,7 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: +"semver@2 || 3 || 4 || 5", semver@^5.6.0, semver@^5.7.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -3955,15 +4162,17 @@ semver@7.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== -semver@^6.0.0, semver@^6.1.0, semver@^6.2.0, semver@^6.3.0: +semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== semver@^7.2.1: - version "7.3.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" - integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" send@0.17.1: version "0.17.1" @@ -4007,6 +4216,13 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -4031,14 +4247,14 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" source-map-support@^0.5.16: version "0.5.19" @@ -4080,9 +4296,9 @@ spdx-expression-parse@^3.0.0: spdx-license-ids "^3.0.0" spdx-license-ids@^3.0.0: - version "3.0.6" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz#c80757383c28abf7296744998cbc106ae8b854ce" - integrity sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw== + version "3.0.9" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz#8a595135def9592bda69709474f1cbeea7c2467f" + integrity sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ== sprintf-js@~1.0.2: version "1.0.3" @@ -4108,30 +4324,30 @@ string-width@^3.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.0.0, string-width@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" - integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== +string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0: + version "4.2.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" + integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string.prototype.trimend@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" - integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== dependencies: + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.17.5" -string.prototype.trimstart@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" - integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== dependencies: + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.17.5" string_decoder@^1.1.1: version "1.3.0" @@ -4190,20 +4406,22 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== +table@^6.0.9: + version "6.7.1" + resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2" + integrity sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg== dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" + ajv "^8.0.1" + lodash.clonedeep "^4.5.0" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.0" + strip-ansi "^6.0.0" term-size@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753" - integrity sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw== + version "2.2.1" + resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" + integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== text-hex@1.0.x: version "1.0.0" @@ -4226,9 +4444,9 @@ tiny-invariant@^1.1.0: integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== tiny-secp256k1@^1.1.3: - version "1.1.5" - resolved "https://registry.yarnpkg.com/tiny-secp256k1/-/tiny-secp256k1-1.1.5.tgz#3dc37b9bf0fa5b4390b9fa29e953228810cebc18" - integrity sha512-duE2hSLSQIpHGzmK48OgRrGTi+4OTkXLC6aa86uOYQ6LLCYZSarVKIAvEtY7MoXjoL6bOXMSerEGMzrvW4SkDw== + version "1.1.6" + resolved "https://registry.yarnpkg.com/tiny-secp256k1/-/tiny-secp256k1-1.1.6.tgz#7e224d2bee8ab8283f284e40e6b4acb74ffe047c" + integrity sha512-FmqJZGduTyvsr2cF3375fqGHUovSwDi/QytexX1Se4BPuPZpTE5Ftp5fg+EFSuEf3lhZqgCRjEG3ydUQ/aNiwA== dependencies: bindings "^1.3.0" bn.js "^4.11.8" @@ -4241,6 +4459,13 @@ tiny-warning@^1.0.3: resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== +tmp@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -4297,6 +4522,11 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + type-fest@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" @@ -4327,7 +4557,17 @@ typeforce@^1.11.5: resolved "https://registry.yarnpkg.com/typeforce/-/typeforce-1.18.0.tgz#d7416a2c5845e085034d70fcc5b6cc4a90edbfdc" integrity sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g== -undefsafe@^2.0.2: +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + +undefsafe@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae" integrity sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A== @@ -4369,10 +4609,10 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= -update-notifier@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.1.tgz#895fc8562bbe666179500f9f2cebac4f26323746" - integrity sha512-9y+Kds0+LoLG6yN802wVXoIfxYEwh3FlZwzMwpCZp62S2i1/Jzeqb9Eeeju3NSHccGGasfGlK5/vEHbAifYRDg== +update-notifier@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3" + integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A== dependencies: boxen "^4.2.0" chalk "^3.0.0" @@ -4389,9 +4629,9 @@ update-notifier@^4.0.0: xdg-basedir "^4.0.0" uri-js@^4.2.2: - version "4.4.0" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602" - integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g== + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" @@ -4402,15 +4642,22 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" +utf-8-validate@^5.0.2: + version "5.0.5" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.5.tgz#dd32c2e82c72002dc9f02eb67ba6761f43456ca1" + integrity sha512-+pnxRYsS/axEpkrrEpzYfNZGXp0IjC/9RIxwM5gntY4Koi8SHmUGSfxfWqxZdRxrtaoVstuOzUp/rbs3JSPELQ== + dependencies: + node-gyp-build "^4.2.0" + util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= util@^0.12.3: - version "0.12.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.12.3.tgz#971bb0292d2cc0c892dab7c6a5d37c2bec707888" - integrity sha512-I8XkoQwE+fPQEhy9v012V+TSdH2kp9ts29i20TaaDUXsg7x/onePbhFJUExBfv/2ay1ZOp/Vsm3nDlmnFGSAog== + version "0.12.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253" + integrity sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw== dependencies: inherits "^2.0.3" is-arguments "^1.0.4" @@ -4425,9 +4672,9 @@ utils-merge@1.0.1: integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= v8-compile-cache@^2.0.3: - version "2.1.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" - integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ== + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== v8flags@^3.1.1: version "3.2.0" @@ -4450,17 +4697,29 @@ vary@~1.1.2: integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= whatwg-fetch@>=0.10.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.4.1.tgz#e5f871572d6879663fa5674c8f833f15a8425ab3" - integrity sha512-sofZVzE1wKwO+EYPbWfiwzaKovWiZXf4coEzjGP9b2GBVgQRLQUZ2QcuPpQExGDAW5GItpEm6Tl4OU5mywnAoQ== + version "3.6.2" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz#dced24f37f2624ed0281725d51d0e2e3fe677f8c" + integrity sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA== + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" which-typed-array@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.2.tgz#e5f98e56bda93e3dac196b01d47c1156679c00b2" - integrity sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ== + version "1.1.4" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.4.tgz#8fcb7d3ee5adf2d771066fba7cf37e32fe8711ff" + integrity sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA== dependencies: available-typed-arrays "^1.0.2" - es-abstract "^1.17.5" + call-bind "^1.0.0" + es-abstract "^1.18.0-next.1" foreach "^2.0.5" function-bind "^1.1.1" has-symbols "^1.0.1" @@ -4488,16 +4747,16 @@ wif@^2.0.6: bs58check "<3.0.0" winston-daily-rotate-file@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/winston-daily-rotate-file/-/winston-daily-rotate-file-4.5.0.tgz#3914ac57c4bdae1138170bec85af0c2217b253b1" - integrity sha512-/HqeWiU48dzGqcrABRlxYWVMdL6l3uKCtFSJyrqK+E2rLnSFNsgYpvwx15EgTitBLNzH69lQd/+z2ASryV2aqw== + version "4.5.5" + resolved "https://registry.yarnpkg.com/winston-daily-rotate-file/-/winston-daily-rotate-file-4.5.5.tgz#cfa3a89f4eb0e4126917592b375759b772bcd972" + integrity sha512-ds0WahIjiDhKCiMXmY799pDBW+58ByqIBtUcsqr4oDoXrAI3Zn+hbgFdUxzMfqA93OG0mPLYVMiotqTgE/WeWQ== dependencies: file-stream-rotator "^0.5.7" object-hash "^2.0.1" triple-beam "^1.3.0" - winston-transport "^4.2.0" + winston-transport "^4.4.0" -winston-transport@^4.2.0, winston-transport@^4.4.0: +winston-transport@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.4.0.tgz#17af518daa690d5b2ecccaa7acf7b20ca7925e59" integrity sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw== @@ -4540,19 +4799,17 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - -ws@7.2.3: - version "7.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46" - integrity sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ== +ws@7.4.6, ws@^7.3.1: + version "7.4.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== xdg-basedir@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== From fa6fad0efb7c8ab2ba9948f1ae6b0ff9e8b143a8 Mon Sep 17 00:00:00 2001 From: james-hummingbot Date: Thu, 3 Jun 2021 13:20:05 +0200 Subject: [PATCH 3/7] Ignore node_modules --- .eslintignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index 0980665..3950c73 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,2 @@ # turn off specific file for eslint -/*.js \ No newline at end of file +/node_modules \ No newline at end of file From 5696dc6e6cb4ceee2988e86c61a5348dfcd95803 Mon Sep 17 00:00:00 2001 From: james-hummingbot Date: Thu, 3 Jun 2021 14:46:43 +0200 Subject: [PATCH 4/7] Apply prettier --- .babelrc | 6 +- .editorconfig | 13 + .eslintrc.js | 12 +- .prettierignore | 4 + .prettierrc | 6 + package.json | 5 +- src/app.js | 80 +-- src/index.js | 92 ++-- src/routes/balancer.route.js | 358 +++++++------ src/routes/celo.route.js | 247 ++++----- src/routes/eth.route.js | 409 ++++++++------- src/routes/index.route.js | 14 +- src/routes/perpetual_finance.route.js | 478 +++++++++-------- src/routes/terra.route.js | 257 +++++----- src/routes/uniswap.route.js | 351 +++++++------ src/routes/uniswap_v3.route.js | 500 ++++++++++-------- src/services/access.js | 28 +- src/services/balancer.js | 246 +++++---- src/services/eth.js | 207 ++++---- src/services/fees.js | 80 +-- src/services/logger.js | 44 +- src/services/perpetual_finance.js | 452 ++++++++++------ src/services/terra.js | 439 ++++++++-------- src/services/uniswap.js | 302 ++++++----- src/services/uniswap_v3.js | 477 ++++++++++------- src/services/utils.js | 146 +++--- src/static/abi.js | 594 ++++++++++++++-------- src/static/uniswap-v3/helper_functions.js | 204 +++++--- src/static/uniswap_route_tokens.json | 87 +++- yarn.lock | 29 ++ 30 files changed, 3581 insertions(+), 2586 deletions(-) create mode 100644 .editorconfig create mode 100644 .prettierignore create mode 100644 .prettierrc diff --git a/.babelrc b/.babelrc index cedf24f..1320b9a 100644 --- a/.babelrc +++ b/.babelrc @@ -1,5 +1,3 @@ { - "presets": [ - "@babel/preset-env" - ] -} \ No newline at end of file + "presets": ["@babel/preset-env"] +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..b4e3016 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# Editor configuration, see http://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 08ab3f8..7d65f3a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,7 +1,8 @@ module.exports = { - extends: 'airbnb-base', + extends: ['airbnb-base', 'eslint:recommended', 'prettier'], + plugins: ['prettier'], env: { - node: true, + node: true }, rules: { camelcase: 'off', @@ -25,6 +26,7 @@ module.exports = { 'no-unused-vars': ['error', { argsIgnorePattern: '^_' }], 'no-underscore-dangle': 'off', 'prefer-destructuring': 'off', - radix: 'off', - }, -}; + 'prettier/prettier': 'error', + radix: 'off' + } +} diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..b4d36e3 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +test +certs +*.md +*.yml \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..0d1aa74 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "trailingComma": "none", + "semi": false, + "singleQuote": true, + "tabWidth": 2 +} diff --git a/package.json b/package.json index 357e1aa..02f1555 100644 --- a/package.json +++ b/package.json @@ -49,12 +49,15 @@ "@babel/preset-env": "^7.14.1", "eslint": "^7.25.0", "eslint-config-airbnb-base": "^14.2.1", + "eslint-config-prettier": "^8.3.0", "eslint-config-standard": "^14.1.1", "eslint-plugin-import": "^2.23.3", "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^3.4.0", "eslint-plugin-promise": "^4.2.1", "eslint-plugin-standard": "^4.0.1", - "nodemon": "^2.0.4" + "nodemon": "^2.0.4", + "prettier": "^2.3.0" }, "engines": { "node": "10.x" diff --git a/src/app.js b/src/app.js index 218e669..811c3f8 100644 --- a/src/app.js +++ b/src/app.js @@ -1,69 +1,69 @@ -import dotenv from 'dotenv'; -import bodyParser from 'body-parser'; -import express from 'express'; -import helmet from 'helmet'; -import { IpFilter } from 'express-ipfilter'; -import { statusMessages } from './services/utils'; -import { validateAccess } from './services/access'; -import { logger } from './services/logger'; +import dotenv from 'dotenv' +import bodyParser from 'body-parser' +import express from 'express' +import helmet from 'helmet' +import { IpFilter } from 'express-ipfilter' +import { statusMessages } from './services/utils' +import { validateAccess } from './services/access' +import { logger } from './services/logger' // Routes -import apiRoutes from './routes/index.route'; -import balancerRoutes from './routes/balancer.route'; -import ethRoutes from './routes/eth.route'; -import terraRoutes from './routes/terra.route'; -import uniswapRoutes from './routes/uniswap.route'; -import uniswapV3Routes from './routes/uniswap_v3.route'; -import perpFiRoutes from './routes/perpetual_finance.route'; +import apiRoutes from './routes/index.route' +import balancerRoutes from './routes/balancer.route' +import ethRoutes from './routes/eth.route' +import terraRoutes from './routes/terra.route' +import uniswapRoutes from './routes/uniswap.route' +import uniswapV3Routes from './routes/uniswap_v3.route' +import perpFiRoutes from './routes/perpetual_finance.route' // terminate if environment not found -const result = dotenv.config(); +const result = dotenv.config() if (result.error) { - logger.error(result.error); - process.exit(1); + logger.error(result.error) + process.exit(1) } // create app -const app = express(); +const app = express() // middleware // #security: remove response headers from middleware // https://www.npmjs.com/package/helmet -app.use(helmet()); +app.use(helmet()) -const ipWhitelist = process.env.IP_WHITELIST; +const ipWhitelist = process.env.IP_WHITELIST if (ipWhitelist) { - app.use(IpFilter(JSON.parse(ipWhitelist), { mode: 'allow' })); + app.use(IpFilter(JSON.parse(ipWhitelist), { mode: 'allow' })) } -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ extended: true })); +app.use(bodyParser.json()) +app.use(bodyParser.urlencoded({ extended: true })) -app.use(validateAccess); +app.use(validateAccess) // mount routes to specific path -app.use('/api', apiRoutes); -app.use('/eth', ethRoutes); -app.use('/eth/uniswap', uniswapRoutes); -app.use('/eth/uniswap/v3', uniswapV3Routes); -app.use('/eth/balancer', balancerRoutes); -app.use('/terra', terraRoutes); -app.use('/perpfi', perpFiRoutes); +app.use('/api', apiRoutes) +app.use('/eth', ethRoutes) +app.use('/eth/uniswap', uniswapRoutes) +app.use('/eth/uniswap/v3', uniswapV3Routes) +app.use('/eth/balancer', balancerRoutes) +app.use('/terra', terraRoutes) +app.use('/perpfi', perpFiRoutes) // app.use('/celo', celoRoutes); app.get('/', (req, res, _next) => { - res.send('ok'); -}); + res.send('ok') +}) /** * Catch all 404 response when routes are not found */ app.use((req, res, _next) => { - const message = `${statusMessages.page_not_found} at ${req.originalUrl}`; - logger.error(message); + const message = `${statusMessages.page_not_found} at ${req.originalUrl}` + logger.error(message) res.status(404).send({ error: 'Page not found', - message, - }); -}); + message + }) +}) -export default app; +export default app diff --git a/src/index.js b/src/index.js index 4e977dd..f7480db 100644 --- a/src/index.js +++ b/src/index.js @@ -1,93 +1,97 @@ #!/usr/bin/env node // absolute imports -import https from 'https'; -import dotenv from 'dotenv'; -import fs from 'fs'; +import https from 'https' +import dotenv from 'dotenv' +import fs from 'fs' // relative imports -import app from './app'; -import { logger } from './services/logger'; +import app from './app' +import { logger } from './services/logger' // terminate if environment not found -const result = dotenv.config(); +const result = dotenv.config() if (result.error) { - logger.info(result.error); - process.exit(1); + logger.info(result.error) + process.exit(1) } -const env = process.env.NODE_ENV; -const port = process.env.PORT; -const certPassphrase = process.env.CERT_PASSPHRASE; -const ethereumChain = process.env.ETHEREUM_CHAIN; -const terraChain = process.env.TERRA_CHAIN; -let certPath = process.env.CERT_PATH; +const env = process.env.NODE_ENV +const port = process.env.PORT +const certPassphrase = process.env.CERT_PASSPHRASE +const ethereumChain = process.env.ETHEREUM_CHAIN +const terraChain = process.env.TERRA_CHAIN +let certPath = process.env.CERT_PATH if ((typeof certPath === 'undefined' && certPath == null) || certPath === '') { // assuming it is local development using test script to generate certs - certPath = './certs'; + certPath = './certs' } else { - certPath = certPath.replace(/\/$/, ''); + certPath = certPath.replace(/\/$/, '') } // set app environment -app.set('env', env); +app.set('env', env) const options = { - key: fs.readFileSync(certPath.concat('/server_key.pem'), { encoding: 'utf-8' }), - cert: fs.readFileSync(certPath.concat('/server_cert.pem'), { encoding: 'utf-8' }), + key: fs.readFileSync(certPath.concat('/server_key.pem'), { + encoding: 'utf-8' + }), + cert: fs.readFileSync(certPath.concat('/server_cert.pem'), { + encoding: 'utf-8' + }), // request client certificate from user requestCert: true, // reject requests with no valid certificate rejectUnauthorized: true, // use ca cert created with own key for self-signed ca: [fs.readFileSync(certPath.concat('/ca_cert.pem'), { encoding: 'utf-8' })], - passphrase: certPassphrase, -}; + passphrase: certPassphrase +} -const server = https.createServer(options, app); +const server = https.createServer(options, app) // event listener for "error" event const onError = (error) => { if (error.syscall !== 'listen') { - throw error; + throw error } - const bind = typeof port === 'string' ? `Pipe ${port}` : `Port ${port}`; + const bind = typeof port === 'string' ? `Pipe ${port}` : `Port ${port}` // handle specific listen errors with friendly messages switch (error.code) { case 'EACCES': - console.error(`${bind} requires elevated privileges`); - process.exit(1); - break; + console.error(`${bind} requires elevated privileges`) + process.exit(1) + break case 'EADDRINUSE': - console.error(`${bind} is already in use`); - process.exit(1); - break; + console.error(`${bind} is already in use`) + process.exit(1) + break default: - throw error; + throw error } -}; +} // event listener for "listening" event. const onListening = () => { - const addr = server.address(); - const bind = typeof addr === 'string' ? `pipe ${addr}` : `port ${addr.port}`; - console.log(`listening on ${bind}`); - logger.debug(`listening on ${bind}`); -}; + const addr = server.address() + const bind = typeof addr === 'string' ? `pipe ${addr}` : `port ${addr.port}` + console.log(`listening on ${bind}`) + logger.debug(`listening on ${bind}`) +} // listen on provided port, on all network interfaces. -server.listen(port); -server.on('error', onError); -server.on('listening', onListening); +server.listen(port) +server.on('error', onError) +server.on('listening', onListening) const serverConfig = { app: 'gateway-api', port, ethereumChain, - terraChain, -}; + terraChain +} -logger.info(JSON.stringify(serverConfig)); -console.log(serverConfig); +logger.info(JSON.stringify(serverConfig)) +console.log(serverConfig) diff --git a/src/routes/balancer.route.js b/src/routes/balancer.route.js index 358bd9d..ddc17e6 100644 --- a/src/routes/balancer.route.js +++ b/src/routes/balancer.route.js @@ -1,30 +1,28 @@ -import BigNumber from 'bignumber.js'; -import { ethers } from 'ethers'; -import express from 'express'; +import BigNumber from 'bignumber.js' +import { ethers } from 'ethers' +import express from 'express' -import { - getParamData, latency, statusMessages, -} from '../services/utils'; +import { getParamData, latency, statusMessages } from '../services/utils' -import Ethereum from '../services/eth'; -import Balancer from '../services/balancer'; -import Fees from '../services/fees'; -import { logger } from '../services/logger'; +import Ethereum from '../services/eth' +import Balancer from '../services/balancer' +import Fees from '../services/fees' +import { logger } from '../services/logger' -const debug = require('debug')('router'); +const debug = require('debug')('router') -const router = express.Router(); -const eth = new Ethereum(process.env.ETHEREUM_CHAIN); -const balancer = new Balancer(process.env.ETHEREUM_CHAIN); -const fees = new Fees(); +const router = express.Router() +const eth = new Ethereum(process.env.ETHEREUM_CHAIN) +const balancer = new Balancer(process.env.ETHEREUM_CHAIN) +const fees = new Fees() -const swapMoreThanMaxPriceError = 'Price too high'; -const swapLessThanMaxPriceError = 'Price too low'; +const swapMoreThanMaxPriceError = 'Price too high' +const swapLessThanMaxPriceError = 'Price too low' const estimateGasLimit = (maxswaps) => { - const gasLimit = balancer.gasBase + maxswaps * balancer.gasPerSwap; - return gasLimit; -}; + const gasLimit = balancer.gasBase + maxswaps * balancer.gasPerSwap + return gasLimit +} router.post('/', async (req, res) => { /* @@ -36,9 +34,9 @@ router.post('/', async (req, res) => { exchangeProxy: balancer.exchangeProxy, subgraphUrl: balancer.subgraphUrl, connection: true, - timestamp: Date.now(), - }); -}); + timestamp: Date.now() + }) +}) router.post('/gas-limit', async (req, res) => { /* @@ -47,28 +45,33 @@ router.post('/gas-limit', async (req, res) => { "maxSwaps":4 } */ - const paramData = getParamData(req.body); + const paramData = getParamData(req.body) try { - const swaps = paramData.maxSwaps; - const maxSwaps = typeof swaps === 'undefined' || parseInt(swaps) === 0 ? balancer.maxSwaps : parseInt(swaps); - const gasLimit = estimateGasLimit(maxSwaps); + const swaps = paramData.maxSwaps + const maxSwaps = + typeof swaps === 'undefined' || parseInt(swaps) === 0 + ? balancer.maxSwaps + : parseInt(swaps) + const gasLimit = estimateGasLimit(maxSwaps) res.status(200).json({ network: balancer.network, gasLimit, - timestamp: Date.now(), - }); + timestamp: Date.now() + }) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.get('/start', async (req, res) => { /* @@ -78,39 +81,51 @@ router.get('/start', async (req, res) => { "gasPrice":30 } */ - const initTime = Date.now(); - const paramData = getParamData(req.query); - const pairs = JSON.parse(paramData.pairs); - let gasPrice; + const initTime = Date.now() + const paramData = getParamData(req.query) + const pairs = JSON.parse(paramData.pairs) + let gasPrice if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice); + gasPrice = parseFloat(paramData.gasPrice) } else { - gasPrice = fees.ethGasPrice; + gasPrice = fees.ethGasPrice } // get token contract address and cache pools for (let pair of pairs) { - pair = pair.split('-'); - const baseTokenSymbol = pair[0]; - const quoteTokenSymbol = pair[1]; - const baseTokenContractInfo = eth.getERC20TokenAddresses(baseTokenSymbol); - const quoteTokenContractInfo = eth.getERC20TokenAddresses(quoteTokenSymbol); + pair = pair.split('-') + const baseTokenSymbol = pair[0] + const quoteTokenSymbol = pair[1] + const baseTokenContractInfo = eth.getERC20TokenAddresses(baseTokenSymbol) + const quoteTokenContractInfo = eth.getERC20TokenAddresses(quoteTokenSymbol) // check for valid token symbols - if (baseTokenContractInfo === undefined || quoteTokenContractInfo === undefined) { - const undefinedToken = baseTokenContractInfo === undefined ? baseTokenSymbol : quoteTokenSymbol; + if ( + baseTokenContractInfo === undefined || + quoteTokenContractInfo === undefined + ) { + const undefinedToken = + baseTokenContractInfo === undefined ? baseTokenSymbol : quoteTokenSymbol res.status(500).json({ error: `Token ${undefinedToken} contract address not found`, - message: `Token contract address not found for ${undefinedToken}. Check token list source`, - }); - return; + message: `Token contract address not found for ${undefinedToken}. Check token list source` + }) + return } - await Promise.allSettled([balancer.fetchPool(baseTokenContractInfo.address, quoteTokenContractInfo.address), - balancer.fetchPool(quoteTokenContractInfo.address, baseTokenContractInfo.address)]); + await Promise.allSettled([ + balancer.fetchPool( + baseTokenContractInfo.address, + quoteTokenContractInfo.address + ), + balancer.fetchPool( + quoteTokenContractInfo.address, + baseTokenContractInfo.address + ) + ]) } - const gasLimit = estimateGasLimit(balancer.maxSwaps); - const gasCost = await fees.getGasCost(gasPrice, gasLimit); + const gasLimit = estimateGasLimit(balancer.maxSwaps) + const gasCost = await fees.getGasCost(gasPrice, gasLimit) const result = { network: eth.network, @@ -120,11 +135,11 @@ router.get('/start', async (req, res) => { pairs, gasPrice, gasLimit, - gasCost, - }; - console.log('Initializing balancer'); - res.status(200).json(result); -}); + gasCost + } + console.log('Initializing balancer') + res.status(200).json(result) +}) router.post('/price', async (req, res) => { /* @@ -136,48 +151,51 @@ router.post('/price', async (req, res) => { "side":buy } */ - const initTime = Date.now(); + const initTime = Date.now() // params: base (required), quote (required), amount (required) - const paramData = getParamData(req.body); - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base); - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote); - const baseTokenAddress = baseTokenContractInfo.address; - const quoteTokenAddress = quoteTokenContractInfo.address; - const baseDenomMultiplier = 10 ** baseTokenContractInfo.decimals; - const quoteDenomMultiplier = 10 ** quoteTokenContractInfo.decimals; - const amount = new BigNumber(parseInt(paramData.amount * baseDenomMultiplier)); - const maxSwaps = balancer.maxSwaps; - const side = paramData.side.toUpperCase(); - let gasPrice; + const paramData = getParamData(req.body) + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base) + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote) + const baseTokenAddress = baseTokenContractInfo.address + const quoteTokenAddress = quoteTokenContractInfo.address + const baseDenomMultiplier = 10 ** baseTokenContractInfo.decimals + const quoteDenomMultiplier = 10 ** quoteTokenContractInfo.decimals + const amount = new BigNumber(parseInt(paramData.amount * baseDenomMultiplier)) + const maxSwaps = balancer.maxSwaps + const side = paramData.side.toUpperCase() + let gasPrice if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice); + gasPrice = parseFloat(paramData.gasPrice) } else { - gasPrice = fees.ethGasPrice; + gasPrice = fees.ethGasPrice } try { // fetch the optimal pool mix from balancer-sor - const { swaps, expectedAmount } = side === 'BUY' - ? await balancer.priceSwapOut( - quoteTokenAddress, // tokenIn is quote asset - baseTokenAddress, // tokenOut is base asset - amount, - maxSwaps, - ) - : await balancer.priceSwapIn( - baseTokenAddress, // tokenIn is base asset - quoteTokenAddress, // tokenOut is quote asset - amount, - maxSwaps, - ); + const { swaps, expectedAmount } = + side === 'BUY' + ? await balancer.priceSwapOut( + quoteTokenAddress, // tokenIn is quote asset + baseTokenAddress, // tokenOut is base asset + amount, + maxSwaps + ) + : await balancer.priceSwapIn( + baseTokenAddress, // tokenIn is base asset + quoteTokenAddress, // tokenOut is quote asset + amount, + maxSwaps + ) if (swaps != null && expectedAmount != null) { - const gasLimit = estimateGasLimit(swaps.length); - const gasCost = await fees.getGasCost(gasPrice, gasLimit); + const gasLimit = estimateGasLimit(swaps.length) + const gasCost = await fees.getGasCost(gasPrice, gasLimit) - const tradeAmount = parseFloat(amount); - const expectedTradeAmount = parseInt(expectedAmount) / quoteDenomMultiplier; - const tradePrice = expectedAmount / amount * baseDenomMultiplier / quoteDenomMultiplier; + const tradeAmount = parseFloat(amount) + const expectedTradeAmount = + parseInt(expectedAmount) / quoteDenomMultiplier + const tradePrice = + ((expectedAmount / amount) * baseDenomMultiplier) / quoteDenomMultiplier const result = { network: balancer.network, @@ -192,26 +210,31 @@ router.post('/price', async (req, res) => { gasPrice, gasLimit, gasCost, - swaps, - }; - debug(`Price ${side} ${baseTokenContractInfo.symbol}-${quoteTokenContractInfo.symbol} | amount:${amount} (rate:${tradePrice}) - gasPrice:${gasPrice} gasLimit:${gasLimit} estimated fee:${gasCost} ETH`); - res.status(200).json(result); - } else { // no pool available + swaps + } + debug( + `Price ${side} ${baseTokenContractInfo.symbol}-${quoteTokenContractInfo.symbol} | amount:${amount} (rate:${tradePrice}) - gasPrice:${gasPrice} gasLimit:${gasLimit} estimated fee:${gasCost} ETH` + ) + res.status(200).json(result) + } else { + // no pool available res.status(200).json({ info: statusMessages.no_pool_available, - message: statusMessages.no_pool_available, - }); + message: statusMessages.no_pool_available + }) } } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/trade', async (req, res) => { /* @@ -226,55 +249,57 @@ router.post('/trade', async (req, res) => { "privateKey":{{privateKey}} } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - const wallet = new ethers.Wallet(privateKey, balancer.provider); + const initTime = Date.now() + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + const wallet = new ethers.Wallet(privateKey, balancer.provider) - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base); - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote); - const baseTokenAddress = baseTokenContractInfo.address; - const quoteTokenAddress = quoteTokenContractInfo.address; - const baseDenomMultiplier = 10 ** baseTokenContractInfo.decimals; - const quoteDenomMultiplier = 10 ** quoteTokenContractInfo.decimals; - const amount = new BigNumber(parseInt(paramData.amount * baseDenomMultiplier)); + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base) + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote) + const baseTokenAddress = baseTokenContractInfo.address + const quoteTokenAddress = quoteTokenContractInfo.address + const baseDenomMultiplier = 10 ** baseTokenContractInfo.decimals + const quoteDenomMultiplier = 10 ** quoteTokenContractInfo.decimals + const amount = new BigNumber(parseInt(paramData.amount * baseDenomMultiplier)) - const maxSwaps = balancer.maxSwaps; - const side = paramData.side.toUpperCase(); + const maxSwaps = balancer.maxSwaps + const side = paramData.side.toUpperCase() - let limitPrice; + let limitPrice if (paramData.limitPrice) { - limitPrice = parseFloat(paramData.limitPrice); + limitPrice = parseFloat(paramData.limitPrice) } - let gasPrice; + let gasPrice if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice); + gasPrice = parseFloat(paramData.gasPrice) } else { - gasPrice = fees.ethGasPrice; + gasPrice = fees.ethGasPrice } try { // fetch the optimal pool mix from balancer-sor - const { swaps, expectedAmount } = side === 'BUY' - ? await balancer.priceSwapOut( - quoteTokenAddress, // tokenIn is quote asset - baseTokenAddress, // tokenOut is base asset - amount, - maxSwaps, - ) - : await balancer.priceSwapIn( - baseTokenAddress, // tokenIn is base asset - quoteTokenAddress, // tokenOut is quote asset - amount, - maxSwaps, - ); + const { swaps, expectedAmount } = + side === 'BUY' + ? await balancer.priceSwapOut( + quoteTokenAddress, // tokenIn is quote asset + baseTokenAddress, // tokenOut is base asset + amount, + maxSwaps + ) + : await balancer.priceSwapIn( + baseTokenAddress, // tokenIn is base asset + quoteTokenAddress, // tokenOut is quote asset + amount, + maxSwaps + ) - const gasLimit = estimateGasLimit(swaps.length); - const gasCost = await fees.getGasCost(gasPrice, gasLimit); + const gasLimit = estimateGasLimit(swaps.length) + const gasCost = await fees.getGasCost(gasPrice, gasLimit) if (side === 'BUY') { - const price = expectedAmount / amount * baseDenomMultiplier / quoteDenomMultiplier; - logger.info(`Price: ${price.toString()}`); + const price = + ((expectedAmount / amount) * baseDenomMultiplier) / quoteDenomMultiplier + logger.info(`Price: ${price.toString()}`) if (!limitPrice || price <= limitPrice) { // pass swaps to exchange-proxy to complete trade const tx = await balancer.swapExactOut( @@ -283,8 +308,8 @@ router.post('/trade', async (req, res) => { quoteTokenAddress, // tokenIn is quote asset baseTokenAddress, // tokenOut is base asset expectedAmount.toString(), - gasPrice, - ); + gasPrice + ) // submit response res.status(200).json({ @@ -299,21 +324,22 @@ router.post('/trade', async (req, res) => { gasPrice, gasLimit, gasCost, - txHash: tx.hash, - }); + txHash: tx.hash + }) } else { res.status(200).json({ error: swapMoreThanMaxPriceError, - message: `Swap price ${price} exceeds limitPrice ${limitPrice}`, - }); - debug(`Swap price ${price} exceeds limitPrice ${limitPrice}`); + message: `Swap price ${price} exceeds limitPrice ${limitPrice}` + }) + debug(`Swap price ${price} exceeds limitPrice ${limitPrice}`) } } else { // sell - const minAmountOut = limitPrice / amount * baseDenomMultiplier; - debug('minAmountOut', minAmountOut); - const price = expectedAmount / amount * baseDenomMultiplier / quoteDenomMultiplier; - logger.info(`Price: ${price.toString()}`); + const minAmountOut = (limitPrice / amount) * baseDenomMultiplier + debug('minAmountOut', minAmountOut) + const price = + ((expectedAmount / amount) * baseDenomMultiplier) / quoteDenomMultiplier + logger.info(`Price: ${price.toString()}`) if (!limitPrice || price >= limitPrice) { // pass swaps to exchange-proxy to complete trade const tx = await balancer.swapExactIn( @@ -323,8 +349,8 @@ router.post('/trade', async (req, res) => { quoteTokenAddress, // tokenOut is quote asset amount.toString(), parseInt(expectedAmount) / quoteDenomMultiplier, - gasPrice, - ); + gasPrice + ) // submit response res.status(200).json({ network: balancer.network, @@ -338,25 +364,27 @@ router.post('/trade', async (req, res) => { gasPrice, gasLimit, gasCost, - txHash: tx.hash, - }); + txHash: tx.hash + }) } else { res.status(200).json({ error: swapLessThanMaxPriceError, - message: `Swap price ${price} lower than limitPrice ${limitPrice}`, - }); - debug(`Swap price ${price} lower than limitPrice ${limitPrice}`); + message: `Swap price ${price} lower than limitPrice ${limitPrice}` + }) + debug(`Swap price ${price} lower than limitPrice ${limitPrice}`) } } } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) -export default router; +export default router diff --git a/src/routes/celo.route.js b/src/routes/celo.route.js index f305edc..0581c4c 100644 --- a/src/routes/celo.route.js +++ b/src/routes/celo.route.js @@ -1,171 +1,177 @@ -const express = require('express'); +const express = require('express') -const router = express.Router(); -const BigNumber = require('bignumber.js'); -const debug = require('debug')('router'); -const spawn = require('child_process').spawn; +const router = express.Router() +const BigNumber = require('bignumber.js') +const debug = require('debug')('router') +const spawn = require('child_process').spawn -const network = 'celo'; -const celocli = 'celocli'; -const DENOM_UNIT_MULTIPLIER = BigNumber('1e+18'); +const network = 'celo' +const celocli = 'celocli' +const DENOM_UNIT_MULTIPLIER = BigNumber('1e+18') -const hbUtils = require('../services/utils'); +const hbUtils = require('../services/utils') -const separator = '=>'; +const separator = '=>' router.use((req, res, next) => { - debug('celo route:', Date.now()); - next(); -}); + debug('celo route:', Date.now()) + next() +}) router.get('/', (req, res) => { - res.status(200).send(network); -}); + res.status(200).send(network) +}) router.get('/status', (req, res) => { /* return if the celocli ultralight node is synced */ - const nodeSync = spawn(celocli, ['node:synced']); + const nodeSync = spawn(celocli, ['node:synced']) - const err_message = []; const - out_message = []; + const err_message = [] + const out_message = [] nodeSync.stdout.on('data', (out) => { - out_message.push(out.toString().trim()); - debug('out_message', out_message); - }); + out_message.push(out.toString().trim()) + debug('out_message', out_message) + }) nodeSync.stderr.on('data', (err) => { - err_message.push(err.toString().trim()); - debug('err_message', err_message); - }); + err_message.push(err.toString().trim()) + debug('err_message', err_message) + }) nodeSync.on('close', (code) => { if (code === 0) { res.status(200).json({ synced: out_message[0].toLowerCase() === 'true', - message: err_message.join(''), - }); + message: err_message.join('') + }) } else { res.status(401).json({ - error: err_message.join(''), - }); + error: err_message.join('') + }) } - }); -}); + }) +}) router.get('/price', (req, res) => { /* api request format: /price?trading_pair=CELO-CUSD&trade_type=sell&amount=1.2345 */ - const keyFormat = ['trading_pair', 'trade_type', 'amount']; + const keyFormat = ['trading_pair', 'trade_type', 'amount'] - const initTime = Date.now(); + const initTime = Date.now() - const paramData = hbUtils.getParamData(req.query, keyFormat); - const tradingPair = paramData.trading_pair; - const requestAmount = paramData.amount; - const amount = parseFloat(requestAmount) * DENOM_UNIT_MULTIPLIER; - debug('params', req.params); - debug('paramData', paramData); + const paramData = hbUtils.getParamData(req.query, keyFormat) + const tradingPair = paramData.trading_pair + const requestAmount = paramData.amount + const amount = parseFloat(requestAmount) * DENOM_UNIT_MULTIPLIER + debug('params', req.params) + debug('paramData', paramData) - const nodeSync = spawn(celocli, ['exchange:show', '--amount', amount]); + const nodeSync = spawn(celocli, ['exchange:show', '--amount', amount]) - const err_message = []; const - out_message = []; + const err_message = [] + const out_message = [] nodeSync.stdout.on('data', (out) => { - out_message.push(out.toString().trim()); - }); + out_message.push(out.toString().trim()) + }) nodeSync.stderr.on('data', (err) => { - err_message.push(err.toString().trim()); - }); + err_message.push(err.toString().trim()) + }) nodeSync.on('close', (code) => { - const exchange_rates = {}; - let price; + const exchange_rates = {} + let price if (code === 0) { // extract exchange rate from cli output out_message.forEach((item, _index) => { if (item.includes(separator)) { - const exchangeInfo = item.split(separator); - const base = exchangeInfo[0].trim().split(' '); - const quote = exchangeInfo[1].trim().split(' '); - const market = [base[1].toUpperCase(), quote[1].toUpperCase()].join('-'); - exchange_rates[market] = quote[0] / DENOM_UNIT_MULTIPLIER; - debug(exchangeInfo, exchange_rates); + const exchangeInfo = item.split(separator) + const base = exchangeInfo[0].trim().split(' ') + const quote = exchangeInfo[1].trim().split(' ') + const market = [base[1].toUpperCase(), quote[1].toUpperCase()].join( + '-' + ) + exchange_rates[market] = quote[0] / DENOM_UNIT_MULTIPLIER + debug(exchangeInfo, exchange_rates) } - }); + }) - price = exchange_rates[tradingPair]; + price = exchange_rates[tradingPair] const result = Object.assign(paramData, { price, timestamp: initTime, - latency: hbUtils.latency(initTime, Date.now()), - }); - res.status(200).json(result); + latency: hbUtils.latency(initTime, Date.now()) + }) + res.status(200).json(result) } - }); -}); + }) +}) router.get('/balance', (req, res) => { /* api request format: /balance?address=0x87A4...b120 */ - const keyFormat = ['address']; - const paramData = hbUtils.getParamData(req.query, keyFormat); - const address = paramData.address; - debug(paramData); + const keyFormat = ['address'] + const paramData = hbUtils.getParamData(req.query, keyFormat) + const address = paramData.address + debug(paramData) - const balance = spawn(celocli, ['account:balance', address]); + const balance = spawn(celocli, ['account:balance', address]) - const err_message = []; const - out_message = []; - const walletBalances = {}; + const err_message = [] + const out_message = [] + const walletBalances = {} balance.stdout.on('data', (out) => { - out_message.push(out.toString().trim()); - debug(out_message); - }); + out_message.push(out.toString().trim()) + debug(out_message) + }) balance.stderr.on('data', (err) => { - err_message.push(err.toString().trim()); - debug(err_message); - }); + err_message.push(err.toString().trim()) + debug(err_message) + }) balance.on('close', (code) => { if (code === 0) { out_message.forEach((item, _index) => { // key indicator in balance result: "celo", "gold", "lockedcelo", "lockedgold", "usd", "pending" - if (item.toLowerCase().includes('lockedcelo') || item.toLowerCase().includes('lockedgold')) { - const balanceArray = item.split('\n'); + if ( + item.toLowerCase().includes('lockedcelo') || + item.toLowerCase().includes('lockedgold') + ) { + const balanceArray = item.split('\n') balanceArray.forEach((x) => { - const keyValue = x.split(':'); - walletBalances[keyValue[0].trim()] = keyValue[1].trim() / DENOM_UNIT_MULTIPLIER; - }); - debug('walletBalances', walletBalances); + const keyValue = x.split(':') + walletBalances[keyValue[0].trim()] = + keyValue[1].trim() / DENOM_UNIT_MULTIPLIER + }) + debug('walletBalances', walletBalances) } - }); + }) res.status(200).json({ address, balance: walletBalances, - timestamp: Date.now(), - }); + timestamp: Date.now() + }) } else { res.status(401).json({ - error: err_message, - }); + error: err_message + }) } - }); -}); + }) +}) router.post('/unlock', (req, res) => { /* @@ -176,53 +182,58 @@ router.post('/unlock', (req, res) => { "secret": "mysupersecret" } */ - const keyFormat = ['address', 'secret']; - const paramData = hbUtils.getParamData(req.body, keyFormat); - const address = paramData.address; - const secret = paramData.secret; + const keyFormat = ['address', 'secret'] + const paramData = hbUtils.getParamData(req.body, keyFormat) + const address = paramData.address + const secret = paramData.secret - debug(paramData); - debug(req.body); + debug(paramData) + debug(req.body) - const lockStatus = spawn(celocli, ['account:unlock', address, '--password', secret]); + const lockStatus = spawn(celocli, [ + 'account:unlock', + address, + '--password', + secret + ]) - const err_message = []; const - out_message = []; + const err_message = [] + const out_message = [] lockStatus.stdout.on('data', (out) => { - out_message.push(out.toString().trim()); - debug(out_message); - }); + out_message.push(out.toString().trim()) + debug(out_message) + }) lockStatus.stderr.on('data', (err) => { - err_message.push(err.toString().trim()); - debug(err_message); - }); + err_message.push(err.toString().trim()) + debug(err_message) + }) lockStatus.on('close', (code) => { - let unlocked = false; + let unlocked = false if (code === 0) { if (out_message.length > 0) { out_message.forEach((item, _index) => { if (item.includes(separator)) { - debug('item', item); + debug('item', item) } - }); + }) } else { - unlocked = true; + unlocked = true } res.status(200).json({ unlocked, message: out_message.join(), - timestamp: Date.now(), - }); + timestamp: Date.now() + }) } else { res.status(401).json({ - error: err_message.join(), - }); + error: err_message.join() + }) } - }); -}); + }) +}) router.post('/trade', (req, res) => { /* @@ -235,14 +246,14 @@ router.post('/trade', (req, res) => { "price": 3.512 } */ - const keyFormat = ['trading_pair', 'trade_type', 'amount', 'price']; - const paramData = hbUtils.getParamData(req.body, keyFormat); - debug(paramData); + const keyFormat = ['trading_pair', 'trade_type', 'amount', 'price'] + const paramData = hbUtils.getParamData(req.body, keyFormat) + debug(paramData) // const result = Object.assign(paramData, { // message: 'WIP', // timestamp: Date.now() // }) - res.status(200).json({ status: 'WIP' }); -}); + res.status(200).json({ status: 'WIP' }) +}) -module.exports = router; +module.exports = router diff --git a/src/routes/eth.route.js b/src/routes/eth.route.js index c6b057a..09dac12 100644 --- a/src/routes/eth.route.js +++ b/src/routes/eth.route.js @@ -1,22 +1,22 @@ -import { ethers, BigNumber } from 'ethers'; -import express from 'express'; +import { ethers, BigNumber } from 'ethers' +import express from 'express' -import { getParamData, latency, statusMessages } from '../services/utils'; -import Ethereum from '../services/eth'; -import Fees from '../services/fees'; -import { logger } from '../services/logger'; +import { getParamData, latency, statusMessages } from '../services/utils' +import Ethereum from '../services/eth' +import Fees from '../services/fees' +import { logger } from '../services/logger' -const debug = require('debug')('router'); +const debug = require('debug')('router') -const router = express.Router(); -const eth = new Ethereum(process.env.ETHEREUM_CHAIN); +const router = express.Router() +const eth = new Ethereum(process.env.ETHEREUM_CHAIN) const spenders = { balancer: process.env.EXCHANGE_PROXY, uniswap: process.env.UNISWAP_ROUTER, uniswapV3Router: process.env.UNISWAP_V3_ROUTER, - uniswapV3NFTManager: process.env.UNISWAP_V3_NFT_MANAGER, -}; -const fees = new Fees(); + uniswapV3NFTManager: process.env.UNISWAP_V3_NFT_MANAGER +} +const fees = new Fees() router.post('/', async (req, res) => { /* @@ -26,9 +26,9 @@ router.post('/', async (req, res) => { network: eth.network, rpcUrl: eth.provider.connection.url, connection: true, - timestamp: Date.now(), - }); -}); + timestamp: Date.now() + }) +}) router.post('/balances', async (req, res) => { /* @@ -38,65 +38,73 @@ router.post('/balances', async (req, res) => { tokenList:{{tokenList}} } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - let wallet; + const initTime = Date.now() + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + let wallet try { - wallet = new ethers.Wallet(privateKey, eth.provider); + wallet = new ethers.Wallet(privateKey, eth.provider) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = 'Error getting wallet'; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') res.status(500).json({ error: reason, - message: err, - }); - return; + message: err + }) + return } // populate token contract info using token symbol list - const tokenContractList = []; - const tokenList = JSON.parse(paramData.tokenList); + const tokenContractList = [] + const tokenList = JSON.parse(paramData.tokenList) tokenList.forEach((symbol) => { - const tokenContractInfo = eth.getERC20TokenAddresses(symbol); - tokenContractList[symbol] = tokenContractInfo; - }); + const tokenContractInfo = eth.getERC20TokenAddresses(symbol) + tokenContractList[symbol] = tokenContractInfo + }) - const balances = {}; - balances.ETH = await eth.getETHBalance(wallet, privateKey); + const balances = {} + balances.ETH = await eth.getETHBalance(wallet, privateKey) try { Promise.all( Object.keys(tokenContractList).map(async (symbol, _index) => { if (tokenContractList[symbol] !== undefined) { - const address = tokenContractList[symbol].address; - const decimals = tokenContractList[symbol].decimals; - balances[symbol] = await eth.getERC20Balance(wallet, address, decimals); + const address = tokenContractList[symbol].address + const decimals = tokenContractList[symbol].decimals + balances[symbol] = await eth.getERC20Balance( + wallet, + address, + decimals + ) } else { - const err = `Token contract info for ${symbol} not found`; - logger.error('Token info not found', { message: err }); - debug(err); + const err = `Token contract info for ${symbol} not found` + logger.error('Token info not found', { message: err }) + debug(err) } - }), + }) ).then(() => { - debug('eth.route - Get Account Balance', { message: JSON.stringify(tokenList) }); + debug('eth.route - Get Account Balance', { + message: JSON.stringify(tokenList) + }) res.status(200).json({ network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), - balances, - }); - }); + balances + }) + }) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/allowances', async (req, res) => { /* @@ -107,60 +115,69 @@ router.post('/allowances', async (req, res) => { connector:{{connector_name}} } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - const spender = spenders[paramData.connector]; - let wallet; + const initTime = Date.now() + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + const spender = spenders[paramData.connector] + let wallet try { - wallet = new ethers.Wallet(privateKey, eth.provider); + wallet = new ethers.Wallet(privateKey, eth.provider) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = 'Error getting wallet'; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') res.status(500).json({ error: reason, - message: err, - }); - return; + message: err + }) + return } // populate token contract info using token symbol list - const tokenContractList = []; - const tokenList = JSON.parse(paramData.tokenList); + const tokenContractList = [] + const tokenList = JSON.parse(paramData.tokenList) tokenList.forEach((symbol) => { - const tokenContractInfo = eth.getERC20TokenAddresses(symbol); - tokenContractList[symbol] = tokenContractInfo; - }); + const tokenContractInfo = eth.getERC20TokenAddresses(symbol) + tokenContractList[symbol] = tokenContractInfo + }) - const approvals = {}; + const approvals = {} try { Promise.all( Object.keys(tokenContractList).map(async (symbol, _index) => { - const address = tokenContractList[symbol].address; - const decimals = tokenContractList[symbol].decimals; - approvals[symbol] = await eth.getERC20Allowance(wallet, spender, address, decimals); - }), + const address = tokenContractList[symbol].address + const decimals = tokenContractList[symbol].decimals + approvals[symbol] = await eth.getERC20Allowance( + wallet, + spender, + address, + decimals + ) + }) ).then(() => { - logger.info('eth.route - Getting allowances', { message: JSON.stringify(tokenList) }); + logger.info('eth.route - Getting allowances', { + message: JSON.stringify(tokenList) + }) res.status(200).json({ network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), spender, - approvals, - }); - }); + approvals + }) + }) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/balances-2', async (req, res) => { /* @@ -171,52 +188,61 @@ router.post('/balances-2', async (req, res) => { tokenDecimalList:{{tokenDecimalList}} } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - let wallet; + const initTime = Date.now() + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + let wallet try { - wallet = new ethers.Wallet(privateKey, eth.provider); + wallet = new ethers.Wallet(privateKey, eth.provider) } catch (err) { - let reason; - err.reason ? reason = err.reason : reason = 'Error getting wallet'; + let reason + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') res.status(500).json({ error: reason, - message: err, - }); - return; + message: err + }) + return } - let tokenAddressList; + let tokenAddressList if (paramData.tokenAddressList) { - tokenAddressList = paramData.tokenAddressList.split(','); + tokenAddressList = paramData.tokenAddressList.split(',') } - let tokenDecimalList; + let tokenDecimalList if (paramData.tokenDecimalList) { - tokenDecimalList = paramData.tokenDecimalList.split(','); + tokenDecimalList = paramData.tokenDecimalList.split(',') } - const balances = {}; - balances.ETH = await eth.getETHBalance(wallet, privateKey); + const balances = {} + balances.ETH = await eth.getETHBalance(wallet, privateKey) try { Promise.all( - tokenAddressList.map(async (value, index) => balances[value] = await eth.getERC20Balance(wallet, value, tokenDecimalList[index])), + tokenAddressList.map( + async (value, index) => + (balances[value] = await eth.getERC20Balance( + wallet, + value, + tokenDecimalList[index] + )) + ) ).then(() => { res.status(200).json({ network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), - balances, - }); - }); + balances + }) + }) } catch (err) { - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/allowances-2', async (req, res) => { /* @@ -228,53 +254,63 @@ router.post('/allowances-2', async (req, res) => { connector:{{connector_name}} } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - const spender = spenders[paramData.connector]; - let wallet; + const initTime = Date.now() + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + const spender = spenders[paramData.connector] + let wallet try { - wallet = new ethers.Wallet(privateKey, eth.provider); + wallet = new ethers.Wallet(privateKey, eth.provider) } catch (err) { - let reason; - err.reason ? reason = err.reason : reason = 'Error getting wallet'; + let reason + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') res.status(500).json({ error: reason, - message: err, - }); - return; + message: err + }) + return } - let tokenAddressList; + let tokenAddressList if (paramData.tokenAddressList) { - tokenAddressList = paramData.tokenAddressList.split(','); + tokenAddressList = paramData.tokenAddressList.split(',') } - let tokenDecimalList; + let tokenDecimalList if (paramData.tokenDecimalList) { - tokenDecimalList = paramData.tokenDecimalList.split(','); + tokenDecimalList = paramData.tokenDecimalList.split(',') } - const approvals = {}; + const approvals = {} try { Promise.all( - tokenAddressList.map(async (value, index) => approvals[value] = await eth.getERC20Allowance(wallet, spender, value, tokenDecimalList[index])), + tokenAddressList.map( + async (value, index) => + (approvals[value] = await eth.getERC20Allowance( + wallet, + spender, + value, + tokenDecimalList[index] + )) + ) ).then(() => { res.status(200).json({ network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), spender, - approvals, - }); - }); + approvals + }) + }) } catch (err) { - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/approve', async (req, res) => { /* @@ -287,41 +323,48 @@ router.post('/approve', async (req, res) => { amount:{{amount}} } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - const spender = spenders[paramData.connector]; - let wallet; + const initTime = Date.now() + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + const spender = spenders[paramData.connector] + let wallet try { - wallet = new ethers.Wallet(privateKey, eth.provider); + wallet = new ethers.Wallet(privateKey, eth.provider) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = 'Error getting wallet'; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') res.status(500).json({ error: reason, - message: err, - }); - return; + message: err + }) + return } - const token = paramData.token; - const tokenContractInfo = eth.getERC20TokenAddresses(token); - const tokenAddress = tokenContractInfo.address; - const decimals = tokenContractInfo.decimals; + const token = paramData.token + const tokenContractInfo = eth.getERC20TokenAddresses(token) + const tokenAddress = tokenContractInfo.address + const decimals = tokenContractInfo.decimals - let amount; - paramData.amount ? amount = ethers.utils.parseUnits(paramData.amount, decimals) - : amount = ethers.constants.MaxUint256; // approve max possible units if no amount specified - let gasPrice; + let amount + paramData.amount + ? (amount = ethers.utils.parseUnits(paramData.amount, decimals)) + : (amount = ethers.constants.MaxUint256) // approve max possible units if no amount specified + let gasPrice if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice); + gasPrice = parseFloat(paramData.gasPrice) } else { - gasPrice = fees.ethGasPrice; + gasPrice = fees.ethGasPrice } try { // call approve function - const approval = await eth.approveERC20(wallet, spender, tokenAddress, amount, gasPrice); + const approval = await eth.approveERC20( + wallet, + spender, + tokenAddress, + amount, + gasPrice + ) // console.log('eth.route - Approving allowance', { message: approval }) // submit response res.status(200).json({ @@ -330,45 +373,49 @@ router.post('/approve', async (req, res) => { latency: latency(initTime, Date.now()), tokenAddress, spender, - amount: amount / 1e18.toString(), - approval, - }); + amount: amount / (1e18).toString(), + approval + }) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/poll', async (req, res) => { - const initTime = Date.now(); - const paramData = getParamData(req.body); - const txHash = paramData.txHash; - const txReceipt = await eth.provider.getTransactionReceipt(txHash); - const receipt = {}; - const confirmed = !!(txReceipt && txReceipt.blockNumber); + const initTime = Date.now() + const paramData = getParamData(req.body) + const txHash = paramData.txHash + const txReceipt = await eth.provider.getTransactionReceipt(txHash) + const receipt = {} + const confirmed = !!(txReceipt && txReceipt.blockNumber) if (confirmed) { - receipt.gasUsed = BigNumber.from(txReceipt.gasUsed).toNumber(); - receipt.blockNumber = txReceipt.blockNumber; - receipt.confirmations = txReceipt.confirmations; - receipt.status = txReceipt.status; - receipt.logs = txReceipt.logs; + receipt.gasUsed = BigNumber.from(txReceipt.gasUsed).toNumber() + receipt.blockNumber = txReceipt.blockNumber + receipt.confirmations = txReceipt.confirmations + receipt.status = txReceipt.status + receipt.logs = txReceipt.logs } - logger.info(`eth.route - Get TX Receipt: ${txHash}`, { message: JSON.stringify(receipt) }); + logger.info(`eth.route - Get TX Receipt: ${txHash}`, { + message: JSON.stringify(receipt) + }) res.status(200).json({ network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), txHash, confirmed, - receipt, - }); - return txReceipt; -}); + receipt + }) + return txReceipt +}) // Kovan faucet to get test tokens (wip) & weth conversion // router.post('/get-weth', async (req, res) => { @@ -425,4 +472,4 @@ router.post('/poll', async (req, res) => { // } // }) -module.exports = router; +module.exports = router diff --git a/src/routes/index.route.js b/src/routes/index.route.js index fbe93c6..1116b5c 100644 --- a/src/routes/index.route.js +++ b/src/routes/index.route.js @@ -1,16 +1,16 @@ -import { loadConfig } from '../services/utils'; +import { loadConfig } from '../services/utils' -const express = require('express'); +const express = require('express') -const router = express.Router(); +const router = express.Router() router.get('/', (req, res) => { res.status(200).json({ app: process.env.APPNAME, image: process.env.IMAGE, config: loadConfig(), - status: 'ok', - }); -}); + status: 'ok' + }) +}) -module.exports = router; +module.exports = router diff --git a/src/routes/perpetual_finance.route.js b/src/routes/perpetual_finance.route.js index 46eb82a..0441a39 100644 --- a/src/routes/perpetual_finance.route.js +++ b/src/routes/perpetual_finance.route.js @@ -1,15 +1,15 @@ -import { ethers } from 'ethers'; -import express from 'express'; +import { ethers } from 'ethers' +import express from 'express' -import { getParamData, latency, statusMessages } from '../services/utils'; -import { logger } from '../services/logger'; -import PerpetualFinance from '../services/perpetual_finance'; +import { getParamData, latency, statusMessages } from '../services/utils' +import { logger } from '../services/logger' +import PerpetualFinance from '../services/perpetual_finance' -require('dotenv').config(); +require('dotenv').config() -const router = express.Router(); -const perpFi = new PerpetualFinance(process.env.ETHEREUM_CHAIN); -setTimeout(perpFi.update_price_loop.bind(perpFi), 2000); +const router = express.Router() +const perpFi = new PerpetualFinance(process.env.ETHEREUM_CHAIN) +setTimeout(perpFi.update_price_loop.bind(perpFi), 2000) router.get('/', async (req, res) => { /* @@ -20,23 +20,23 @@ router.get('/', async (req, res) => { provider: perpFi.provider.connection.url, loadedMetadata: perpFi.loadedMetadata, connection: true, - timestamp: Date.now(), - }); -}); + timestamp: Date.now() + }) +}) router.get('/load-metadata', async (req, res) => { /* GET / */ - const loadedMetadata = await perpFi.load_metadata(); + const loadedMetadata = await perpFi.load_metadata() res.status(200).json({ network: perpFi.network, provider: perpFi.provider.connection.url, loadedMetadata, connection: true, - timestamp: Date.now(), - }); -}); + timestamp: Date.now() + }) +}) router.post('/balances', async (req, res) => { /* @@ -45,41 +45,43 @@ router.post('/balances', async (req, res) => { privateKey:{{privateKey}} } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - let wallet; + const initTime = Date.now() + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + let wallet try { - wallet = new ethers.Wallet(privateKey, perpFi.provider); + wallet = new ethers.Wallet(privateKey, perpFi.provider) } catch (err) { - let reason; - err.reason ? reason = err.reason : reason = 'Error getting wallet'; + let reason + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') res.status(500).json({ error: reason, - message: err, - }); - return; + message: err + }) + return } - const balances = {}; - balances.XDAI = await perpFi.getXdaiBalance(wallet); - balances.USDC = await perpFi.getUSDCBalance(wallet); + const balances = {} + balances.XDAI = await perpFi.getXdaiBalance(wallet) + balances.USDC = await perpFi.getUSDCBalance(wallet) try { res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - balances, - }); + balances + }) } catch (err) { - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/allowances', async (req, res) => { /* @@ -88,40 +90,42 @@ router.post('/allowances', async (req, res) => { privateKey:{{privateKey}} } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - let wallet; + const initTime = Date.now() + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + let wallet try { - wallet = new ethers.Wallet(privateKey, perpFi.provider); + wallet = new ethers.Wallet(privateKey, perpFi.provider) } catch (err) { - let reason; - err.reason ? reason = err.reason : reason = 'Error getting wallet'; + let reason + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') res.status(500).json({ error: reason, - message: err, - }); - return; + message: err + }) + return } - const approvals = {}; - approvals.USDC = await perpFi.getAllowance(wallet); + const approvals = {} + approvals.USDC = await perpFi.getAllowance(wallet) try { res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - approvals, - }); + approvals + }) } catch (err) { - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/approve', async (req, res) => { /* @@ -131,48 +135,49 @@ router.post('/approve', async (req, res) => { amount:{{amount}} } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - let amount; - paramData.amount ? amount = paramData.amount - : amount = '1000000000'; - let wallet; + const initTime = Date.now() + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + let amount + paramData.amount ? (amount = paramData.amount) : (amount = '1000000000') + let wallet try { - wallet = new ethers.Wallet(privateKey, perpFi.provider); + wallet = new ethers.Wallet(privateKey, perpFi.provider) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = 'Error getting wallet'; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') res.status(500).json({ error: reason, - message: err, - }); - return; + message: err + }) + return } try { // call approve function - const approval = await perpFi.approve(wallet, amount); - logger.info('perpFi.route - Approving allowance'); + const approval = await perpFi.approve(wallet, amount) + logger.info('perpFi.route - Approving allowance') // submit response res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), amount, - approval, - }); + approval + }) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/open', async (req, res) => { /* @@ -186,33 +191,40 @@ router.post('/open', async (req, res) => { privateKey:{{privateKey}} } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const side = paramData.side; - const pair = paramData.pair; - const margin = paramData.margin; - const leverage = paramData.leverage; - const minBaseAssetAmount = paramData.minBaseAssetAmount; - console.log(minBaseAssetAmount); - const privateKey = paramData.privateKey; - let wallet; + const initTime = Date.now() + const paramData = getParamData(req.body) + const side = paramData.side + const pair = paramData.pair + const margin = paramData.margin + const leverage = paramData.leverage + const minBaseAssetAmount = paramData.minBaseAssetAmount + console.log(minBaseAssetAmount) + const privateKey = paramData.privateKey + let wallet try { - wallet = new ethers.Wallet(privateKey, perpFi.provider); + wallet = new ethers.Wallet(privateKey, perpFi.provider) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = 'Error getting wallet'; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') res.status(500).json({ error: reason, - message: err, - }); - return; + message: err + }) + return } try { // call openPosition function - const tx = await perpFi.openPosition(side, margin, leverage, pair, minBaseAssetAmount, wallet); - logger.info('perpFi.route - Opening position'); + const tx = await perpFi.openPosition( + side, + margin, + leverage, + pair, + minBaseAssetAmount, + wallet + ) + logger.info('perpFi.route - Opening position') // submit response res.status(200).json({ network: perpFi.network, @@ -222,18 +234,20 @@ router.post('/open', async (req, res) => { side, leverage, minBaseAssetAmount, - txHash: tx.hash, - }); + txHash: tx.hash + }) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/close', async (req, res) => { /* @@ -244,47 +258,49 @@ router.post('/close', async (req, res) => { pair:{{pair}} } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const minimalQuoteAsset = paramData.minimalQuoteAsset; - const privateKey = paramData.privateKey; - const pair = paramData.pair; - let wallet; + const initTime = Date.now() + const paramData = getParamData(req.body) + const minimalQuoteAsset = paramData.minimalQuoteAsset + const privateKey = paramData.privateKey + const pair = paramData.pair + let wallet try { - wallet = new ethers.Wallet(privateKey, perpFi.provider); + wallet = new ethers.Wallet(privateKey, perpFi.provider) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = 'Error getting wallet'; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') res.status(500).json({ error: reason, - message: err, - }); - return; + message: err + }) + return } try { // call closePosition function - const tx = await perpFi.closePosition(wallet, pair, minimalQuoteAsset); - logger.info('perpFi.route - Closing position'); + const tx = await perpFi.closePosition(wallet, pair, minimalQuoteAsset) + logger.info('perpFi.route - Closing position') // submit response res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), minimalQuoteAsset, - txHash: tx.hash, - }); + txHash: tx.hash + }) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/position', async (req, res) => { /* @@ -294,45 +310,47 @@ router.post('/position', async (req, res) => { pair:{{pair}} } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - const pair = paramData.pair; - let wallet; + const initTime = Date.now() + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + const pair = paramData.pair + let wallet try { - wallet = new ethers.Wallet(privateKey, perpFi.provider); + wallet = new ethers.Wallet(privateKey, perpFi.provider) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = 'Error getting wallet'; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') res.status(500).json({ error: reason, - message: err, - }); - return; + message: err + }) + return } try { // call getPosition function - const position = await perpFi.getPosition(wallet, pair); - logger.info('perpFi.route - getting active position'); + const position = await perpFi.getPosition(wallet, pair) + logger.info('perpFi.route - getting active position') // submit response res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - position, - }); + position + }) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/margin', async (req, res) => { /* @@ -341,44 +359,46 @@ router.post('/margin', async (req, res) => { privateKey:{{privateKey}} } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - let wallet; + const initTime = Date.now() + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + let wallet try { - wallet = new ethers.Wallet(privateKey, perpFi.provider); + wallet = new ethers.Wallet(privateKey, perpFi.provider) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = 'Error getting wallet'; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') res.status(500).json({ error: reason, - message: err, - }); - return; + message: err + }) + return } try { // call getAllBalances function - const allBalances = await perpFi.getActiveMargin(wallet); - logger.info('perpFi.route - Getting all balances'); + const allBalances = await perpFi.getActiveMargin(wallet) + logger.info('perpFi.route - Getting all balances') // submit response res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - margin: allBalances, - }); + margin: allBalances + }) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/receipt', async (req, res) => { /* @@ -387,29 +407,31 @@ router.post('/receipt', async (req, res) => { txHash:{{txHash}} } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const txHash = paramData.txHash; - const txReceipt = await perpFi.provider.getTransactionReceipt(txHash); - const receipt = {}; - const confirmed = !!(txReceipt && txReceipt.blockNumber); + const initTime = Date.now() + const paramData = getParamData(req.body) + const txHash = paramData.txHash + const txReceipt = await perpFi.provider.getTransactionReceipt(txHash) + const receipt = {} + const confirmed = !!(txReceipt && txReceipt.blockNumber) if (txReceipt !== null) { - receipt.gasUsed = ethers.utils.formatEther(txReceipt.gasUsed); - receipt.blockNumber = txReceipt.blockNumber; - receipt.confirmations = txReceipt.confirmations; - receipt.status = txReceipt.status; + receipt.gasUsed = ethers.utils.formatEther(txReceipt.gasUsed) + receipt.blockNumber = txReceipt.blockNumber + receipt.confirmations = txReceipt.confirmations + receipt.status = txReceipt.status } - logger.info(`eth.route - Get TX Receipt: ${txHash}`, { message: JSON.stringify(receipt) }); + logger.info(`eth.route - Get TX Receipt: ${txHash}`, { + message: JSON.stringify(receipt) + }) res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), txHash, confirmed, - receipt, - }); - return txReceipt; -}); + receipt + }) + return txReceipt +}) router.post('/price', async (req, res) => { /* @@ -420,58 +442,62 @@ router.post('/price', async (req, res) => { amount:{{amount}} } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const side = paramData.side; - const pair = paramData.pair; - const amount = paramData.amount; + const initTime = Date.now() + const paramData = getParamData(req.body) + const side = paramData.side + const pair = paramData.pair + const amount = paramData.amount try { // call getPrice function - const price = await perpFi.getPrice(side, amount, pair); - logger.info('perpFi.route - Getting price'); + const price = await perpFi.getPrice(side, amount, pair) + logger.info('perpFi.route - Getting price') // submit response res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), side, - price, - }); + price + }) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.get('/pairs', async (req, res) => { /* GET */ - const initTime = Date.now(); + const initTime = Date.now() try { res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - pairs: Object.keys(perpFi.amm), - }); + pairs: Object.keys(perpFi.amm) + }) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/funding', async (req, res) => { /* @@ -480,30 +506,32 @@ router.post('/funding', async (req, res) => { pair:{{pair}} } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const pair = paramData.pair; + const initTime = Date.now() + const paramData = getParamData(req.body) + const pair = paramData.pair try { // call getFundingRate function - const fr = await perpFi.getFundingRate(pair); - logger.info('perpFi.route - Getting funding info'); + const fr = await perpFi.getFundingRate(pair) + logger.info('perpFi.route - Getting funding info') // submit response res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - fr, - }); + fr + }) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) -export default router; +export default router diff --git a/src/routes/terra.route.js b/src/routes/terra.route.js index 506935f..6f9058f 100644 --- a/src/routes/terra.route.js +++ b/src/routes/terra.route.js @@ -1,17 +1,20 @@ -import express from 'express'; +import express from 'express' import { - getParamData, latency, reportConnectionError, statusMessages, -} from '../services/utils'; -import { logger } from '../services/logger'; + getParamData, + latency, + reportConnectionError, + statusMessages +} from '../services/utils' +import { logger } from '../services/logger' -import Terra from '../services/terra'; +import Terra from '../services/terra' -const router = express.Router(); -const terra = new Terra(); +const router = express.Router() +const terra = new Terra() // constants -const network = terra.lcd.config.chainID; -const denomUnitMultiplier = terra.denomUnitMultiplier; +const network = terra.lcd.config.chainID +const denomUnitMultiplier = terra.denomUnitMultiplier router.post('/', async (req, res) => { /* @@ -23,57 +26,59 @@ router.post('/', async (req, res) => { gasPrices: terra.lcd.config.gasPrices, gasAdjustment: terra.lcd.config.gasAdjustment, connection: true, - timestamp: Date.now(), - }); -}); + timestamp: Date.now() + }) +}) router.post('/balances', async (req, res) => { /* POST: address:{{address}} */ - const initTime = Date.now(); + const initTime = Date.now() - const paramData = getParamData(req.body); - const address = paramData.address; + const paramData = getParamData(req.body) + const address = paramData.address - const balances = {}; + const balances = {} try { await terra.lcd.bank.balance(address).then((bal) => { bal.toArray().forEach(async (x) => { - const item = x.toData(); - const denom = item.denom; - const amount = item.amount / denomUnitMultiplier; - const symbol = terra.tokens[denom].symbol; - balances[symbol] = amount; - }); - }); - logger.info('terra.route - Get Account Balance'); + const item = x.toData() + const denom = item.denom + const amount = item.amount / denomUnitMultiplier + const symbol = terra.tokens[denom].symbol + balances[symbol] = amount + }) + }) + logger.info('terra.route - Get Account Balance') res.status(200).json({ network, timestamp: initTime, latency: latency(initTime, Date.now()), - balances, - }); + balances + }) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let message; - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; - const isAxiosError = err.isAxiosError; + logger.error(req.originalUrl, { message: err }) + let message + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) + const isAxiosError = err.isAxiosError if (isAxiosError) { - reason = err.response.status; - message = err.response.statusText; + reason = err.response.status + message = err.response.statusText } else { - message = err; + message = err } res.status(500).json({ error: reason, - message, - }); + message + }) } -}); +}) router.post('/start', async (req, res) => { /* @@ -84,10 +89,10 @@ router.post('/start', async (req, res) => { "amount":1 } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const baseTokenSymbol = paramData.base; - const quoteTokenSymbol = paramData.quote; + const initTime = Date.now() + const paramData = getParamData(req.body) + const baseTokenSymbol = paramData.base + const quoteTokenSymbol = paramData.quote const result = { network, @@ -95,10 +100,10 @@ router.post('/start', async (req, res) => { latency: latency(initTime, Date.now()), success: true, base: baseTokenSymbol, - quote: quoteTokenSymbol, - }; - res.status(200).json(result); -}); + quote: quoteTokenSymbol + } + res.status(200).json(result) +}) router.post('/price', async (req, res) => { /* @@ -110,55 +115,58 @@ router.post('/price', async (req, res) => { "amount":1 } */ - const initTime = Date.now(); + const initTime = Date.now() - const paramData = getParamData(req.body); - const baseToken = paramData.base; - const quoteToken = paramData.quote; - const tradeType = paramData.side.toUpperCase(); - const amount = parseFloat(paramData.amount); + const paramData = getParamData(req.body) + const baseToken = paramData.base + const quoteToken = paramData.quote + const tradeType = paramData.side.toUpperCase() + const amount = parseFloat(paramData.amount) - let exchangeRate; + let exchangeRate try { - await terra.getSwapRate(baseToken, quoteToken, amount, tradeType).then((rate) => { - exchangeRate = rate; - }).catch((err) => { - reportConnectionError(res, err); - }); - - res.status(200).json( - { - network, - timestamp: initTime, - latency: latency(initTime, Date.now()), - base: baseToken, - quote: quoteToken, - amount, - tradeType, - price: exchangeRate.price.amount, - cost: exchangeRate.cost.amount, - txFee: exchangeRate.txFee.amount, - }, - ); + await terra + .getSwapRate(baseToken, quoteToken, amount, tradeType) + .then((rate) => { + exchangeRate = rate + }) + .catch((err) => { + reportConnectionError(res, err) + }) + + res.status(200).json({ + network, + timestamp: initTime, + latency: latency(initTime, Date.now()), + base: baseToken, + quote: quoteToken, + amount, + tradeType, + price: exchangeRate.price.amount, + cost: exchangeRate.cost.amount, + txFee: exchangeRate.txFee.amount + }) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let message; - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; - const isAxiosError = err.isAxiosError; + logger.error(req.originalUrl, { message: err }) + let message + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) + const isAxiosError = err.isAxiosError if (isAxiosError) { - reason = err.response.status; - message = err.response.statusText; + reason = err.response.status + message = err.response.statusText } else { - message = err; + message = err } res.status(500).json({ error: reason, - message, - }); + message + }) } -}); +}) router.post('/trade', async (req, res) => { /* @@ -171,25 +179,38 @@ router.post('/trade', async (req, res) => { "secret": "mysupersecret" } */ - const initTime = Date.now(); + const initTime = Date.now() - const paramData = getParamData(req.body); - const baseToken = paramData.base; - const quoteToken = paramData.quote; - const tradeType = paramData.side.toUpperCase(); - const amount = parseFloat(paramData.amount); - const gasPrice = parseFloat(paramData.gas_price) || terra.lcd.config.gasPrices.uluna; - const gasAdjustment = paramData.gas_adjustment || terra.lcd.config.gasAdjustment; - const secret = paramData.privateKey; + const paramData = getParamData(req.body) + const baseToken = paramData.base + const quoteToken = paramData.quote + const tradeType = paramData.side.toUpperCase() + const amount = parseFloat(paramData.amount) + const gasPrice = + parseFloat(paramData.gas_price) || terra.lcd.config.gasPrices.uluna + const gasAdjustment = + paramData.gas_adjustment || terra.lcd.config.gasAdjustment + const secret = paramData.privateKey - let tokenSwaps; + let tokenSwaps try { - await terra.swapTokens(baseToken, quoteToken, amount, tradeType, gasPrice, gasAdjustment, secret).then((swap) => { - tokenSwaps = swap; - }).catch((err) => { - reportConnectionError(res, err); - }); + await terra + .swapTokens( + baseToken, + quoteToken, + amount, + tradeType, + gasPrice, + gasAdjustment, + secret + ) + .then((swap) => { + tokenSwaps = swap + }) + .catch((err) => { + reportConnectionError(res, err) + }) const swapResult = { network, @@ -198,30 +219,32 @@ router.post('/trade', async (req, res) => { base: baseToken, tradeType, quote: quoteToken, - amount, - }; - Object.assign(swapResult, tokenSwaps); - logger.info(`terra.route - ${tradeType}: ${baseToken}-${quoteToken} - Amount: ${amount}`); - res.status(200).json( - swapResult, - ); + amount + } + Object.assign(swapResult, tokenSwaps) + logger.info( + `terra.route - ${tradeType}: ${baseToken}-${quoteToken} - Amount: ${amount}` + ) + res.status(200).json(swapResult) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let message; - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; - const isAxiosError = err.isAxiosError; + logger.error(req.originalUrl, { message: err }) + let message + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) + const isAxiosError = err.isAxiosError if (isAxiosError) { - reason = err.response.status; - message = err.response.statusText; + reason = err.response.status + message = err.response.statusText } else { - message = err; + message = err } res.status(500).json({ error: reason, - message, - }); + message + }) } -}); +}) -module.exports = router; +module.exports = router diff --git a/src/routes/uniswap.route.js b/src/routes/uniswap.route.js index 825bfb8..6201ae0 100644 --- a/src/routes/uniswap.route.js +++ b/src/routes/uniswap.route.js @@ -1,44 +1,44 @@ -import { ethers } from 'ethers'; -import express from 'express'; +import { ethers } from 'ethers' +import express from 'express' -import { getParamData, latency, statusMessages } from '../services/utils'; -import { logger } from '../services/logger'; -import Ethereum from '../services/eth'; -import Uniswap from '../services/uniswap'; -import Fees from '../services/fees'; +import { getParamData, latency, statusMessages } from '../services/utils' +import { logger } from '../services/logger' +import Ethereum from '../services/eth' +import Uniswap from '../services/uniswap' +import Fees from '../services/fees' -require('dotenv').config(); +require('dotenv').config() -const debug = require('debug')('router'); +const debug = require('debug')('router') -const router = express.Router(); -const eth = new Ethereum(process.env.ETHEREUM_CHAIN); -const uniswap = new Uniswap(process.env.ETHEREUM_CHAIN); -uniswap.generate_tokens(); -setTimeout(uniswap.update_pairs.bind(uniswap), 2000); -const fees = new Fees(); +const router = express.Router() +const eth = new Ethereum(process.env.ETHEREUM_CHAIN) +const uniswap = new Uniswap(process.env.ETHEREUM_CHAIN) +uniswap.generate_tokens() +setTimeout(uniswap.update_pairs.bind(uniswap), 2000) +const fees = new Fees() -const swapMoreThanMaxPriceError = 'Price too high'; -const swapLessThanMaxPriceError = 'Price too low'; +const swapMoreThanMaxPriceError = 'Price too high' +const swapLessThanMaxPriceError = 'Price too low' -const estimateGasLimit = () => uniswap.gasLimit; +const estimateGasLimit = () => uniswap.gasLimit const getErrorMessage = (err) => { /* [WIP] Custom error message based-on string match */ - let message = err; + let message = err if (err.includes('failed to meet quorum')) { - message = 'Failed to meet quorum in Uniswap'; + message = 'Failed to meet quorum in Uniswap' } else if (err.includes('Invariant failed: ADDRESSES')) { - message = 'Invariant failed: ADDRESSES'; + message = 'Invariant failed: ADDRESSES' } else if (err.includes('"call revert exception')) { - message = statusMessages.no_pool_available; + message = statusMessages.no_pool_available } else if (err.includes('"trade" is read-only')) { - message = statusMessages.no_pool_available; + message = statusMessages.no_pool_available } - return message; -}; + return message +} router.post('/', async (req, res) => { /* @@ -49,32 +49,34 @@ router.post('/', async (req, res) => { provider: uniswap.provider.connection.url, uniswap_router: uniswap.router, connection: true, - timestamp: Date.now(), - }); -}); + timestamp: Date.now() + }) +}) router.post('/gas-limit', async (req, res) => { /* POST: /buy-price */ - const gasLimit = estimateGasLimit(); + const gasLimit = estimateGasLimit() try { res.status(200).json({ network: uniswap.network, gasLimit, - timestamp: Date.now(), - }); + timestamp: Date.now() + }) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.get('/start', async (req, res) => { /* @@ -84,38 +86,47 @@ router.get('/start', async (req, res) => { "gasPrice":30 } */ - const initTime = Date.now(); - const paramData = getParamData(req.query); - const pairs = JSON.parse(paramData.pairs); - let gasPrice; + const initTime = Date.now() + const paramData = getParamData(req.query) + const pairs = JSON.parse(paramData.pairs) + let gasPrice if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice); + gasPrice = parseFloat(paramData.gasPrice) } else { - gasPrice = fees.ethGasPrice; + gasPrice = fees.ethGasPrice } // get token contract address and cache paths for (let pair of pairs) { - pair = pair.split('-'); - const baseTokenSymbol = pair[0]; - const quoteTokenSymbol = pair[1]; - const baseTokenContractInfo = eth.getERC20TokenAddresses(baseTokenSymbol); - const quoteTokenContractInfo = eth.getERC20TokenAddresses(quoteTokenSymbol); + pair = pair.split('-') + const baseTokenSymbol = pair[0] + const quoteTokenSymbol = pair[1] + const baseTokenContractInfo = eth.getERC20TokenAddresses(baseTokenSymbol) + const quoteTokenContractInfo = eth.getERC20TokenAddresses(quoteTokenSymbol) // check for valid token symbols - if (baseTokenContractInfo === undefined || quoteTokenContractInfo === undefined) { - const undefinedToken = baseTokenContractInfo === undefined ? baseTokenSymbol : quoteTokenSymbol; + if ( + baseTokenContractInfo === undefined || + quoteTokenContractInfo === undefined + ) { + const undefinedToken = + baseTokenContractInfo === undefined ? baseTokenSymbol : quoteTokenSymbol res.status(500).json({ error: `Token ${undefinedToken} contract address not found`, - message: `Token contract address not found for ${undefinedToken}. Check token list source`, - }); - return; + message: `Token contract address not found for ${undefinedToken}. Check token list source` + }) + return } - await Promise.allSettled([uniswap.extend_update_pairs([baseTokenContractInfo.address, quoteTokenContractInfo.address])]); + await Promise.allSettled([ + uniswap.extend_update_pairs([ + baseTokenContractInfo.address, + quoteTokenContractInfo.address + ]) + ]) } - const gasLimit = estimateGasLimit(); - const gasCost = await fees.getGasCost(gasPrice, gasLimit); + const gasLimit = estimateGasLimit() + const gasCost = await fees.getGasCost(gasPrice, gasLimit) const result = { network: eth.network, @@ -125,10 +136,10 @@ router.get('/start', async (req, res) => { pairs, gasPrice, gasLimit, - gasCost, - }; - res.status(200).json(result); -}); + gasCost + } + res.status(200).json(result) +}) router.post('/trade', async (req, res) => { /* @@ -143,57 +154,58 @@ router.post('/trade', async (req, res) => { "side":{buy|sell} } */ - const initTime = Date.now(); + const initTime = Date.now() // params: privateKey (required), base (required), quote (required), amount (required), maxPrice (required), gasPrice (required) - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - const wallet = new ethers.Wallet(privateKey, uniswap.provider); - const amount = paramData.amount; + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + const wallet = new ethers.Wallet(privateKey, uniswap.provider) + const amount = paramData.amount - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base); - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote); - const baseTokenAddress = baseTokenContractInfo.address; - const quoteTokenAddress = quoteTokenContractInfo.address; - const side = paramData.side.toUpperCase(); + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base) + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote) + const baseTokenAddress = baseTokenContractInfo.address + const quoteTokenAddress = quoteTokenContractInfo.address + const side = paramData.side.toUpperCase() - let limitPrice; + let limitPrice if (paramData.limitPrice) { - limitPrice = parseFloat(paramData.limitPrice); + limitPrice = parseFloat(paramData.limitPrice) } - let gasPrice; + let gasPrice if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice); + gasPrice = parseFloat(paramData.gasPrice) } else { - gasPrice = fees.ethGasPrice; + gasPrice = fees.ethGasPrice } - const gasLimit = estimateGasLimit(); - const gasCost = await fees.getGasCost(gasPrice, gasLimit); + const gasLimit = estimateGasLimit() + const gasCost = await fees.getGasCost(gasPrice, gasLimit) try { // fetch the optimal pool mix from uniswap - const { trade, expectedAmount } = side === 'BUY' - ? await uniswap.priceSwapOut( - quoteTokenAddress, // tokenIn is quote asset - baseTokenAddress, // tokenOut is base asset - amount, - ) - : await uniswap.priceSwapIn( - baseTokenAddress, // tokenIn is base asset - quoteTokenAddress, // tokenOut is quote asset - amount, - ); + const { trade, expectedAmount } = + side === 'BUY' + ? await uniswap.priceSwapOut( + quoteTokenAddress, // tokenIn is quote asset + baseTokenAddress, // tokenOut is base asset + amount + ) + : await uniswap.priceSwapIn( + baseTokenAddress, // tokenIn is base asset + quoteTokenAddress, // tokenOut is quote asset + amount + ) if (side === 'BUY') { - const price = trade.executionPrice.invert().toSignificant(8); - logger.info(`uniswap.route - Price: ${price.toString()}`); + const price = trade.executionPrice.invert().toSignificant(8) + logger.info(`uniswap.route - Price: ${price.toString()}`) if (!limitPrice || price <= limitPrice) { // pass swaps to exchange-proxy to complete trade const tx = await uniswap.swapExactOut( wallet, trade, baseTokenAddress, - gasPrice, - ); + gasPrice + ) // submit response res.status(200).json({ network: uniswap.network, @@ -207,27 +219,29 @@ router.post('/trade', async (req, res) => { gasPrice, gasLimit, gasCost, - txHash: tx.hash, - }); + txHash: tx.hash + }) } else { res.status(200).json({ error: swapMoreThanMaxPriceError, - message: `Swap price ${price} exceeds limitPrice ${limitPrice}`, - }); - logger.info(`uniswap.route - Swap price ${price} exceeds limitPrice ${limitPrice}`); + message: `Swap price ${price} exceeds limitPrice ${limitPrice}` + }) + logger.info( + `uniswap.route - Swap price ${price} exceeds limitPrice ${limitPrice}` + ) } } else { // sell - const price = trade.executionPrice.toSignificant(8); - logger.info(`Price: ${price.toString()}`); + const price = trade.executionPrice.toSignificant(8) + logger.info(`Price: ${price.toString()}`) if (!limitPrice || price >= limitPrice) { // pass swaps to exchange-proxy to complete trade const tx = await uniswap.swapExactIn( wallet, trade, baseTokenAddress, - gasPrice, - ); + gasPrice + ) // submit response res.status(200).json({ network: uniswap.network, @@ -241,26 +255,30 @@ router.post('/trade', async (req, res) => { gasPrice, gasLimit, gasCost, - txHash: tx.hash, - }); + txHash: tx.hash + }) } else { res.status(200).json({ error: swapLessThanMaxPriceError, - message: `Swap price ${price} lower than limitPrice ${limitPrice}`, - }); - logger.info(`uniswap.route - Swap price ${price} lower than limitPrice ${limitPrice}`); + message: `Swap price ${price} lower than limitPrice ${limitPrice}` + }) + logger.info( + `uniswap.route - Swap price ${price} lower than limitPrice ${limitPrice}` + ) } } } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/price', async (req, res) => { /* @@ -271,47 +289,49 @@ router.post('/price', async (req, res) => { "amount":1 } */ - const initTime = Date.now(); + const initTime = Date.now() // params: base (required), quote (required), amount (required) - const paramData = getParamData(req.body); - const amount = paramData.amount; + const paramData = getParamData(req.body) + const amount = paramData.amount - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base); - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote); - const baseTokenAddress = baseTokenContractInfo.address; - const quoteTokenAddress = quoteTokenContractInfo.address; - const side = paramData.side.toUpperCase(); - let gasPrice; + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base) + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote) + const baseTokenAddress = baseTokenContractInfo.address + const quoteTokenAddress = quoteTokenContractInfo.address + const side = paramData.side.toUpperCase() + let gasPrice if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice); + gasPrice = parseFloat(paramData.gasPrice) } else { - gasPrice = fees.ethGasPrice; + gasPrice = fees.ethGasPrice } - const gasLimit = estimateGasLimit(); - const gasCost = await fees.getGasCost(gasPrice, gasLimit); + const gasLimit = estimateGasLimit() + const gasCost = await fees.getGasCost(gasPrice, gasLimit) try { // fetch the optimal pool mix from uniswap - const { trade, expectedAmount } = side === 'BUY' - ? await uniswap.priceSwapOut( - quoteTokenAddress, // tokenIn is quote asset - baseTokenAddress, // tokenOut is base asset - amount, - ) - : await uniswap.priceSwapIn( - baseTokenAddress, // tokenIn is base asset - quoteTokenAddress, // tokenOut is quote asset - amount, - ); + const { trade, expectedAmount } = + side === 'BUY' + ? await uniswap.priceSwapOut( + quoteTokenAddress, // tokenIn is quote asset + baseTokenAddress, // tokenOut is base asset + amount + ) + : await uniswap.priceSwapIn( + baseTokenAddress, // tokenIn is base asset + quoteTokenAddress, // tokenOut is quote asset + amount + ) if (trade !== null && expectedAmount !== null) { - const price = side === 'BUY' - ? trade.executionPrice.invert().toSignificant(8) - : trade.executionPrice.toSignificant(8); + const price = + side === 'BUY' + ? trade.executionPrice.invert().toSignificant(8) + : trade.executionPrice.toSignificant(8) - const tradeAmount = parseFloat(amount); - const expectedTradeAmount = parseFloat(expectedAmount.toSignificant(8)); - const tradePrice = parseFloat(price); + const tradeAmount = parseFloat(amount) + const expectedTradeAmount = parseFloat(expectedAmount.toSignificant(8)) + const tradePrice = parseFloat(price) const result = { network: uniswap.network, @@ -325,40 +345,45 @@ router.post('/price', async (req, res) => { gasPrice, gasLimit, gasCost, - trade, - }; - debug(`Price ${side} ${baseTokenContractInfo.symbol}-${quoteTokenContractInfo.symbol} | amount:${amount} (rate:${tradePrice}) - gasPrice:${gasPrice} gasLimit:${gasLimit} estimated fee:${gasCost} ETH`); - res.status(200).json(result); - } else { // no pool available + trade + } + debug( + `Price ${side} ${baseTokenContractInfo.symbol}-${quoteTokenContractInfo.symbol} | amount:${amount} (rate:${tradePrice}) - gasPrice:${gasPrice} gasLimit:${gasLimit} estimated fee:${gasCost} ETH` + ) + res.status(200).json(result) + } else { + // no pool available res.status(200).json({ info: statusMessages.no_pool_available, - message: '', - }); + message: '' + }) } } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - let errCode = 500; + logger.error(req.originalUrl, { message: err }) + let reason + let errCode = 500 if (Object.keys(err).includes('isInsufficientReservesError')) { - errCode = 200; - reason = `${statusMessages.insufficient_reserves} in ${side} at Uniswap`; + errCode = 200 + reason = `${statusMessages.insufficient_reserves} in ${side} at Uniswap` } else if (Object.getOwnPropertyNames(err).includes('message')) { - reason = getErrorMessage(err.message); + reason = getErrorMessage(err.message) if (reason === statusMessages.no_pool_available) { - errCode = 200; + errCode = 200 res.status(errCode).json({ info: reason, - message: err, - }); + message: err + }) } } else { - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) } res.status(errCode).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) -export default router; +export default router diff --git a/src/routes/uniswap_v3.route.js b/src/routes/uniswap_v3.route.js index 7be8d43..c184f40 100644 --- a/src/routes/uniswap_v3.route.js +++ b/src/routes/uniswap_v3.route.js @@ -1,45 +1,48 @@ -import { ethers } from 'ethers'; -import express from 'express'; +import { ethers } from 'ethers' +import express from 'express' import { - getNonceManager, getParamData, latency, statusMessages, -} from '../services/utils'; + getNonceManager, + getParamData, + latency, + statusMessages +} from '../services/utils' -import { logger } from '../services/logger'; -import Ethereum from '../services/eth'; -import UniswapV3 from '../services/uniswap_v3'; -import Fees from '../services/fees'; +import { logger } from '../services/logger' +import Ethereum from '../services/eth' +import UniswapV3 from '../services/uniswap_v3' +import Fees from '../services/fees' -require('dotenv').config(); +require('dotenv').config() -const debug = require('debug')('router'); +const debug = require('debug')('router') -const router = express.Router(); -const eth = new Ethereum(process.env.ETHEREUM_CHAIN); -const uniswap = new UniswapV3(process.env.ETHEREUM_CHAIN); +const router = express.Router() +const eth = new Ethereum(process.env.ETHEREUM_CHAIN) +const uniswap = new UniswapV3(process.env.ETHEREUM_CHAIN) -const fees = new Fees(); +const fees = new Fees() // const swapMoreThanMaxPriceError = 'Price too high' // const swapLessThanMaxPriceError = 'Price too low' -const estimateGasLimit = () => uniswap.gasLimit; +const estimateGasLimit = () => uniswap.gasLimit const getErrorMessage = (err) => { /* [WIP] Custom error message based-on string match */ - let message = err; + let message = err if (err.includes('failed to meet quorum')) { - message = 'Failed to meet quorum in Uniswap'; + message = 'Failed to meet quorum in Uniswap' } else if (err.includes('Invariant failed: ADDRESSES')) { - message = 'Invariant failed: ADDRESSES'; + message = 'Invariant failed: ADDRESSES' } else if (err.includes('"call revert exception')) { - message = statusMessages.no_pool_available; + message = statusMessages.no_pool_available } else if (err.includes('"trade" is read-only')) { - message = statusMessages.no_pool_available; + message = statusMessages.no_pool_available } - return message; -}; + return message +} router.post('/', async (req, res) => { /* @@ -50,32 +53,34 @@ router.post('/', async (req, res) => { provider: uniswap.provider.connection.url, uniswap_router: uniswap.router, connection: true, - timestamp: Date.now(), - }); -}); + timestamp: Date.now() + }) +}) router.post('/gas-limit', async (req, res) => { /* POST: /gas-limit */ - const gasLimit = estimateGasLimit(); + const gasLimit = estimateGasLimit() try { res.status(200).json({ network: uniswap.network, gasLimit, - timestamp: Date.now(), - }); + timestamp: Date.now() + }) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/result', async (req, res) => { /* @@ -84,21 +89,21 @@ router.post('/result', async (req, res) => { "logs":"[...]" } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const logs = JSON.parse(paramData.logs); + const initTime = Date.now() + const paramData = getParamData(req.body) + const logs = JSON.parse(paramData.logs) const result = { network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), - info: uniswap.abiDecoder.decodeLogs(logs), - }; - res.status(200).json(result); -}); + info: uniswap.abiDecoder.decodeLogs(logs) + } + res.status(200).json(result) +}) router.post('/trade', async (req, res) => { -/* + /* POST: /trade x-www-form-urlencoded: { "quote":"BAT" @@ -111,32 +116,36 @@ router.post('/trade', async (req, res) => { "side":{buy|sell} } */ - const initTime = Date.now(); + const initTime = Date.now() // params: privateKey (required), base (required), quote (required), amount (required), maxPrice (required), gasPrice (required) - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - const wallet = await getNonceManager(new ethers.Wallet(privateKey, uniswap.provider)); - const amount = paramData.amount; - - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base); - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote); - const baseTokenAddress = baseTokenContractInfo.address; - const quoteTokenAddress = quoteTokenContractInfo.address; - const side = paramData.side.toUpperCase(); - const tier = paramData.tier.toUpperCase(); - - let limitPrice; + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + const wallet = await getNonceManager( + new ethers.Wallet(privateKey, uniswap.provider) + ) + const amount = paramData.amount + + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base) + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote) + const baseTokenAddress = baseTokenContractInfo.address + const quoteTokenAddress = quoteTokenContractInfo.address + const side = paramData.side.toUpperCase() + const tier = paramData.tier.toUpperCase() + + let limitPrice if (paramData.limitPrice) { - limitPrice = parseFloat(paramData.limitPrice); - } else { limitPrice = 0; } - let gasPrice; + limitPrice = parseFloat(paramData.limitPrice) + } else { + limitPrice = 0 + } + let gasPrice if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice); + gasPrice = parseFloat(paramData.gasPrice) } else { - gasPrice = fees.ethGasPrice; + gasPrice = fees.ethGasPrice } - const gasLimit = estimateGasLimit(); - const gasCost = await fees.getGasCost(gasPrice, gasLimit); + const gasLimit = estimateGasLimit() + const gasCost = await fees.getGasCost(gasPrice, gasLimit) try { if (side === 'BUY') { @@ -147,8 +156,8 @@ router.post('/trade', async (req, res) => { amount, limitPrice, tier, - gasPrice, - ); + gasPrice + ) // submit response res.status(200).json({ network: uniswap.network, @@ -162,8 +171,8 @@ router.post('/trade', async (req, res) => { gasPrice, gasLimit, gasCost, - txHash: tx.hash, - }); + txHash: tx.hash + }) } else { // sell const tx = await uniswap.swapExactIn( @@ -173,8 +182,8 @@ router.post('/trade', async (req, res) => { amount, limitPrice, tier, - gasPrice, - ); + gasPrice + ) // submit response res.status(200).json({ @@ -189,19 +198,21 @@ router.post('/trade', async (req, res) => { gasPrice, gasLimit, gasCost, - txHash: tx.hash, - }); + txHash: tx.hash + }) } } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(500).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/price', async (req, res) => { /* @@ -211,29 +222,35 @@ router.post('/price', async (req, res) => { "base":"DAI" } */ - const initTime = Date.now(); + const initTime = Date.now() // params: base (required), quote (required), amount (required) - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - const wallet = await getNonceManager(new ethers.Wallet(privateKey, uniswap.provider)); - - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base); - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote); - const baseTokenAddress = baseTokenContractInfo.address; - const quoteTokenAddress = quoteTokenContractInfo.address; - - let gasPrice; + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + const wallet = await getNonceManager( + new ethers.Wallet(privateKey, uniswap.provider) + ) + + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base) + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote) + const baseTokenAddress = baseTokenContractInfo.address + const quoteTokenAddress = quoteTokenContractInfo.address + + let gasPrice if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice); + gasPrice = parseFloat(paramData.gasPrice) } else { - gasPrice = fees.ethGasPrice; + gasPrice = fees.ethGasPrice } - const gasLimit = estimateGasLimit(); - const gasCost = await fees.getGasCost(gasPrice, gasLimit); + const gasLimit = estimateGasLimit() + const gasCost = await fees.getGasCost(gasPrice, gasLimit) try { // fetch pools for all tiers - const prices = await uniswap.currentPrice(wallet, baseTokenAddress, quoteTokenAddress); + const prices = await uniswap.currentPrice( + wallet, + baseTokenAddress, + quoteTokenAddress + ) const result = { network: uniswap.network, @@ -244,35 +261,43 @@ router.post('/price', async (req, res) => { prices, gasPrice, gasLimit, - gasCost, - }; - debug(`Mid Price ${baseTokenContractInfo.symbol}-${quoteTokenContractInfo.symbol} | (rate:${JSON.stringify(prices)}) - gasPrice:${gasPrice} gasLimit:${gasLimit} estimated fee:${gasCost} ETH`); - res.status(200).json(result); + gasCost + } + debug( + `Mid Price ${baseTokenContractInfo.symbol}-${ + quoteTokenContractInfo.symbol + } | (rate:${JSON.stringify( + prices + )}) - gasPrice:${gasPrice} gasLimit:${gasLimit} estimated fee:${gasCost} ETH` + ) + res.status(200).json(result) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - let errCode = 500; + logger.error(req.originalUrl, { message: err }) + let reason + let errCode = 500 if (Object.keys(err).includes('isInsufficientReservesError')) { - errCode = 200; - reason = `${statusMessages.insufficient_reserves} at Uniswap`; + errCode = 200 + reason = `${statusMessages.insufficient_reserves} at Uniswap` } else if (Object.getOwnPropertyNames(err).includes('message')) { - reason = getErrorMessage(err.message); + reason = getErrorMessage(err.message) if (reason === statusMessages.no_pool_available) { - errCode = 200; + errCode = 200 res.status(errCode).json({ info: reason, - message: err, - }); + message: err + }) } } else { - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) } res.status(errCode).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) // LP section @@ -283,32 +308,34 @@ router.post('/position', async (req, res) => { "tokenId":"tokenId" } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - const wallet = await getNonceManager(new ethers.Wallet(privateKey, uniswap.provider)); - const tokenId = paramData.tokenId; + const initTime = Date.now() + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + const wallet = await getNonceManager( + new ethers.Wallet(privateKey, uniswap.provider) + ) + const tokenId = paramData.tokenId try { // fetch position data - const positionData = await uniswap.getPosition(wallet, tokenId); + const positionData = await uniswap.getPosition(wallet, tokenId) const result = { network: uniswap.network, timestamp: initTime, latency: latency(initTime, Date.now()), - position: positionData, - }; - debug(`Position data: ${positionData} `); - res.status(200).json(result); + position: positionData + } + debug(`Position data: ${positionData} `) + res.status(200).json(result) } catch (err) { - logger.error(req.originalUrl, { message: err }); + logger.error(req.originalUrl, { message: err }) res.status(500).json({ info: statusMessages.operation_error, - position: {}, - }); + position: {} + }) } -}); +}) router.post('/add-position', async (req, res) => { /* @@ -323,31 +350,42 @@ router.post('/add-position', async (req, res) => { "amount1": amount1 } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - const wallet = await getNonceManager(new ethers.Wallet(privateKey, uniswap.provider)); - - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.token0); - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.token1); - const fee = paramData.fee; - const lowerPrice = parseFloat(paramData.lowerPrice); - const upperPrice = parseFloat(paramData.upperPrice); - const amount0 = paramData.amount0; - const amount1 = paramData.amount1; - - let gasPrice; + const initTime = Date.now() + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + const wallet = await getNonceManager( + new ethers.Wallet(privateKey, uniswap.provider) + ) + + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.token0) + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.token1) + const fee = paramData.fee + const lowerPrice = parseFloat(paramData.lowerPrice) + const upperPrice = parseFloat(paramData.upperPrice) + const amount0 = paramData.amount0 + const amount1 = paramData.amount1 + + let gasPrice if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice); + gasPrice = parseFloat(paramData.gasPrice) } else { - gasPrice = fees.ethGasPrice; + gasPrice = fees.ethGasPrice } - const gasLimit = estimateGasLimit(); - const gasCost = await fees.getGasCost(gasPrice, gasLimit); + const gasLimit = estimateGasLimit() + const gasCost = await fees.getGasCost(gasPrice, gasLimit) try { // add position to pool - const newPosition = await uniswap.addPosition(wallet, baseTokenContractInfo, quoteTokenContractInfo, amount0, amount1, fee, lowerPrice, upperPrice); + const newPosition = await uniswap.addPosition( + wallet, + baseTokenContractInfo, + quoteTokenContractInfo, + amount0, + amount1, + fee, + lowerPrice, + upperPrice + ) const result = { network: uniswap.network, @@ -363,18 +401,18 @@ router.post('/add-position', async (req, res) => { hash: newPosition.hash, gasPrice, gasLimit, - gasCost, - }; - debug(`New Position: ${newPosition.hash}`); - res.status(200).json(result); + gasCost + } + debug(`New Position: ${newPosition.hash}`) + res.status(200).json(result) } catch (err) { - logger.error(req.originalUrl, { message: err }); + logger.error(req.originalUrl, { message: err }) res.status(200).json({ info: statusMessages.operation_error, - message: err, - }); + message: err + }) } -}); +}) router.post('/remove-position', async (req, res) => { /* @@ -383,23 +421,25 @@ router.post('/remove-position', async (req, res) => { "tokenId":"12" } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - const wallet = await getNonceManager(new ethers.Wallet(privateKey, uniswap.provider)); - const tokenId = paramData.tokenId; - - let gasPrice; + const initTime = Date.now() + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + const wallet = await getNonceManager( + new ethers.Wallet(privateKey, uniswap.provider) + ) + const tokenId = paramData.tokenId + + let gasPrice if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice); + gasPrice = parseFloat(paramData.gasPrice) } else { - gasPrice = fees.ethGasPrice; + gasPrice = fees.ethGasPrice } - const gasLimit = estimateGasLimit(); - const gasCost = await fees.getGasCost(gasPrice, gasLimit); + const gasLimit = estimateGasLimit() + const gasCost = await fees.getGasCost(gasPrice, gasLimit) try { - const removelp = await uniswap.removePosition(wallet, tokenId); + const removelp = await uniswap.removePosition(wallet, tokenId) const result = { network: uniswap.network, @@ -408,21 +448,23 @@ router.post('/remove-position', async (req, res) => { hash: removelp.hash, gasPrice, gasLimit, - gasCost, - }; - debug(`Remove lp: ${removelp.hash}`); - res.status(200).json(result); + gasCost + } + debug(`Remove lp: ${removelp.hash}`) + res.status(200).json(result) } catch (err) { - logger.error(req.originalUrl, { message: err }); - let reason; - const errCode = 500; - err.reason ? reason = err.reason : reason = statusMessages.operation_error; + logger.error(req.originalUrl, { message: err }) + let reason + const errCode = 500 + err.reason + ? (reason = err.reason) + : (reason = statusMessages.operation_error) res.status(errCode).json({ error: reason, - message: err, - }); + message: err + }) } -}); +}) router.post('/replace-position', async (req, res) => { /* @@ -438,33 +480,45 @@ router.post('/replace-position', async (req, res) => { "amount1": amount1 } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - const wallet = await getNonceManager(new ethers.Wallet(privateKey, uniswap.provider)); - const tokenId = paramData.tokenId; - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.token0); - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.token1); - const fee = paramData.fee; - const lowerPrice = parseFloat(paramData.lowerPrice); - const upperPrice = parseFloat(paramData.upperPrice); - const amount0 = paramData.amount0; - const amount1 = paramData.amount1; - - let gasPrice; + const initTime = Date.now() + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + const wallet = await getNonceManager( + new ethers.Wallet(privateKey, uniswap.provider) + ) + const tokenId = paramData.tokenId + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.token0) + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.token1) + const fee = paramData.fee + const lowerPrice = parseFloat(paramData.lowerPrice) + const upperPrice = parseFloat(paramData.upperPrice) + const amount0 = paramData.amount0 + const amount1 = paramData.amount1 + + let gasPrice if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice); + gasPrice = parseFloat(paramData.gasPrice) } else { - gasPrice = fees.ethGasPrice; + gasPrice = fees.ethGasPrice } - const gasLimit = estimateGasLimit(); - const gasCost = await fees.getGasCost(gasPrice, gasLimit); + const gasLimit = estimateGasLimit() + const gasCost = await fees.getGasCost(gasPrice, gasLimit) try { // const position = await uniswap.getPosition(wallet, tokenId) // const token0 = eth.getERC20TokenByAddress(position.token0) // const token1 = eth.getERC20TokenByAddress(position.token1) - const positionChange = await uniswap.replacePosition(wallet, tokenId, baseTokenContractInfo, quoteTokenContractInfo, amount0, amount1, fee, lowerPrice, upperPrice); + const positionChange = await uniswap.replacePosition( + wallet, + tokenId, + baseTokenContractInfo, + quoteTokenContractInfo, + amount0, + amount1, + fee, + lowerPrice, + upperPrice + ) const result = { network: uniswap.network, @@ -476,18 +530,18 @@ router.post('/replace-position', async (req, res) => { hash: positionChange.hash, gasPrice, gasLimit, - gasCost, - }; - debug(`Position change ${positionChange.hash}`); - res.status(200).json(result); + gasCost + } + debug(`Position change ${positionChange.hash}`) + res.status(200).json(result) } catch (err) { - logger.error(req.originalUrl, { message: err }); + logger.error(req.originalUrl, { message: err }) res.status(200).json({ info: statusMessages.operation_error, - message: err, - }); + message: err + }) } -}); +}) router.post('/collect-fees', async (req, res) => { /* @@ -498,24 +552,26 @@ router.post('/collect-fees', async (req, res) => { "amount1": amount1 } */ - const initTime = Date.now(); - const paramData = getParamData(req.body); - const privateKey = paramData.privateKey; - const wallet = await getNonceManager(new ethers.Wallet(privateKey, uniswap.provider)); - const tokenId = paramData.tokenId; - - let gasPrice; + const initTime = Date.now() + const paramData = getParamData(req.body) + const privateKey = paramData.privateKey + const wallet = await getNonceManager( + new ethers.Wallet(privateKey, uniswap.provider) + ) + const tokenId = paramData.tokenId + + let gasPrice if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice); + gasPrice = parseFloat(paramData.gasPrice) } else { - gasPrice = fees.ethGasPrice; + gasPrice = fees.ethGasPrice } - const gasLimit = estimateGasLimit(); - const gasCost = await fees.getGasCost(gasPrice, gasLimit); + const gasLimit = estimateGasLimit() + const gasCost = await fees.getGasCost(gasPrice, gasLimit) try { // withdraw fees - const collect = await uniswap.collectFees(wallet, tokenId); + const collect = await uniswap.collectFees(wallet, tokenId) const result = { network: uniswap.network, @@ -525,17 +581,17 @@ router.post('/collect-fees', async (req, res) => { hash: collect.hash, gasPrice, gasLimit, - gasCost, - }; - debug(`Fees: ${collect.hash}`); - res.status(200).json(result); + gasCost + } + debug(`Fees: ${collect.hash}`) + res.status(200).json(result) } catch (err) { - logger.error(req.originalUrl, { message: err }); + logger.error(req.originalUrl, { message: err }) res.status(200).json({ info: statusMessages.operation_error, - message: err, - }); + message: err + }) } -}); +}) -export default router; +export default router diff --git a/src/services/access.js b/src/services/access.js index cf374b9..d917e80 100644 --- a/src/services/access.js +++ b/src/services/access.js @@ -2,23 +2,23 @@ middleware for validating mutual authentication access */ -import { logger } from './logger'; -import { statusMessages } from './utils'; +import { logger } from './logger' +import { statusMessages } from './utils' export const validateAccess = (req, res, next) => { - const cert = req.connection.getPeerCertificate(); + const cert = req.connection.getPeerCertificate() if (req.client.authorized) { - const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; - const method = req.method; - const url = req.url; - const requestInfo = `Request from IP: ${ip} ${method} ${url}`; - console.log(requestInfo); - next(); + const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress + const method = req.method + const url = req.url + const requestInfo = `Request from IP: ${ip} ${method} ${url}` + console.log(requestInfo) + next() } else if (cert.subject) { - logger.error(statusMessages.ssl_cert_invalid); - res.status(403).send({ error: statusMessages.ssl_cert_invalid }); + logger.error(statusMessages.ssl_cert_invalid) + res.status(403).send({ error: statusMessages.ssl_cert_invalid }) } else { - logger.error(statusMessages.ssl_cert_required); - res.status(401).send({ error: statusMessages.ssl_cert_required }); + logger.error(statusMessages.ssl_cert_required) + res.status(401).send({ error: statusMessages.ssl_cert_required }) } -}; +} diff --git a/src/services/balancer.js b/src/services/balancer.js index a954f21..aa3715c 100644 --- a/src/services/balancer.js +++ b/src/services/balancer.js @@ -1,75 +1,92 @@ -import { logger } from './logger'; +import { logger } from './logger' -const debug = require('debug')('router'); -require('dotenv').config(); // DO NOT REMOVE. needed to configure REACT_APP_SUBGRAPH_URL used by @balancer-labs/sor -const sor = require('@balancer-labs/sor'); -const BigNumber = require('bignumber.js'); -const ethers = require('ethers'); -const proxyArtifact = require('../static/ExchangeProxy.json'); +const debug = require('debug')('router') +require('dotenv').config() // DO NOT REMOVE. needed to configure REACT_APP_SUBGRAPH_URL used by @balancer-labs/sor +const sor = require('@balancer-labs/sor') +const BigNumber = require('bignumber.js') +const ethers = require('ethers') +const proxyArtifact = require('../static/ExchangeProxy.json') // constants -const MULTI = '0xeefba1e63905ef1d7acba5a8513c70307c1ce441'; -const MULTI_KOVAN = ' 0x2cc8688C5f75E365aaEEb4ea8D6a480405A48D2A'; -const MAX_UINT = ethers.constants.MaxUint256; -const GAS_BASE = process.env.BALANCER_GAS_BASE || 200688; -const GAS_PER_SWAP = process.env.BALANCER_GAS_PER_SWAP || 100000; +const MULTI = '0xeefba1e63905ef1d7acba5a8513c70307c1ce441' +const MULTI_KOVAN = ' 0x2cc8688C5f75E365aaEEb4ea8D6a480405A48D2A' +const MAX_UINT = ethers.constants.MaxUint256 +const GAS_BASE = process.env.BALANCER_GAS_BASE || 200688 +const GAS_PER_SWAP = process.env.BALANCER_GAS_PER_SWAP || 100000 export default class Balancer { constructor(network = 'kovan') { - const providerUrl = process.env.ETHEREUM_RPC_URL; - this.network = process.env.ETHEREUM_CHAIN; - this.provider = new ethers.providers.JsonRpcProvider(providerUrl); - this.subgraphUrl = process.env.REACT_APP_SUBGRAPH_URL; - this.gasBase = GAS_BASE; - this.gasPerSwap = GAS_PER_SWAP; - this.maxSwaps = process.env.BALANCER_MAX_SWAPS || 4; - this.exchangeProxy = process.env.EXCHANGE_PROXY; - this.cachedPools = []; + const providerUrl = process.env.ETHEREUM_RPC_URL + this.network = process.env.ETHEREUM_CHAIN + this.provider = new ethers.providers.JsonRpcProvider(providerUrl) + this.subgraphUrl = process.env.REACT_APP_SUBGRAPH_URL + this.gasBase = GAS_BASE + this.gasPerSwap = GAS_PER_SWAP + this.maxSwaps = process.env.BALANCER_MAX_SWAPS || 4 + this.exchangeProxy = process.env.EXCHANGE_PROXY + this.cachedPools = [] switch (network) { case 'mainnet': - this.multiCall = MULTI; - break; + this.multiCall = MULTI + break case 'kovan': - this.multiCall = MULTI_KOVAN; - break; + this.multiCall = MULTI_KOVAN + break default: - const err = `Invalid network ${network}`; - logger.error(err); - throw Error(err); + const err = `Invalid network ${network}` + logger.error(err) + throw Error(err) } } async fetchPool(tokenIn, tokenOut) { - const pools = await sor.getPoolsWithTokens(tokenIn, tokenOut); - this.cachedPools[tokenIn + tokenOut] = pools; + const pools = await sor.getPoolsWithTokens(tokenIn, tokenOut) + this.cachedPools[tokenIn + tokenOut] = pools if (pools.pools.length === 0) { - debug('>>> No pools contain the tokens provided.', { message: this.network }); - return {}; + debug('>>> No pools contain the tokens provided.', { + message: this.network + }) + return {} } - debug(`>>> ${pools.pools.length} Pools Retrieved.`, { message: this.network }); + debug(`>>> ${pools.pools.length} Pools Retrieved.`, { + message: this.network + }) } async getCachedPools(tokenIn, tokenOut) { - const cachePools = this.cachedPools[tokenIn + tokenOut].pools; - debug(`>>> get cached Pools. ${tokenIn + tokenOut}`, { message: `total pools: ${cachePools.length}` }); - return cachePools; + const cachePools = this.cachedPools[tokenIn + tokenOut].pools + debug(`>>> get cached Pools. ${tokenIn + tokenOut}`, { + message: `total pools: ${cachePools.length}` + }) + return cachePools } - async priceSwapIn(tokenIn, tokenOut, tokenInAmount, maxSwaps = this.maxSwaps) { + async priceSwapIn( + tokenIn, + tokenOut, + tokenInAmount, + maxSwaps = this.maxSwaps + ) { // Fetch all the pools that contain the tokens provided try { // Get current on-chain data about the fetched pools - await this.fetchPool(tokenIn, tokenOut); + await this.fetchPool(tokenIn, tokenOut) - let poolData; - const cachedPools = await this.getCachedPools(tokenIn, tokenOut); + let poolData + const cachedPools = await this.getCachedPools(tokenIn, tokenOut) if (this.network === 'mainnet') { - poolData = await sor.parsePoolDataOnChain(cachedPools, tokenIn, tokenOut, this.multiCall, this.provider); + poolData = await sor.parsePoolDataOnChain( + cachedPools, + tokenIn, + tokenOut, + this.multiCall, + this.provider + ) } else { // Kovan multicall throws an ENS error - poolData = await sor.parsePoolData(cachedPools, tokenIn, tokenOut); + poolData = await sor.parsePoolData(cachedPools, tokenIn, tokenOut) } // Parse the pools and pass them to smart order outer to get the swaps needed @@ -78,15 +95,15 @@ export default class Balancer { 'swapExactIn', // swapType: string tokenInAmount, // targetInputAmount: BigNumber new BigNumber(maxSwaps.toString()), // maxBalancers: number - 0, // costOutputToken: BigNumber - ); + 0 // costOutputToken: BigNumber + ) - const swapsFormatted = sor.formatSwapsExactAmountIn(sorSwaps, MAX_UINT, 0); - const expectedAmount = sor.calcTotalOutput(swapsFormatted, poolData); - debug(`Expected Out: ${expectedAmount.toString()} (${tokenOut})`); + const swapsFormatted = sor.formatSwapsExactAmountIn(sorSwaps, MAX_UINT, 0) + const expectedAmount = sor.calcTotalOutput(swapsFormatted, poolData) + debug(`Expected Out: ${expectedAmount.toString()} (${tokenOut})`) // Create correct swap format for new proxy - const swaps = []; + const swaps = [] for (let i = 0; i < swapsFormatted.length; i++) { const swap = { pool: swapsFormatted[i].pool, @@ -94,32 +111,43 @@ export default class Balancer { tokenOut, swapAmount: swapsFormatted[i].tokenInParam, limitReturnAmount: swapsFormatted[i].tokenOutParam, - maxPrice: swapsFormatted[i].maxPrice.toString(), - }; - swaps.push(swap); + maxPrice: swapsFormatted[i].maxPrice.toString() + } + swaps.push(swap) } - return { swaps, expectedAmount }; + return { swaps, expectedAmount } } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error in swapExactOut'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error in swapExactOut') + return reason } } - async priceSwapOut(tokenIn, tokenOut, tokenOutAmount, maxSwaps = this.maxSwaps) { + async priceSwapOut( + tokenIn, + tokenOut, + tokenOutAmount, + maxSwaps = this.maxSwaps + ) { // Fetch all the pools that contain the tokens provided try { // Get current on-chain data about the fetched pools - await this.fetchPool(tokenIn, tokenOut); + await this.fetchPool(tokenIn, tokenOut) - let poolData; - const cachedPools = await this.getCachedPools(tokenIn, tokenOut); + let poolData + const cachedPools = await this.getCachedPools(tokenIn, tokenOut) if (this.network === 'mainnet') { - poolData = await sor.parsePoolDataOnChain(cachedPools, tokenIn, tokenOut, this.multiCall, this.provider); + poolData = await sor.parsePoolDataOnChain( + cachedPools, + tokenIn, + tokenOut, + this.multiCall, + this.provider + ) } else { // Kovan multicall throws an ENS error - poolData = await sor.parsePoolData(cachedPools, tokenIn, tokenOut); + poolData = await sor.parsePoolData(cachedPools, tokenIn, tokenOut) } // Parse the pools and pass them to smart order outer to get the swaps needed @@ -128,14 +156,18 @@ export default class Balancer { 'swapExactOut', // swapType: string tokenOutAmount, // targetInputAmount: BigNumber new BigNumber(maxSwaps.toString()), // maxBalancers: number - 0, // costOutputToken: BigNumber - ); - const swapsFormatted = sor.formatSwapsExactAmountOut(sorSwaps, MAX_UINT, MAX_UINT); - const expectedAmount = sor.calcTotalInput(swapsFormatted, poolData); - debug(`Expected In: ${expectedAmount.toString()} (${tokenIn})`); + 0 // costOutputToken: BigNumber + ) + const swapsFormatted = sor.formatSwapsExactAmountOut( + sorSwaps, + MAX_UINT, + MAX_UINT + ) + const expectedAmount = sor.calcTotalInput(swapsFormatted, poolData) + debug(`Expected In: ${expectedAmount.toString()} (${tokenIn})`) // Create correct swap format for new proxy - const swaps = []; + const swaps = [] for (let i = 0; i < swapsFormatted.length; i++) { const swap = { pool: swapsFormatted[i].pool, @@ -143,23 +175,35 @@ export default class Balancer { tokenOut, swapAmount: swapsFormatted[i].tokenOutParam, limitReturnAmount: swapsFormatted[i].tokenInParam, - maxPrice: swapsFormatted[i].maxPrice.toString(), - }; - swaps.push(swap); + maxPrice: swapsFormatted[i].maxPrice.toString() + } + swaps.push(swap) } - return { swaps, expectedAmount }; + return { swaps, expectedAmount } } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error in swapExactOut'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error in swapExactOut') + return reason } } - async swapExactIn(wallet, swaps, tokenIn, tokenOut, amountIn, minAmountOut, gasPrice) { - debug(`Number of swaps: ${swaps.length}`); + async swapExactIn( + wallet, + swaps, + tokenIn, + tokenOut, + amountIn, + minAmountOut, + gasPrice + ) { + debug(`Number of swaps: ${swaps.length}`) try { - const contract = new ethers.Contract(this.exchangeProxy, proxyArtifact.abi, wallet); + const contract = new ethers.Contract( + this.exchangeProxy, + proxyArtifact.abi, + wallet + ) const tx = await contract.batchSwapExactIn( swaps, tokenIn, @@ -168,23 +212,27 @@ export default class Balancer { 0, { gasPrice: gasPrice * 1e9, - gasLimit: GAS_BASE + swaps.length * GAS_PER_SWAP, - }, - ); - debug(`Tx Hash: ${tx.hash}`); - return tx; + gasLimit: GAS_BASE + swaps.length * GAS_PER_SWAP + } + ) + debug(`Tx Hash: ${tx.hash}`) + return tx } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error in swapExactIn'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error in swapExactIn') + return reason } } async swapExactOut(wallet, swaps, tokenIn, tokenOut, expectedIn, gasPrice) { - debug(`Number of swaps: ${swaps.length}`); + debug(`Number of swaps: ${swaps.length}`) try { - const contract = new ethers.Contract(this.exchangeProxy, proxyArtifact.abi, wallet); + const contract = new ethers.Contract( + this.exchangeProxy, + proxyArtifact.abi, + wallet + ) const tx = await contract.batchSwapExactOut( swaps, tokenIn, @@ -192,16 +240,16 @@ export default class Balancer { expectedIn, { gasPrice: gasPrice * 1e9, - gasLimit: GAS_BASE + swaps.length * GAS_PER_SWAP, - }, - ); - debug(`Tx Hash: ${tx.hash}`); - return tx; + gasLimit: GAS_BASE + swaps.length * GAS_PER_SWAP + } + ) + debug(`Tx Hash: ${tx.hash}`) + return tx } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error in swapExactOut'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error in swapExactOut') + return reason } } } diff --git a/src/services/eth.js b/src/services/eth.js index 16bf93a..68d2ae9 100644 --- a/src/services/eth.js +++ b/src/services/eth.js @@ -1,87 +1,99 @@ -import axios from 'axios'; -import { logger } from './logger'; +import axios from 'axios' +import { logger } from './logger' -require('dotenv').config(); -const fs = require('fs'); -const ethers = require('ethers'); -const abi = require('../static/abi'); +require('dotenv').config() +const fs = require('fs') +const ethers = require('ethers') +const abi = require('../static/abi') // constants -const APPROVAL_GAS_LIMIT = process.env.ETH_APPROVAL_GAS_LIMIT || 50000; +const APPROVAL_GAS_LIMIT = process.env.ETH_APPROVAL_GAS_LIMIT || 50000 export default class Ethereum { constructor(network = 'mainnet') { // network defaults to kovan - const providerUrl = process.env.ETHEREUM_RPC_URL; - this.provider = new ethers.providers.JsonRpcProvider(providerUrl); - this.erc20TokenListURL = process.env.ETHEREUM_TOKEN_LIST_URL; - this.network = network; + const providerUrl = process.env.ETHEREUM_RPC_URL + this.provider = new ethers.providers.JsonRpcProvider(providerUrl) + this.erc20TokenListURL = process.env.ETHEREUM_TOKEN_LIST_URL + this.network = network // update token list - this.getERC20TokenList(); // erc20TokenList + this.getERC20TokenList() // erc20TokenList } // get ETH balance async getETHBalance(wallet) { try { - const balance = await wallet.getBalance(); - return balance / 1e18.toString(); + const balance = await wallet.getBalance() + return balance / (1e18).toString() } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error ETH balance lookup'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error ETH balance lookup') + return reason } } // get ERC-20 token balance async getERC20Balance(wallet, tokenAddress, decimals = 18) { // instantiate a contract and pass in provider for read-only access - const contract = new ethers.Contract(tokenAddress, abi.ERC20Abi, this.provider); + const contract = new ethers.Contract( + tokenAddress, + abi.ERC20Abi, + this.provider + ) try { - const balance = await contract.balanceOf(wallet.address); - return balance / (10 ** decimals).toString(); + const balance = await contract.balanceOf(wallet.address) + return balance / (10 ** decimals).toString() } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error balance lookup'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error balance lookup') + return reason } } // get ERC-20 token allowance async getERC20Allowance(wallet, spender, tokenAddress, decimals = 18) { // instantiate a contract and pass in provider for read-only access - const contract = new ethers.Contract(tokenAddress, abi.ERC20Abi, this.provider); + const contract = new ethers.Contract( + tokenAddress, + abi.ERC20Abi, + this.provider + ) try { - const allowance = await contract.allowance(wallet.address, spender); - return allowance / (10 ** decimals).toString(); + const allowance = await contract.allowance(wallet.address, spender) + return allowance / (10 ** decimals).toString() } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error allowance lookup'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error allowance lookup') + return reason } } // approve a spender to transfer tokens from a wallet address - async approveERC20(wallet, spender, tokenAddress, amount, gasPrice = this.gasPrice, _gasLimit) { + async approveERC20( + wallet, + spender, + tokenAddress, + amount, + gasPrice = this.gasPrice, + _gasLimit + ) { try { // fixate gas limit to prevent overwriting - const approvalGasLimit = APPROVAL_GAS_LIMIT; + const approvalGasLimit = APPROVAL_GAS_LIMIT // instantiate a contract and pass in wallet, which act on behalf of that signer - const contract = new ethers.Contract(tokenAddress, abi.ERC20Abi, wallet); - return await contract.approve( - spender, - amount, { - gasPrice: gasPrice * 1e9, - gasLimit: approvalGasLimit, - }, - ); + const contract = new ethers.Contract(tokenAddress, abi.ERC20Abi, wallet) + return await contract.approve(spender, amount, { + gasPrice: gasPrice * 1e9, + gasLimit: approvalGasLimit + }) } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error approval'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error approval') + return reason } } @@ -90,77 +102,98 @@ export default class Ethereum { try { this.provider.getGasPrice().then((gas) => { // gasPrice is a BigNumber; convert it to a decimal string - const gasPrice = gas.toString(); - return gasPrice; - }); + const gasPrice = gas.toString() + return gasPrice + }) } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error gas lookup'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error gas lookup') + return reason } } - async deposit(wallet, tokenAddress, amount, gasPrice = this.gasPrice, gasLimit = this.approvalGasLimit) { + async deposit( + wallet, + tokenAddress, + amount, + gasPrice = this.gasPrice, + gasLimit = this.approvalGasLimit + ) { // deposit ETH to a contract address try { - const contract = new ethers.Contract(tokenAddress, abi.KovanWETHAbi, wallet); - return await contract.deposit( - { - value: amount, - gasPrice: gasPrice * 1e9, - gasLimit, - }, - ); + const contract = new ethers.Contract( + tokenAddress, + abi.KovanWETHAbi, + wallet + ) + return await contract.deposit({ + value: amount, + gasPrice: gasPrice * 1e9, + gasLimit + }) } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error deposit'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error deposit') + return reason } } // get ERC20 Token List async getERC20TokenList() { - let tokenListSource; + let tokenListSource try { if (this.network === 'kovan') { - tokenListSource = 'src/static/erc20_tokens_kovan.json'; - this.erc20TokenList = JSON.parse(fs.readFileSync(tokenListSource)); + tokenListSource = 'src/static/erc20_tokens_kovan.json' + this.erc20TokenList = JSON.parse(fs.readFileSync(tokenListSource)) } else if (this.network === 'mainnet') { - tokenListSource = this.erc20TokenListURL; + tokenListSource = this.erc20TokenListURL if (tokenListSource === undefined || tokenListSource === null) { - const errMessage = 'Token List source not found'; - logger.error('ERC20 Token List Error', { message: errMessage }); - console.log('eth - Error: ', errMessage); + const errMessage = 'Token List source not found' + logger.error('ERC20 Token List Error', { message: errMessage }) + console.log('eth - Error: ', errMessage) } - if (this.erc20TokenList === undefined || this.erc20TokenList === null || this.erc20TokenList === {}) { - const response = await axios.get(tokenListSource); + if ( + this.erc20TokenList === undefined || + this.erc20TokenList === null || + this.erc20TokenList === {} + ) { + const response = await axios.get(tokenListSource) if (response.status === 200 && response.data) { - this.erc20TokenList = response.data; + this.erc20TokenList = response.data } } } else { - throw Error(`Invalid network ${this.network}`); + throw Error(`Invalid network ${this.network}`) } - console.log('get ERC20 Token List', this.network, 'source', tokenListSource); + console.log( + 'get ERC20 Token List', + this.network, + 'source', + tokenListSource + ) } catch (err) { - console.log(err); - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error ERC 20 Token List'; - return reason; + console.log(err) + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error ERC 20 Token List') + return reason } } // Refactor name to getERC20TokenByName getERC20TokenAddresses(tokenSymbol) { - const tokenContractAddress = this.erc20TokenList.tokens.filter((obj) => obj.symbol === tokenSymbol.toUpperCase()); - return tokenContractAddress[0]; + const tokenContractAddress = this.erc20TokenList.tokens.filter( + (obj) => obj.symbol === tokenSymbol.toUpperCase() + ) + return tokenContractAddress[0] } getERC20TokenByAddress(tokenAddress) { - const tokenContract = this.erc20TokenList.tokens.filter((obj) => obj.address.toUpperCase() === tokenAddress.toUpperCase()); - return tokenContract[0]; + const tokenContract = this.erc20TokenList.tokens.filter( + (obj) => obj.address.toUpperCase() === tokenAddress.toUpperCase() + ) + return tokenContract[0] } } diff --git a/src/services/fees.js b/src/services/fees.js index faa5805..4a3ab6e 100644 --- a/src/services/fees.js +++ b/src/services/fees.js @@ -1,52 +1,72 @@ -import axios from 'axios'; -import BigNumber from 'bignumber.js'; -import { logger } from './logger'; +import axios from 'axios' +import BigNumber from 'bignumber.js' +import { logger } from './logger' -require('dotenv').config(); +require('dotenv').config() // constants -const ethGasStationHost = 'https://ethgasstation.info'; -const ethGasStationEnabled = process.env.ENABLE_ETH_GAS_STATION || false; -const ethGasStationApiKey = process.env.ETH_GAS_STATION_API_KEY; -const ethManualGasPrice = parseInt(process.env.MANUAL_GAS_PRICE); -const ethGasStationURL = `${ethGasStationHost}/api/ethgasAPI.json?api-key=${ethGasStationApiKey}`; -const defaultRefreshInterval = 120; -const denom = BigNumber('1e+9'); +const ethGasStationHost = 'https://ethgasstation.info' +const ethGasStationEnabled = process.env.ENABLE_ETH_GAS_STATION || false +const ethGasStationApiKey = process.env.ETH_GAS_STATION_API_KEY +const ethManualGasPrice = parseInt(process.env.MANUAL_GAS_PRICE) +const ethGasStationURL = `${ethGasStationHost}/api/ethgasAPI.json?api-key=${ethGasStationApiKey}` +const defaultRefreshInterval = 120 +const denom = BigNumber('1e+9') export default class Fees { constructor() { - this.ethGasStationGasLevel = process.env.ETH_GAS_STATION_GAS_LEVEL; - this.ethGasStationRefreshTime = (process.env.ETH_GAS_STATION_REFRESH_TIME || defaultRefreshInterval) * 1000; - this.getETHGasStationFee(this.ethGasStationGasLevel, 0); + this.ethGasStationGasLevel = process.env.ETH_GAS_STATION_GAS_LEVEL + this.ethGasStationRefreshTime = + (process.env.ETH_GAS_STATION_REFRESH_TIME || defaultRefreshInterval) * + 1000 + this.getETHGasStationFee(this.ethGasStationGasLevel, 0) } // get ETH Gas Station - async getETHGasStationFee(gasLevel = this.ethGasStationGasLevel, interval = defaultRefreshInterval) { + async getETHGasStationFee( + gasLevel = this.ethGasStationGasLevel, + interval = defaultRefreshInterval + ) { try { - if (ethGasStationEnabled === true || ethGasStationEnabled.toLowerCase() === 'true') { - const response = await axios.get(ethGasStationURL); + if ( + ethGasStationEnabled === true || + ethGasStationEnabled.toLowerCase() === 'true' + ) { + const response = await axios.get(ethGasStationURL) // divite by 10 to convert it to Gwei) - this.ethGasPrice = response.data[gasLevel] / 10; - console.log(`get ETHGasStation gas price (${gasLevel}): ${this.ethGasPrice} / interval: ${this.ethGasStationRefreshTime / 1000} sec`); + this.ethGasPrice = response.data[gasLevel] / 10 + console.log( + `get ETHGasStation gas price (${gasLevel}): ${ + this.ethGasPrice + } / interval: ${this.ethGasStationRefreshTime / 1000} sec` + ) } else { - this.ethGasPrice = ethManualGasPrice; - console.log(`get manual fixed gas price: ${this.ethGasPrice} / interval: ${this.ethGasStationRefreshTime / 1000} sec`); + this.ethGasPrice = ethManualGasPrice + console.log( + `get manual fixed gas price: ${this.ethGasPrice} / interval: ${ + this.ethGasStationRefreshTime / 1000 + } sec` + ) } } catch (err) { - console.log(err); - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error ETH gas fee lookup'; - return reason; + console.log(err) + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error ETH gas fee lookup') + return reason } - if (interval > 0) { // set to '0' for one-time retrieval - setTimeout(this.getETHGasStationFee.bind(this), this.ethGasStationRefreshTime); // update every x seconds + if (interval > 0) { + // set to '0' for one-time retrieval + setTimeout( + this.getETHGasStationFee.bind(this), + this.ethGasStationRefreshTime + ) // update every x seconds } } // get gas cost async getGasCost(gasPrice, gasLimit, inGwei = false) { - const cost = gasPrice * gasLimit; - return inGwei ? cost : cost / denom; + const cost = gasPrice * gasLimit + return inGwei ? cost : cost / denom } } diff --git a/src/services/logger.js b/src/services/logger.js index d12da4c..774e0af 100644 --- a/src/services/logger.js +++ b/src/services/logger.js @@ -1,28 +1,26 @@ -import { getLocalDate } from './utils'; +import { getLocalDate } from './utils' -require('dotenv').config(); -const appRoot = require('app-root-path'); -const winston = require('winston'); -require('winston-daily-rotate-file'); +require('dotenv').config() +const appRoot = require('app-root-path') +const winston = require('winston') +require('winston-daily-rotate-file') const logFormat = winston.format.combine( winston.format.timestamp(), winston.format.align(), - winston.format.printf( - (info) => { - const localDate = getLocalDate(); - return `${localDate} | ${info.level} | ${info.message}`; - }, - ), -); + winston.format.printf((info) => { + const localDate = getLocalDate() + return `${localDate} | ${info.level} | ${info.message}` + }) +) const getLogPath = () => { - let logPath = process.env.LOG_PATH; + let logPath = process.env.LOG_PATH if (typeof logPath === 'undefined' || logPath == null || logPath === '') { - logPath = [appRoot.path, 'logs'].join('/'); + logPath = [appRoot.path, 'logs'].join('/') } - return logPath; -}; + return logPath +} const config = { file: { @@ -30,16 +28,16 @@ const config = { filename: `${getLogPath()}/logs_gateway_app.log.%DATE%`, datePattern: 'YYYY-MM-DD', handleExceptions: true, - handleRejections: true, - }, -}; + handleRejections: true + } +} -const allLogsFileTransport = new winston.transports.DailyRotateFile(config.file); +const allLogsFileTransport = new winston.transports.DailyRotateFile(config.file) const options = { format: logFormat, transports: [allLogsFileTransport], - exitOnError: false, -}; + exitOnError: false +} -export const logger = winston.createLogger(options); +export const logger = winston.createLogger(options) diff --git a/src/services/perpetual_finance.js b/src/services/perpetual_finance.js index 9113ad0..98d0afc 100644 --- a/src/services/perpetual_finance.js +++ b/src/services/perpetual_finance.js @@ -1,67 +1,70 @@ -import { logger } from './logger'; +import { logger } from './logger' -const fetch = require('cross-fetch'); +const fetch = require('cross-fetch') -const Ethers = require('ethers'); -const AmmArtifact = require('@perp/contract/build/contracts/Amm.json'); -const ClearingHouseArtifact = require('@perp/contract/build/contracts/ClearingHouse.json'); -const ClearingHouseViewerArtifact = require('@perp/contract/build/contracts/ClearingHouseViewer.json'); -const TetherTokenArtifact = require('@perp/contract/build/contracts/TetherToken.json'); +const Ethers = require('ethers') +const AmmArtifact = require('@perp/contract/build/contracts/Amm.json') +const ClearingHouseArtifact = require('@perp/contract/build/contracts/ClearingHouse.json') +const ClearingHouseViewerArtifact = require('@perp/contract/build/contracts/ClearingHouseViewer.json') +const TetherTokenArtifact = require('@perp/contract/build/contracts/TetherToken.json') -const GAS_LIMIT = 2123456; -const DEFAULT_DECIMALS = 18; -const CONTRACT_ADDRESSES = 'https://metadata.perp.exchange/'; -const XDAI_PROVIDER = process.env.XDAI_PROVIDER || 'https://dai.poa.network'; -const PNL_OPTION_SPOT_PRICE = 0; -const UPDATE_PERIOD = 60000; // stop updating prices after 30 secs from last request +const GAS_LIMIT = 2123456 +const DEFAULT_DECIMALS = 18 +const CONTRACT_ADDRESSES = 'https://metadata.perp.exchange/' +const XDAI_PROVIDER = process.env.XDAI_PROVIDER || 'https://dai.poa.network' +const PNL_OPTION_SPOT_PRICE = 0 +const UPDATE_PERIOD = 60000 // stop updating prices after 30 secs from last request export default class PerpetualFinance { constructor(network = 'mainnet') { - this.providerUrl = XDAI_PROVIDER; - this.network = network; - this.provider = new Ethers.providers.JsonRpcProvider(this.providerUrl); - this.gasLimit = GAS_LIMIT; - this.contractAddressesUrl = CONTRACT_ADDRESSES; - this.amm = {}; - this.priceCache = {}; - this.cacheExpirary = {}; - this.pairAmountCache = {}; + this.providerUrl = XDAI_PROVIDER + this.network = network + this.provider = new Ethers.providers.JsonRpcProvider(this.providerUrl) + this.gasLimit = GAS_LIMIT + this.contractAddressesUrl = CONTRACT_ADDRESSES + this.amm = {} + this.priceCache = {} + this.cacheExpirary = {} + this.pairAmountCache = {} switch (network) { case 'mainnet': - this.contractAddressesUrl += 'production.json'; - break; + this.contractAddressesUrl += 'production.json' + break case 'kovan': - this.contractAddressesUrl += 'staging.json'; - break; + this.contractAddressesUrl += 'staging.json' + break default: - const err = `Invalid network ${network}`; - logger.error(err); - throw Error(err); + const err = `Invalid network ${network}` + logger.error(err) + throw Error(err) } - this.loadedMetadata = this.load_metadata(); + this.loadedMetadata = this.load_metadata() } async load_metadata() { try { - const metadata = await fetch(this.contractAddressesUrl).then((res) => res.json()); - const layer2 = Object.keys(metadata.layers.layer2.contracts); + const metadata = await fetch(this.contractAddressesUrl).then((res) => + res.json() + ) + const layer2 = Object.keys(metadata.layers.layer2.contracts) for (const key of layer2) { if (metadata.layers.layer2.contracts[key].name === 'Amm') { - this.amm[key] = metadata.layers.layer2.contracts[key].address; + this.amm[key] = metadata.layers.layer2.contracts[key].address } else { - this[key] = metadata.layers.layer2.contracts[key].address; + this[key] = metadata.layers.layer2.contracts[key].address } } - this.layer2AmbAddr = metadata.layers.layer2.externalContracts.ambBridgeOnXDai; - this.xUsdcAddr = metadata.layers.layer2.externalContracts.usdc; - this.loadedMetadata = true; - return true; + this.layer2AmbAddr = + metadata.layers.layer2.externalContracts.ambBridgeOnXDai + this.xUsdcAddr = metadata.layers.layer2.externalContracts.usdc + this.loadedMetadata = true + return true } catch (err) { - return false; + return false } } @@ -69,70 +72,104 @@ export default class PerpetualFinance { if (Object.keys(this.cacheExpirary).length > 0) { for (const pair in this.cacheExpirary) { if (this.cacheExpirary[pair] <= Date.now()) { - delete this.cacheExpirary[pair]; - delete this.priceCache[pair]; + delete this.cacheExpirary[pair] + delete this.priceCache[pair] } } for (const pair in this.cacheExpirary) { - const amm = new Ethers.Contract(this.amm[pair], AmmArtifact.abi, this.provider); - await Promise.allSettled([amm.getInputPrice(0, { d: Ethers.utils.parseUnits(this.pairAmountCache[pair], DEFAULT_DECIMALS) }), - amm.getOutputPrice(0, { d: Ethers.utils.parseUnits(this.pairAmountCache[pair], DEFAULT_DECIMALS) })]) - .then((values) => { - if (!this.priceCache.hasOwnProperty(pair)) { this.priceCache[pair] = []; } - this.priceCache[pair][0] = this.pairAmountCache[pair] / Ethers.utils.formatUnits(values[0].value.d); - this.priceCache[pair][1] = Ethers.utils.formatUnits(values[1].value.d) / this.pairAmountCache[pair]; - }); + const amm = new Ethers.Contract( + this.amm[pair], + AmmArtifact.abi, + this.provider + ) + await Promise.allSettled([ + amm.getInputPrice(0, { + d: Ethers.utils.parseUnits( + this.pairAmountCache[pair], + DEFAULT_DECIMALS + ) + }), + amm.getOutputPrice(0, { + d: Ethers.utils.parseUnits( + this.pairAmountCache[pair], + DEFAULT_DECIMALS + ) + }) + ]).then((values) => { + if (!this.priceCache.hasOwnProperty(pair)) { + this.priceCache[pair] = [] + } + this.priceCache[pair][0] = + this.pairAmountCache[pair] / + Ethers.utils.formatUnits(values[0].value.d) + this.priceCache[pair][1] = + Ethers.utils.formatUnits(values[1].value.d) / + this.pairAmountCache[pair] + }) } } - setTimeout(this.update_price_loop.bind(this), 10000); // update every 10 seconds + setTimeout(this.update_price_loop.bind(this), 10000) // update every 10 seconds } // get XDai balance async getXdaiBalance(wallet) { try { - const xDaiBalance = await wallet.getBalance(); - return Ethers.utils.formatEther(xDaiBalance); + const xDaiBalance = await wallet.getBalance() + return Ethers.utils.formatEther(xDaiBalance) } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error xDai balance lookup'; - return reason; + logger.error(err) + let reason + err.reason + ? (reason = err.reason) + : (reason = 'error xDai balance lookup') + return reason } } // get XDai USDC balance async getUSDCBalance(wallet) { try { - const layer2Usdc = new Ethers.Contract(this.xUsdcAddr, TetherTokenArtifact.abi, wallet); - const layer2UsdcBalance = await layer2Usdc.balanceOf(wallet.address); - const layer2UsdcDecimals = await layer2Usdc.decimals(); - return Ethers.utils.formatUnits(layer2UsdcBalance, layer2UsdcDecimals); + const layer2Usdc = new Ethers.Contract( + this.xUsdcAddr, + TetherTokenArtifact.abi, + wallet + ) + const layer2UsdcBalance = await layer2Usdc.balanceOf(wallet.address) + const layer2UsdcDecimals = await layer2Usdc.decimals() + return Ethers.utils.formatUnits(layer2UsdcBalance, layer2UsdcDecimals) } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error balance lookup'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error balance lookup') + return reason } } // get allowance async getAllowance(wallet) { // instantiate a contract and pass in provider for read-only access - const layer2Usdc = new Ethers.Contract(this.xUsdcAddr, TetherTokenArtifact.abi, wallet); + const layer2Usdc = new Ethers.Contract( + this.xUsdcAddr, + TetherTokenArtifact.abi, + wallet + ) try { const allowanceForClearingHouse = await layer2Usdc.allowance( wallet.address, - this.ClearingHouse, - ); + this.ClearingHouse + ) - return Ethers.utils.formatUnits(allowanceForClearingHouse, DEFAULT_DECIMALS); + return Ethers.utils.formatUnits( + allowanceForClearingHouse, + DEFAULT_DECIMALS + ) } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error allowance lookup'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error allowance lookup') + return reason } } @@ -140,157 +177,242 @@ export default class PerpetualFinance { async approve(wallet, amount) { try { // instantiate a contract and pass in wallet - const layer2Usdc = new Ethers.Contract(this.xUsdcAddr, TetherTokenArtifact.abi, wallet); - const tx = await layer2Usdc.approve(this.ClearingHouse, Ethers.utils.parseUnits(amount, DEFAULT_DECIMALS)); + const layer2Usdc = new Ethers.Contract( + this.xUsdcAddr, + TetherTokenArtifact.abi, + wallet + ) + const tx = await layer2Usdc.approve( + this.ClearingHouse, + Ethers.utils.parseUnits(amount, DEFAULT_DECIMALS) + ) // TO-DO: We may want to supply custom gasLimit value above - return tx.hash; + return tx.hash } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error approval'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error approval') + return reason } } // open Position async openPosition(side, margin, levrg, pair, minBaseAmount, wallet) { try { - const quoteAssetAmount = { d: Ethers.utils.parseUnits(margin, DEFAULT_DECIMALS) }; - const leverage = { d: Ethers.utils.parseUnits(levrg, DEFAULT_DECIMALS) }; - const minBaseAssetAmount = { d: Ethers.utils.parseUnits(minBaseAmount, DEFAULT_DECIMALS) }; - const clearingHouse = new Ethers.Contract(this.ClearingHouse, ClearingHouseArtifact.abi, wallet); + const quoteAssetAmount = { + d: Ethers.utils.parseUnits(margin, DEFAULT_DECIMALS) + } + const leverage = { d: Ethers.utils.parseUnits(levrg, DEFAULT_DECIMALS) } + const minBaseAssetAmount = { + d: Ethers.utils.parseUnits(minBaseAmount, DEFAULT_DECIMALS) + } + const clearingHouse = new Ethers.Contract( + this.ClearingHouse, + ClearingHouseArtifact.abi, + wallet + ) const tx = await clearingHouse.openPosition( this.amm[pair], side, quoteAssetAmount, leverage, minBaseAssetAmount, - { gasLimit: this.gasLimit }, - ); - return tx; + { gasLimit: this.gasLimit } + ) + return tx } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error opening position'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error opening position') + return reason } } // close Position async closePosition(wallet, pair, minimalQuote) { try { - const minimalQuoteAsset = { d: Ethers.utils.parseUnits(minimalQuote, DEFAULT_DECIMALS) }; - const clearingHouse = new Ethers.Contract(this.ClearingHouse, ClearingHouseArtifact.abi, wallet); - const tx = await clearingHouse.closePosition(this.amm[pair], minimalQuoteAsset, { gasLimit: this.gasLimit }); - return tx; + const minimalQuoteAsset = { + d: Ethers.utils.parseUnits(minimalQuote, DEFAULT_DECIMALS) + } + const clearingHouse = new Ethers.Contract( + this.ClearingHouse, + ClearingHouseArtifact.abi, + wallet + ) + const tx = await clearingHouse.closePosition( + this.amm[pair], + minimalQuoteAsset, + { gasLimit: this.gasLimit } + ) + return tx } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error closing position'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error closing position') + return reason } } // get active position async getPosition(wallet, pair) { try { - const positionValues = {}; - const clearingHouse = new Ethers.Contract(this.ClearingHouse, ClearingHouseArtifact.abi, wallet); - let premIndex = 0; - await Promise.allSettled([clearingHouse.getPosition(this.amm[pair], - wallet.address), - clearingHouse.getLatestCumulativePremiumFraction(this.amm[pair]), - clearingHouse.getPositionNotionalAndUnrealizedPnl(this.amm[pair], - wallet.address, - Ethers.BigNumber.from(PNL_OPTION_SPOT_PRICE))]) - .then((values) => { - positionValues.openNotional = Ethers.utils.formatUnits(values[0].value.openNotional.d, DEFAULT_DECIMALS); - positionValues.size = Ethers.utils.formatUnits(values[0].value.size.d, DEFAULT_DECIMALS); - positionValues.margin = Ethers.utils.formatUnits(values[0].value.margin.d, DEFAULT_DECIMALS); - positionValues.cumulativePremiumFraction = Ethers.utils.formatUnits(values[0].value.lastUpdatedCumulativePremiumFraction.d, DEFAULT_DECIMALS); - premIndex = Ethers.utils.formatUnits(values[1].value.d, DEFAULT_DECIMALS); - positionValues.pnl = Ethers.utils.formatUnits(values[2].value.unrealizedPnl.d, DEFAULT_DECIMALS); - positionValues.positionNotional = Ethers.utils.formatUnits(values[2].value.positionNotional.d, DEFAULT_DECIMALS); - }); + const positionValues = {} + const clearingHouse = new Ethers.Contract( + this.ClearingHouse, + ClearingHouseArtifact.abi, + wallet + ) + let premIndex = 0 + await Promise.allSettled([ + clearingHouse.getPosition(this.amm[pair], wallet.address), + clearingHouse.getLatestCumulativePremiumFraction(this.amm[pair]), + clearingHouse.getPositionNotionalAndUnrealizedPnl( + this.amm[pair], + wallet.address, + Ethers.BigNumber.from(PNL_OPTION_SPOT_PRICE) + ) + ]).then((values) => { + positionValues.openNotional = Ethers.utils.formatUnits( + values[0].value.openNotional.d, + DEFAULT_DECIMALS + ) + positionValues.size = Ethers.utils.formatUnits( + values[0].value.size.d, + DEFAULT_DECIMALS + ) + positionValues.margin = Ethers.utils.formatUnits( + values[0].value.margin.d, + DEFAULT_DECIMALS + ) + positionValues.cumulativePremiumFraction = Ethers.utils.formatUnits( + values[0].value.lastUpdatedCumulativePremiumFraction.d, + DEFAULT_DECIMALS + ) + premIndex = Ethers.utils.formatUnits( + values[1].value.d, + DEFAULT_DECIMALS + ) + positionValues.pnl = Ethers.utils.formatUnits( + values[2].value.unrealizedPnl.d, + DEFAULT_DECIMALS + ) + positionValues.positionNotional = Ethers.utils.formatUnits( + values[2].value.positionNotional.d, + DEFAULT_DECIMALS + ) + }) - positionValues.entryPrice = Math.abs(positionValues.openNotional / positionValues.size); - positionValues.fundingPayment = (premIndex - positionValues.cumulativePremiumFraction) * positionValues.size; // * -1 - return positionValues; + positionValues.entryPrice = Math.abs( + positionValues.openNotional / positionValues.size + ) + positionValues.fundingPayment = + (premIndex - positionValues.cumulativePremiumFraction) * + positionValues.size // * -1 + return positionValues } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error getting active position'; - return reason; + logger.error(err) + let reason + err.reason + ? (reason = err.reason) + : (reason = 'error getting active position') + return reason } } // get active margin async getActiveMargin(wallet) { try { - const clearingHouseViewer = new Ethers.Contract(this.ClearingHouseViewer, ClearingHouseViewerArtifact.abi, wallet); - const activeMargin = await clearingHouseViewer.getPersonalBalanceWithFundingPayment( - this.xUsdcAddr, - wallet.address, - ); - return activeMargin / 1e18.toString(); + const clearingHouseViewer = new Ethers.Contract( + this.ClearingHouseViewer, + ClearingHouseViewerArtifact.abi, + wallet + ) + const activeMargin = + await clearingHouseViewer.getPersonalBalanceWithFundingPayment( + this.xUsdcAddr, + wallet.address + ) + return activeMargin / (1e18).toString() } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error getting active position'; - return reason; + logger.error(err) + let reason + err.reason + ? (reason = err.reason) + : (reason = 'error getting active position') + return reason } } // get Price async getPrice(side, amount, pair) { try { - let price; - this.cacheExpirary[pair] = Date.now() + UPDATE_PERIOD; - this.pairAmountCache[pair] = amount; + let price + this.cacheExpirary[pair] = Date.now() + UPDATE_PERIOD + this.pairAmountCache[pair] = amount if (!this.priceCache.hasOwnProperty(pair)) { - const amm = new Ethers.Contract(this.amm[pair], AmmArtifact.abi, this.provider); + const amm = new Ethers.Contract( + this.amm[pair], + AmmArtifact.abi, + this.provider + ) if (side === 'buy') { - price = await amm.getInputPrice(0, { d: Ethers.utils.parseUnits(amount, DEFAULT_DECIMALS) }); - price = amount / Ethers.utils.formatUnits(price.d); + price = await amm.getInputPrice(0, { + d: Ethers.utils.parseUnits(amount, DEFAULT_DECIMALS) + }) + price = amount / Ethers.utils.formatUnits(price.d) } else { - price = await amm.getOutputPrice(0, { d: Ethers.utils.parseUnits(amount, DEFAULT_DECIMALS) }); - price = Ethers.utils.formatUnits(price.d) / amount; + price = await amm.getOutputPrice(0, { + d: Ethers.utils.parseUnits(amount, DEFAULT_DECIMALS) + }) + price = Ethers.utils.formatUnits(price.d) / amount } } else if (side === 'buy') { - price = this.priceCache[pair][0]; - } else { price = this.priceCache[pair][1]; } - return price; + price = this.priceCache[pair][0] + } else { + price = this.priceCache[pair][1] + } + return price } catch (err) { - console.log(err); - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error getting Price'; - return reason; + console.log(err) + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error getting Price') + return reason } } // get getFundingRate async getFundingRate(pair) { try { - const funding = {}; - const amm = new Ethers.Contract(this.amm[pair], AmmArtifact.abi, this.provider); - await Promise.allSettled([amm.getUnderlyingTwapPrice(3600), + const funding = {} + const amm = new Ethers.Contract( + this.amm[pair], + AmmArtifact.abi, + this.provider + ) + await Promise.allSettled([ + amm.getUnderlyingTwapPrice(3600), amm.getTwapPrice(3600), - amm.nextFundingTime()]) - .then((values) => { - funding.indexPrice = parseFloat(Ethers.utils.formatUnits(values[0].value.d)); - funding.markPrice = parseFloat(Ethers.utils.formatUnits(values[1].value.d)); - funding.nextFundingTime = parseInt(values[2].value.toString()); - }); + amm.nextFundingTime() + ]).then((values) => { + funding.indexPrice = parseFloat( + Ethers.utils.formatUnits(values[0].value.d) + ) + funding.markPrice = parseFloat( + Ethers.utils.formatUnits(values[1].value.d) + ) + funding.nextFundingTime = parseInt(values[2].value.toString()) + }) - funding.rate = ((funding.markPrice - funding.indexPrice) / 24) / funding.indexPrice; - return funding; + funding.rate = + (funding.markPrice - funding.indexPrice) / 24 / funding.indexPrice + return funding } catch (err) { - console.log(err); - logger.error(err)(); - let reason; - err.reason ? reason = err.reason : reason = 'error getting fee'; - return reason; + console.log(err) + logger.error(err)() + let reason + err.reason ? (reason = err.reason) : (reason = 'error getting fee') + return reason } } } diff --git a/src/services/terra.js b/src/services/terra.js index 613f284..48d8485 100644 --- a/src/services/terra.js +++ b/src/services/terra.js @@ -1,12 +1,16 @@ import { - LCDClient, Coin, MsgSwap, MnemonicKey, isTxError, -} from '@terra-money/terra.js'; -import BigNumber from 'bignumber.js'; -import { logger } from './logger'; -import { getHummingbotMemo } from './utils'; - -const debug = require('debug')('router'); -require('dotenv').config(); + LCDClient, + Coin, + MsgSwap, + MnemonicKey, + isTxError +} from '@terra-money/terra.js' +import BigNumber from 'bignumber.js' +import { logger } from './logger' +import { getHummingbotMemo } from './utils' + +const debug = require('debug')('router') +require('dotenv').config() // constants const TERRA_TOKENS = { @@ -14,36 +18,36 @@ const TERRA_TOKENS = { uusd: { symbol: 'UST' }, ukrw: { symbol: 'KRT' }, usdr: { symbol: 'SDT' }, - umnt: { symbol: 'MNT' }, -}; -const DENOM_UNIT = BigNumber('1e+6'); -const TOBIN_TAX = 0.0025; // a Tobin Tax (set at 0.25%) for spot-converting Terra<>Terra swaps -const MIN_SPREAD = 0.02; // a minimum spread (set at 2%) for Terra<>Luna swaps -const GAS_PRICE = { uluna: 0.16 }; -const GAS_ADJUSTMENT = 1.4; + umnt: { symbol: 'MNT' } +} +const DENOM_UNIT = BigNumber('1e+6') +const TOBIN_TAX = 0.0025 // a Tobin Tax (set at 0.25%) for spot-converting Terra<>Terra swaps +const MIN_SPREAD = 0.02 // a minimum spread (set at 2%) for Terra<>Luna swaps +const GAS_PRICE = { uluna: 0.16 } +const GAS_ADJUSTMENT = 1.4 export default class Terra { constructor() { - this.lcdUrl = process.env.TERRA_LCD_URL; - this.network = process.env.TERRA_CHAIN; - this.tokens = TERRA_TOKENS; - this.denomUnitMultiplier = DENOM_UNIT; - this.tobinTax = TOBIN_TAX; - this.minSpread = MIN_SPREAD; - this.memo = getHummingbotMemo(); + this.lcdUrl = process.env.TERRA_LCD_URL + this.network = process.env.TERRA_CHAIN + this.tokens = TERRA_TOKENS + this.denomUnitMultiplier = DENOM_UNIT + this.tobinTax = TOBIN_TAX + this.minSpread = MIN_SPREAD + this.memo = getHummingbotMemo() try { - this.lcd = this.connect(); + this.lcd = this.connect() this.lcd.market.parameters().catch(() => { - throw new Error('Connection error'); - }); + throw new Error('Connection error') + }) // set gas & fee - this.lcd.config.gasAdjustment = GAS_ADJUSTMENT; - this.lcd.config.gasPrices = GAS_PRICE; + this.lcd.config.gasAdjustment = GAS_ADJUSTMENT + this.lcd.config.gasPrices = GAS_PRICE } catch (err) { - logger.error(err); - throw Error(`Connection failed: ${this.network}`); + logger.error(err) + throw Error(`Connection failed: ${this.network}`) } } @@ -52,268 +56,307 @@ export default class Terra { try { const lcd = new LCDClient({ URL: this.lcdUrl, - chainID: this.network, - }); - lcd.config.gasAdjustment = GAS_ADJUSTMENT; - lcd.config.gasPrices = GAS_PRICE; - return lcd; + chainID: this.network + }) + lcd.config.gasAdjustment = GAS_ADJUSTMENT + lcd.config.gasPrices = GAS_PRICE + return lcd } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error Terra LCD connect'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error Terra LCD connect') + return reason } } // get Token Denom getTokenDenom(symbol) { try { - let denom; + let denom Object.keys(TERRA_TOKENS).forEach((item) => { if (TERRA_TOKENS[item].symbol === symbol) { - denom = item; + denom = item } - }); - return denom; + }) + return denom } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error Terra Denom lookup'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error Terra Denom lookup') + return reason } } // get Token Symbol getTokenSymbol(denom) { try { - const { symbol } = TERRA_TOKENS[denom]; - return symbol; + const { symbol } = TERRA_TOKENS[denom] + return symbol } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error Terra Denom lookup'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error Terra Denom lookup') + return reason } } getTxAttributes(attributes) { - const attrib = {}; + const attrib = {} attributes.forEach((item) => { - attrib[item.key] = item.value; - }); - return attrib; + attrib[item.key] = item.value + }) + return attrib } async getEstimateFee(tx) { try { - const fee = await this.lcd.tx.estimateFee(tx); - return fee; + const fee = await this.lcd.tx.estimateFee(tx) + return fee } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error Terra estimate fee lookup'; - return reason; + logger.error(err) + let reason + err.reason + ? (reason = err.reason) + : (reason = 'error Terra estimate fee lookup') + return reason } } async getExchangeRate(denom) { try { - const exchangeRates = await this.lcd.oracle.exchangeRates(); - return exchangeRates.get(denom); + const exchangeRates = await this.lcd.oracle.exchangeRates() + return exchangeRates.get(denom) } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error Terra exchange rate lookup'; - return reason; + logger.error(err) + let reason + err.reason + ? (reason = err.reason) + : (reason = 'error Terra exchange rate lookup') + return reason } } async getTxFee() { try { - const lunaFee = GAS_PRICE.uluna * GAS_ADJUSTMENT; - const feeList = { uluna: lunaFee }; + const lunaFee = GAS_PRICE.uluna * GAS_ADJUSTMENT + const feeList = { uluna: lunaFee } await this.lcd.oracle.exchangeRates().then((rates) => { Object.keys(rates._coins).forEach((key) => { - feeList[key] = rates._coins[key].amount * lunaFee; - }); - }); - debug('lunaFee', lunaFee, feeList); + feeList[key] = rates._coins[key].amount * lunaFee + }) + }) + debug('lunaFee', lunaFee, feeList) - return feeList; + return feeList } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error Terra exchange rate lookup'; - return reason; + logger.error(err) + let reason + err.reason + ? (reason = err.reason) + : (reason = 'error Terra exchange rate lookup') + return reason } } // get Terra Swap Rate async getSwapRate(baseToken, quoteToken, amount, tradeType) { try { - let exchangeRate; let offerCoin; let offerDenom; let swapDenom; let cost; let costAmount; let - offer; - const swaps = {}; + let exchangeRate + let offerCoin + let offerDenom + let swapDenom + let cost + let costAmount + let offer + const swaps = {} if (tradeType.toLowerCase() === 'sell') { // sell base - offerDenom = this.getTokenDenom(baseToken); - swapDenom = this.getTokenDenom(quoteToken); - - offerCoin = new Coin(offerDenom, amount * DENOM_UNIT); - await this.lcd.market.swapRate(offerCoin, swapDenom).then((swapCoin) => { - offer = { amount }; - exchangeRate = { - amount: (swapCoin.amount / DENOM_UNIT) / amount, - token: quoteToken, - }; - costAmount = amount * exchangeRate.amount; - cost = { - amount: costAmount, - token: quoteToken, - }; - }); + offerDenom = this.getTokenDenom(baseToken) + swapDenom = this.getTokenDenom(quoteToken) + + offerCoin = new Coin(offerDenom, amount * DENOM_UNIT) + await this.lcd.market + .swapRate(offerCoin, swapDenom) + .then((swapCoin) => { + offer = { amount } + exchangeRate = { + amount: swapCoin.amount / DENOM_UNIT / amount, + token: quoteToken + } + costAmount = amount * exchangeRate.amount + cost = { + amount: costAmount, + token: quoteToken + } + }) } else { // buy base - offerDenom = this.getTokenDenom(quoteToken); - swapDenom = this.getTokenDenom(baseToken); - - offerCoin = new Coin(offerDenom, 1 * DENOM_UNIT); - await this.lcd.market.swapRate(offerCoin, swapDenom).then((swapCoin) => { - exchangeRate = { - amount: (amount / parseInt(swapCoin.amount) * DENOM_UNIT) / amount, // adjusted amount - token: quoteToken, - }; - costAmount = amount * exchangeRate.amount; - cost = { - amount: costAmount, - token: quoteToken, - }; - offer = { amount: cost.amount }; - }); + offerDenom = this.getTokenDenom(quoteToken) + swapDenom = this.getTokenDenom(baseToken) + + offerCoin = new Coin(offerDenom, 1 * DENOM_UNIT) + await this.lcd.market + .swapRate(offerCoin, swapDenom) + .then((swapCoin) => { + exchangeRate = { + amount: + ((amount / parseInt(swapCoin.amount)) * DENOM_UNIT) / amount, // adjusted amount + token: quoteToken + } + costAmount = amount * exchangeRate.amount + cost = { + amount: costAmount, + token: quoteToken + } + offer = { amount: cost.amount } + }) } - let txFee; + let txFee await this.getTxFee().then((fee) => { // fee in quote - txFee = { amount: parseFloat(fee[this.getTokenDenom(quoteToken)]), token: quoteToken }; - }); - - swaps.offer = offer; - swaps.price = exchangeRate; - swaps.cost = cost; - swaps.txFee = txFee; - debug('swaps', swaps); - return swaps; + txFee = { + amount: parseFloat(fee[this.getTokenDenom(quoteToken)]), + token: quoteToken + } + }) + + swaps.offer = offer + swaps.price = exchangeRate + swaps.cost = cost + swaps.txFee = txFee + debug('swaps', swaps) + return swaps } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = 'error swap rate lookup'; - return reason; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = 'error swap rate lookup') + return reason } } // Swap tokens - async swapTokens(baseToken, quoteToken, amount, tradeType, gasPrice, gasAdjustment, secret) { - let swapResult; + async swapTokens( + baseToken, + quoteToken, + amount, + tradeType, + gasPrice, + gasAdjustment, + secret + ) { + let swapResult try { // connect to lcd - const lcd = this.connect(); + const lcd = this.connect() const mk = new MnemonicKey({ - mnemonic: secret, - }); - let wallet; + mnemonic: secret + }) + let wallet try { - wallet = lcd.wallet(mk); + wallet = lcd.wallet(mk) } catch (err) { - logger.error(err); - throw Error('Wallet access error'); + logger.error(err) + throw Error('Wallet access error') } - const address = wallet.key.accAddress; + const address = wallet.key.accAddress // get the current swap rate - const baseDenom = this.getTokenDenom(baseToken); - const quoteDenom = this.getTokenDenom(quoteToken); + const baseDenom = this.getTokenDenom(baseToken) + const quoteDenom = this.getTokenDenom(quoteToken) - let offerDenom; let - swapDenom; - let swaps; let - txAttributes; - const tokenSwap = {}; + let offerDenom + let swapDenom + let swaps + let txAttributes + const tokenSwap = {} if (tradeType.toLowerCase() === 'sell') { - offerDenom = baseDenom; - swapDenom = quoteDenom; + offerDenom = baseDenom + swapDenom = quoteDenom } else { - offerDenom = quoteDenom; - swapDenom = baseDenom; + offerDenom = quoteDenom + swapDenom = baseDenom } - await this.getSwapRate(baseToken, quoteToken, amount, tradeType, secret).then((rate) => { - swaps = rate; - }); + await this.getSwapRate( + baseToken, + quoteToken, + amount, + tradeType, + secret + ).then((rate) => { + swaps = rate + }) - const offerAmount = parseInt((swaps.offer.amount) * DENOM_UNIT); - const offerCoin = new Coin(offerDenom, offerAmount); + const offerAmount = parseInt(swaps.offer.amount * DENOM_UNIT) + const offerCoin = new Coin(offerDenom, offerAmount) // Create and Sign Transaction - const msgSwap = new MsgSwap(address, offerCoin, swapDenom); + const msgSwap = new MsgSwap(address, offerCoin, swapDenom) - let txOptions; - if (gasPrice !== null && gasPrice !== null) { // ignore gasAdjustment when gasPrice is not set + let txOptions + if (gasPrice !== null && gasPrice !== null) { + // ignore gasAdjustment when gasPrice is not set txOptions = { msgs: [msgSwap], gasPrices: { uluna: parseFloat(gasPrice) }, gasAdjustment, - memo: this.memo, - }; + memo: this.memo + } } else { txOptions = { msgs: [msgSwap], - memo: this.memo, - }; + memo: this.memo + } } - await wallet.createAndSignTx(txOptions).then((tx) => lcd.tx.broadcast(tx)).then((txResult) => { - swapResult = txResult; - - const swapSuccess = !isTxError(txResult); - if (swapSuccess) { - tokenSwap.txSuccess = swapSuccess; - } else { - tokenSwap.txSuccess = !swapSuccess; - throw new Error(`encountered an error while running the transaction: ${txResult.code} ${txResult.codespace}`); - } - const txHash = txResult.txhash; - const { events } = JSON.parse(txResult.raw_log)[0]; - const swap = events.find((obj) => obj.type === 'swap'); - txAttributes = this.getTxAttributes(swap.attributes); - const offer = Coin.fromString(txAttributes.offer); - const ask = Coin.fromString(txAttributes.swap_coin); - const fee = Coin.fromString(txAttributes.swap_fee); - - tokenSwap.expectedIn = { - amount: parseFloat(offer.amount) / DENOM_UNIT, - token: TERRA_TOKENS[offer.denom].symbol, - }; - tokenSwap.expectedOut = { - amount: parseFloat(ask.amount) / DENOM_UNIT, - token: TERRA_TOKENS[ask.denom].symbol, - }; - tokenSwap.fee = { - amount: parseFloat(fee.amount) / DENOM_UNIT, - token: TERRA_TOKENS[fee.denom].symbol, - }; - tokenSwap.txHash = txHash; - }); - return tokenSwap; + await wallet + .createAndSignTx(txOptions) + .then((tx) => lcd.tx.broadcast(tx)) + .then((txResult) => { + swapResult = txResult + + const swapSuccess = !isTxError(txResult) + if (swapSuccess) { + tokenSwap.txSuccess = swapSuccess + } else { + tokenSwap.txSuccess = !swapSuccess + throw new Error( + `encountered an error while running the transaction: ${txResult.code} ${txResult.codespace}` + ) + } + const txHash = txResult.txhash + const { events } = JSON.parse(txResult.raw_log)[0] + const swap = events.find((obj) => obj.type === 'swap') + txAttributes = this.getTxAttributes(swap.attributes) + const offer = Coin.fromString(txAttributes.offer) + const ask = Coin.fromString(txAttributes.swap_coin) + const fee = Coin.fromString(txAttributes.swap_fee) + + tokenSwap.expectedIn = { + amount: parseFloat(offer.amount) / DENOM_UNIT, + token: TERRA_TOKENS[offer.denom].symbol + } + tokenSwap.expectedOut = { + amount: parseFloat(ask.amount) / DENOM_UNIT, + token: TERRA_TOKENS[ask.denom].symbol + } + tokenSwap.fee = { + amount: parseFloat(fee.amount) / DENOM_UNIT, + token: TERRA_TOKENS[fee.denom].symbol + } + tokenSwap.txHash = txHash + }) + return tokenSwap } catch (err) { - logger.error(err); - let reason; - err.reason ? reason = err.reason : reason = swapResult; - return { txSuccess: false, message: reason }; + logger.error(err) + let reason + err.reason ? (reason = err.reason) : (reason = swapResult) + return { txSuccess: false, message: reason } } } } diff --git a/src/services/uniswap.js b/src/services/uniswap.js index 9298b54..076dbb7 100644 --- a/src/services/uniswap.js +++ b/src/services/uniswap.js @@ -1,75 +1,88 @@ -import { logger } from './logger'; +import { logger } from './logger' -const debug = require('debug')('router'); -const math = require('mathjs'); -const uni = require('@uniswap/sdk'); -const ethers = require('ethers'); -const proxyArtifact = require('../static/uniswap_v2_router_abi.json'); -const routeTokens = require('../static/uniswap_route_tokens.json'); +const debug = require('debug')('router') +const math = require('mathjs') +const uni = require('@uniswap/sdk') +const ethers = require('ethers') +const proxyArtifact = require('../static/uniswap_v2_router_abi.json') +const routeTokens = require('../static/uniswap_route_tokens.json') // constants -const ROUTER = process.env.UNISWAP_ROUTER; -const GAS_LIMIT = process.env.UNISWAP_GAS_LIMIT || 150688; -const TTL = process.env.UNISWAP_TTL || 300; -const UPDATE_PERIOD = process.env.UNISWAP_UPDATE_PERIOD || 300000; // stop updating pair after 5 minutes from last request +const ROUTER = process.env.UNISWAP_ROUTER +const GAS_LIMIT = process.env.UNISWAP_GAS_LIMIT || 150688 +const TTL = process.env.UNISWAP_TTL || 300 +const UPDATE_PERIOD = process.env.UNISWAP_UPDATE_PERIOD || 300000 // stop updating pair after 5 minutes from last request export default class Uniswap { constructor(network = 'mainnet') { - this.providerUrl = process.env.ETHEREUM_RPC_URL; - this.network = process.env.ETHEREUM_CHAIN; - this.provider = new ethers.providers.JsonRpcProvider(this.providerUrl); - this.router = ROUTER; - this.slippage = math.fraction(process.env.UNISWAP_ALLOWED_SLIPPAGE); - this.allowedSlippage = new uni.Percent(this.slippage.n, (this.slippage.d * 100)); - this.pairsCacheTime = process.env.UNISWAP_PAIRS_CACHE_TIME; - this.gasLimit = GAS_LIMIT; - this.expireTokenPairUpdate = UPDATE_PERIOD; - this.zeroReserveCheckInterval = process.env.UNISWAP_NO_RESERVE_CHECK_INTERVAL; - this.zeroReservePairs = {}; // No reserve pairs - this.tokenList = {}; - this.pairs = []; - this.tokenSwapList = {}; - this.cachedRoutes = {}; + this.providerUrl = process.env.ETHEREUM_RPC_URL + this.network = process.env.ETHEREUM_CHAIN + this.provider = new ethers.providers.JsonRpcProvider(this.providerUrl) + this.router = ROUTER + this.slippage = math.fraction(process.env.UNISWAP_ALLOWED_SLIPPAGE) + this.allowedSlippage = new uni.Percent( + this.slippage.n, + this.slippage.d * 100 + ) + this.pairsCacheTime = process.env.UNISWAP_PAIRS_CACHE_TIME + this.gasLimit = GAS_LIMIT + this.expireTokenPairUpdate = UPDATE_PERIOD + this.zeroReserveCheckInterval = + process.env.UNISWAP_NO_RESERVE_CHECK_INTERVAL + this.zeroReservePairs = {} // No reserve pairs + this.tokenList = {} + this.pairs = [] + this.tokenSwapList = {} + this.cachedRoutes = {} switch (network) { case 'mainnet': - this.chainID = uni.ChainId.MAINNET; - break; + this.chainID = uni.ChainId.MAINNET + break case 'kovan': - this.chainID = uni.ChainId.KOVAN; - break; + this.chainID = uni.ChainId.KOVAN + break default: - const err = `Invalid network ${network}`; - logger.error(err); - throw Error(err); + const err = `Invalid network ${network}` + logger.error(err) + throw Error(err) } } async fetch_route(tIn, tOut) { - let route; - let pair; + let route + let pair try { - pair = await uni.Fetcher.fetchPairData(tIn, tOut); - route = new uni.Route([pair], tIn, tOut); + pair = await uni.Fetcher.fetchPairData(tIn, tOut) + route = new uni.Route([pair], tIn, tOut) } catch (err) { - logger.error(err); + logger.error(err) } - return route; + return route } generate_tokens() { for (const token of routeTokens[this.network]) { - this.tokenList[token.address] = new uni.Token(this.chainID, token.address, token.decimals, token.symbol, token.name); + this.tokenList[token.address] = new uni.Token( + this.chainID, + token.address, + token.decimals, + token.symbol, + token.name + ) } } async extend_update_pairs(tokens = []) { for (const token of tokens) { if (!this.tokenList.hasOwnProperty(token)) { - this.tokenList[token] = await uni.Fetcher.fetchTokenData(this.chainID, token); + this.tokenList[token] = await uni.Fetcher.fetchTokenData( + this.chainID, + token + ) } - this.tokenSwapList[token] = Date.now() + this.expireTokenPairUpdate; + this.tokenSwapList[token] = Date.now() + this.expireTokenPairUpdate } } @@ -78,7 +91,7 @@ export default class Uniswap { if (Object.keys(this.zeroReservePairs).length > 0) { for (const pair in this.zeroReservePairs) { if (this.zeroReservePairs[pair] <= Date.now()) { - delete this.zeroReservePairs[pair]; + delete this.zeroReservePairs[pair] // delete this.tokenList[token]; } } @@ -88,129 +101,158 @@ export default class Uniswap { if (Object.keys(this.tokenSwapList).length > 0) { for (const token in this.tokenSwapList) { if (this.tokenSwapList[token] <= Date.now()) { - delete this.tokenSwapList[token]; + delete this.tokenSwapList[token] // delete this.tokenList[token]; } } - const tokens = Object.keys(this.tokenList); - let firstToken; let secondToken; let - position; - const length = tokens.length; - const pairs = []; - const pairAddressRequests = []; - const pairAddressResponses = []; + const tokens = Object.keys(this.tokenList) + let firstToken + let secondToken + let position + const length = tokens.length + const pairs = [] + const pairAddressRequests = [] + const pairAddressResponses = [] for (firstToken = 0; firstToken < length; firstToken++) { - for (secondToken = firstToken + 1; secondToken < length; secondToken++) { + for ( + secondToken = firstToken + 1; + secondToken < length; + secondToken++ + ) { try { - const pairString = `${this.tokenList[tokens[firstToken]].address}-${this.tokenList[tokens[secondToken]].address}`; + const pairString = `${this.tokenList[tokens[firstToken]].address}-${ + this.tokenList[tokens[secondToken]].address + }` if (!this.zeroReservePairs.hasOwnProperty(pairString)) { - pairs.push(pairString); - pairAddressRequests.push(uni.Fetcher.fetchPairData(this.tokenList[tokens[firstToken]], this.tokenList[tokens[secondToken]])); + pairs.push(pairString) + pairAddressRequests.push( + uni.Fetcher.fetchPairData( + this.tokenList[tokens[firstToken]], + this.tokenList[tokens[secondToken]] + ) + ) } } catch (err) { - logger.error(err); + logger.error(err) } } } await Promise.allSettled(pairAddressRequests).then((values) => { for (position = 0; position < pairAddressRequests.length; position++) { - if (values[position].status === 'fulfilled') { pairAddressResponses.push(values[position].value); } else { this.zeroReservePairs[pairs[position]] = Date.now() + this.zeroReserveCheckInterval; } + if (values[position].status === 'fulfilled') { + pairAddressResponses.push(values[position].value) + } else { + this.zeroReservePairs[pairs[position]] = + Date.now() + this.zeroReserveCheckInterval + } } - }); - this.pairs = pairAddressResponses; + }) + this.pairs = pairAddressResponses } - setTimeout(this.update_pairs.bind(this), 1000); + setTimeout(this.update_pairs.bind(this), 1000) } async priceSwapIn(tokenIn, tokenOut, tokenInAmount) { - await this.extend_update_pairs([tokenIn, tokenOut]); - const tIn = this.tokenList[tokenIn]; - const tOut = this.tokenList[tokenOut]; - const tokenAmountIn = new uni.TokenAmount(tIn, ethers.utils.parseUnits(tokenInAmount, tIn.decimals)); + await this.extend_update_pairs([tokenIn, tokenOut]) + const tIn = this.tokenList[tokenIn] + const tOut = this.tokenList[tokenOut] + const tokenAmountIn = new uni.TokenAmount( + tIn, + ethers.utils.parseUnits(tokenInAmount, tIn.decimals) + ) if (this.pairs.length === 0) { - const route = await this.fetch_route(tIn, tOut); - const trade = uni.Trade.exactIn(route, tokenAmountIn); + const route = await this.fetch_route(tIn, tOut) + const trade = uni.Trade.exactIn(route, tokenAmountIn) if (trade !== undefined) { - const expectedAmount = trade.minimumAmountOut(this.allowedSlippage); - this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade; - return { trade, expectedAmount }; + const expectedAmount = trade.minimumAmountOut(this.allowedSlippage) + this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade + return { trade, expectedAmount } } - return "Can't find route to swap, kindly update "; + return "Can't find route to swap, kindly update " + } + let trade = uni.Trade.bestTradeExactIn( + this.pairs, + tokenAmountIn, + this.tokenList[tokenOut], + { maxHops: 5 } + )[0] + if (trade === undefined) { + trade = this.cachedRoutes[tIn.symbol + tOut.Symbol] + } else { + this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade } - let trade = uni.Trade.bestTradeExactIn(this.pairs, tokenAmountIn, this.tokenList[tokenOut], { maxHops: 5 })[0]; - if (trade === undefined) { trade = this.cachedRoutes[tIn.symbol + tOut.Symbol]; } else { this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade; } - const expectedAmount = trade.minimumAmountOut(this.allowedSlippage); - return { trade, expectedAmount }; + const expectedAmount = trade.minimumAmountOut(this.allowedSlippage) + return { trade, expectedAmount } } async priceSwapOut(tokenIn, tokenOut, tokenOutAmount) { - await this.extend_update_pairs([tokenIn, tokenOut]); - const tOut = this.tokenList[tokenOut]; - const tIn = this.tokenList[tokenIn]; - const tokenAmountOut = new uni.TokenAmount(tOut, ethers.utils.parseUnits(tokenOutAmount, tOut.decimals)); + await this.extend_update_pairs([tokenIn, tokenOut]) + const tOut = this.tokenList[tokenOut] + const tIn = this.tokenList[tokenIn] + const tokenAmountOut = new uni.TokenAmount( + tOut, + ethers.utils.parseUnits(tokenOutAmount, tOut.decimals) + ) if (this.pairs.length === 0) { - const route = await this.fetch_route(tIn, tOut); - const trade = uni.Trade.exactOut(route, tokenAmountOut); + const route = await this.fetch_route(tIn, tOut) + const trade = uni.Trade.exactOut(route, tokenAmountOut) if (trade !== undefined) { - const expectedAmount = trade.maximumAmountIn(this.allowedSlippage); - this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade; - return { trade, expectedAmount }; + const expectedAmount = trade.maximumAmountIn(this.allowedSlippage) + this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade + return { trade, expectedAmount } } - return; + return } - let trade = uni.Trade.bestTradeExactOut(this.pairs, this.tokenList[tokenIn], tokenAmountOut, { maxHops: 5 })[0]; - if (trade === undefined) { trade = this.cachedRoutes[tIn.symbol + tOut.Symbol]; } else { this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade; } - const expectedAmount = trade.maximumAmountIn(this.allowedSlippage); - return { trade, expectedAmount }; + let trade = uni.Trade.bestTradeExactOut( + this.pairs, + this.tokenList[tokenIn], + tokenAmountOut, + { maxHops: 5 } + )[0] + if (trade === undefined) { + trade = this.cachedRoutes[tIn.symbol + tOut.Symbol] + } else { + this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade + } + const expectedAmount = trade.maximumAmountIn(this.allowedSlippage) + return { trade, expectedAmount } } async swapExactIn(wallet, trade, tokenAddress, gasPrice) { - const result = uni.Router.swapCallParameters( - trade, - { - ttl: TTL, - recipient: wallet.address, - allowedSlippage: this.allowedSlippage, - }, - ); - - const contract = new ethers.Contract(this.router, proxyArtifact.abi, wallet); - const tx = await contract[result.methodName]( - ...result.args, - { - gasPrice: gasPrice * 1e9, - gasLimit: GAS_LIMIT, - value: result.value, - }, - ); - - debug(`Tx Hash: ${tx.hash}`); - return tx; + const result = uni.Router.swapCallParameters(trade, { + ttl: TTL, + recipient: wallet.address, + allowedSlippage: this.allowedSlippage + }) + + const contract = new ethers.Contract(this.router, proxyArtifact.abi, wallet) + const tx = await contract[result.methodName](...result.args, { + gasPrice: gasPrice * 1e9, + gasLimit: GAS_LIMIT, + value: result.value + }) + + debug(`Tx Hash: ${tx.hash}`) + return tx } async swapExactOut(wallet, trade, tokenAddress, gasPrice) { - const result = uni.Router.swapCallParameters( - trade, - { - ttl: TTL, - recipient: wallet.address, - allowedSlippage: this.allowedSlippage, - }, - ); - - const contract = new ethers.Contract(this.router, proxyArtifact.abi, wallet); - const tx = await contract[result.methodName]( - ...result.args, - { - gasPrice: gasPrice * 1e9, - gasLimit: GAS_LIMIT, - value: result.value, - }, - ); - - debug(`Tx Hash: ${tx.hash}`); - return tx; + const result = uni.Router.swapCallParameters(trade, { + ttl: TTL, + recipient: wallet.address, + allowedSlippage: this.allowedSlippage + }) + + const contract = new ethers.Contract(this.router, proxyArtifact.abi, wallet) + const tx = await contract[result.methodName](...result.args, { + gasPrice: gasPrice * 1e9, + gasLimit: GAS_LIMIT, + value: result.value + }) + + debug(`Tx Hash: ${tx.hash}`) + return tx } } diff --git a/src/services/uniswap_v3.js b/src/services/uniswap_v3.js index 0469f7f..fecf868 100644 --- a/src/services/uniswap_v3.js +++ b/src/services/uniswap_v3.js @@ -1,156 +1,211 @@ -import { logger } from './logger'; +import { logger } from './logger' import { - encodePriceSqrt, getTickFromPrice, -} from '../static/uniswap-v3/helper_functions'; + encodePriceSqrt, + getTickFromPrice +} from '../static/uniswap-v3/helper_functions' -const debug = require('debug')('router'); -const math = require('mathjs'); -const uni = require('@uniswap/sdk'); -const ethers = require('ethers'); -const coreArtifact = require('@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json'); -const nftArtifact = require('@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'); -const routerArtifact = require('@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json'); -const poolArtifact = require('@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json'); +const debug = require('debug')('router') +const math = require('mathjs') +const uni = require('@uniswap/sdk') +const ethers = require('ethers') +const coreArtifact = require('@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json') +const nftArtifact = require('@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json') +const routerArtifact = require('@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json') +const poolArtifact = require('@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json') // const routeTokens = require('../static/uniswap_route_tokens.json') -const abiDecoder = require('abi-decoder'); +const abiDecoder = require('abi-decoder') // constants -const FeeAmount = { LOW: 500, MEDIUM: 3000, HIGH: 10000 }; -const GAS_LIMIT = process.env.UNISWAP_GAS_LIMIT || 5506880; -const TTL = process.env.UNISWAP_TTL || 300; -const UPDATE_PERIOD = process.env.UNISWAP_UPDATE_PERIOD || 300000; // stop updating pair after 5 minutes from last request -const MaxUint128 = ethers.BigNumber.from(2).pow(128).sub(1); +const FeeAmount = { LOW: 500, MEDIUM: 3000, HIGH: 10000 } +const GAS_LIMIT = process.env.UNISWAP_GAS_LIMIT || 5506880 +const TTL = process.env.UNISWAP_TTL || 300 +const UPDATE_PERIOD = process.env.UNISWAP_UPDATE_PERIOD || 300000 // stop updating pair after 5 minutes from last request +const MaxUint128 = ethers.BigNumber.from(2).pow(128).sub(1) -abiDecoder.addABI(nftArtifact.abi); -abiDecoder.addABI(routerArtifact.abi); +abiDecoder.addABI(nftArtifact.abi) +abiDecoder.addABI(routerArtifact.abi) export default class UniswapV3 { constructor(network = 'mainnet') { - this.providerUrl = process.env.ETHEREUM_RPC_URL; - this.network = process.env.ETHEREUM_CHAIN; - this.provider = new ethers.providers.JsonRpcProvider(this.providerUrl); - this.router = process.env.UNISWAP_V3_ROUTER; - this.nftManager = process.env.UNISWAP_V3_NFT_MANAGER; - this.core = process.env.UNISWAP_V3_CORE; - this.slippage = process.env.UNISWAP_ALLOWED_SLIPPAGE; - this.pairsCacheTime = process.env.UNISWAP_PAIRS_CACHE_TIME; - this.gasLimit = GAS_LIMIT; - this.expireTokenPairUpdate = UPDATE_PERIOD; - this.zeroReserveCheckInterval = process.env.UNISWAP_NO_RESERVE_CHECK_INTERVAL; - this.zeroReservePairs = {}; // No reserve pairs - this.tokenList = {}; - this.pairs = []; - this.tokenSwapList = {}; - this.cachedRoutes = {}; - this.abiDecoder = abiDecoder; + this.providerUrl = process.env.ETHEREUM_RPC_URL + this.network = process.env.ETHEREUM_CHAIN + this.provider = new ethers.providers.JsonRpcProvider(this.providerUrl) + this.router = process.env.UNISWAP_V3_ROUTER + this.nftManager = process.env.UNISWAP_V3_NFT_MANAGER + this.core = process.env.UNISWAP_V3_CORE + this.slippage = process.env.UNISWAP_ALLOWED_SLIPPAGE + this.pairsCacheTime = process.env.UNISWAP_PAIRS_CACHE_TIME + this.gasLimit = GAS_LIMIT + this.expireTokenPairUpdate = UPDATE_PERIOD + this.zeroReserveCheckInterval = + process.env.UNISWAP_NO_RESERVE_CHECK_INTERVAL + this.zeroReservePairs = {} // No reserve pairs + this.tokenList = {} + this.pairs = [] + this.tokenSwapList = {} + this.cachedRoutes = {} + this.abiDecoder = abiDecoder switch (network) { case 'mainnet': - this.chainID = uni.ChainId.MAINNET; - break; + this.chainID = uni.ChainId.MAINNET + break case 'kovan': - this.chainID = uni.ChainId.KOVAN; - break; + this.chainID = uni.ChainId.KOVAN + break default: - const err = `Invalid network ${network}`; - logger.error(err); + const err = `Invalid network ${network}` + logger.error(err) } } get_contract(contract, wallet) { - if (contract === 'core') { return new ethers.Contract(this.core, coreArtifact.abi, wallet); } - if (contract === 'router') { return new ethers.Contract(this.router, routerArtifact.abi, wallet); } - return new ethers.Contract(this.nftManager, nftArtifact.abi, wallet); + if (contract === 'core') { + return new ethers.Contract(this.core, coreArtifact.abi, wallet) + } + if (contract === 'router') { + return new ethers.Contract(this.router, routerArtifact.abi, wallet) + } + return new ethers.Contract(this.nftManager, nftArtifact.abi, wallet) } async currentPrice(wallet, tokenIn, tokenOut) { - let pool; let - poolContract; - const poolPrices = []; - const poolLiquidity = []; - const keys = ['LOW', 'MEDIUM', 'HIGH']; - const coreContract = this.get_contract('core', wallet); + let pool + let poolContract + const poolPrices = [] + const poolLiquidity = [] + const keys = ['LOW', 'MEDIUM', 'HIGH'] + const coreContract = this.get_contract('core', wallet) - const poolAddressRequests = [coreContract.getPool(tokenIn, tokenOut, FeeAmount.LOW), + const poolAddressRequests = [ + coreContract.getPool(tokenIn, tokenOut, FeeAmount.LOW), coreContract.getPool(tokenIn, tokenOut, FeeAmount.MEDIUM), - coreContract.getPool(tokenIn, tokenOut, FeeAmount.HIGH)]; + coreContract.getPool(tokenIn, tokenOut, FeeAmount.HIGH) + ] await Promise.allSettled(poolAddressRequests).then((values) => { for (pool = 0; pool < 3; pool++) { - if (values[pool].value === ethers.constants.AddressZero) { poolPrices[pool] = 0; } else { - poolContract = new ethers.Contract(values[pool].value, poolArtifact.abi, wallet); - poolPrices[pool] = poolContract.observe([1, 0]); + if (values[pool].value === ethers.constants.AddressZero) { + poolPrices[pool] = 0 + } else { + poolContract = new ethers.Contract( + values[pool].value, + poolArtifact.abi, + wallet + ) + poolPrices[pool] = poolContract.observe([1, 0]) } } - }); + }) await Promise.allSettled(poolPrices).then((values) => { for (pool = 0; pool < 3; pool++) { - poolPrices[pool] = poolLiquidity[pool] = 0; + poolPrices[pool] = poolLiquidity[pool] = 0 if (values[pool].value) { for (const tick of values[pool].value.tickCumulatives) { - poolPrices[pool] = tick.toNumber() - poolPrices[pool]; + poolPrices[pool] = tick.toNumber() - poolPrices[pool] } - poolPrices[pool] = math.pow(1.0001, poolPrices[pool]); + poolPrices[pool] = math.pow(1.0001, poolPrices[pool]) } } - }); - return Object.assign(...keys.map((k, i) => ({ [k]: poolPrices[i] }))); + }) + return Object.assign(...keys.map((k, i) => ({ [k]: poolPrices[i] }))) } - async swapExactIn(wallet, baseTokenContractInfo, quoteTokenContractInfo, baseAmount, limitPrice, tier, _gasPrice) { + async swapExactIn( + wallet, + baseTokenContractInfo, + quoteTokenContractInfo, + baseAmount, + limitPrice, + tier, + _gasPrice + ) { // sell, In => base, Out => quote - const minPercentOut = (1 - (this.slippage / 100)); - const amountOutMinimum = Math.floor(baseAmount * limitPrice * minPercentOut * quoteTokenContractInfo.decimals) / quoteTokenContractInfo.decimals; + const minPercentOut = 1 - this.slippage / 100 + const amountOutMinimum = + Math.floor( + baseAmount * + limitPrice * + minPercentOut * + quoteTokenContractInfo.decimals + ) / quoteTokenContractInfo.decimals // const priceFraction = math.fraction(limitPrice) - const contract = this.get_contract('router', wallet); - const tx = await contract.exactInputSingle({ - tokenIn: baseTokenContractInfo.address, - tokenOut: quoteTokenContractInfo.address, - fee: FeeAmount[tier], - recipient: wallet.signer.address, - deadline: Date.now() + TTL, - amountIn: ethers.utils.parseUnits(baseAmount, baseTokenContractInfo.decimals), - amountOutMinimum: ethers.utils.parseUnits(amountOutMinimum.toString(), quoteTokenContractInfo.decimals), - sqrtPriceLimitX96: 0, - }, - { - gasLimit: GAS_LIMIT, - }); + const contract = this.get_contract('router', wallet) + const tx = await contract.exactInputSingle( + { + tokenIn: baseTokenContractInfo.address, + tokenOut: quoteTokenContractInfo.address, + fee: FeeAmount[tier], + recipient: wallet.signer.address, + deadline: Date.now() + TTL, + amountIn: ethers.utils.parseUnits( + baseAmount, + baseTokenContractInfo.decimals + ), + amountOutMinimum: ethers.utils.parseUnits( + amountOutMinimum.toString(), + quoteTokenContractInfo.decimals + ), + sqrtPriceLimitX96: 0 + }, + { + gasLimit: GAS_LIMIT + } + ) - debug(`Tx Hash: ${tx.hash}`); - tx.expectedAmount = amountOutMinimum; - return tx; + debug(`Tx Hash: ${tx.hash}`) + tx.expectedAmount = amountOutMinimum + return tx } - async swapExactOut(wallet, baseTokenContractInfo, quoteTokenContractInfo, baseAmount, limitPrice, tier, _gasPrice) { + async swapExactOut( + wallet, + baseTokenContractInfo, + quoteTokenContractInfo, + baseAmount, + limitPrice, + tier, + _gasPrice + ) { // buy, In => quote, Out => base - const maxPercentIn = (1 + (this.slippage / 100)); - const amountInMaximum = Math.ceil(baseAmount * limitPrice * maxPercentIn * quoteTokenContractInfo.decimals) / quoteTokenContractInfo.decimals; + const maxPercentIn = 1 + this.slippage / 100 + const amountInMaximum = + Math.ceil( + baseAmount * limitPrice * maxPercentIn * quoteTokenContractInfo.decimals + ) / quoteTokenContractInfo.decimals // const priceFraction = math.fraction(limitPrice) - const contract = this.get_contract('router', wallet); - const tx = await contract.exactOutputSingle({ - tokenIn: quoteTokenContractInfo.address, - tokenOut: baseTokenContractInfo.address, - fee: FeeAmount[tier], - recipient: wallet.signer.address, - deadline: Date.now() + TTL, - amountOut: ethers.utils.parseUnits(baseAmount, baseTokenContractInfo.decimals), - amountInMaximum: ethers.utils.parseUnits(amountInMaximum.toString(), quoteTokenContractInfo.decimals), - sqrtPriceLimitX96: 0, - }, - { - gasLimit: GAS_LIMIT, - }); + const contract = this.get_contract('router', wallet) + const tx = await contract.exactOutputSingle( + { + tokenIn: quoteTokenContractInfo.address, + tokenOut: baseTokenContractInfo.address, + fee: FeeAmount[tier], + recipient: wallet.signer.address, + deadline: Date.now() + TTL, + amountOut: ethers.utils.parseUnits( + baseAmount, + baseTokenContractInfo.decimals + ), + amountInMaximum: ethers.utils.parseUnits( + amountInMaximum.toString(), + quoteTokenContractInfo.decimals + ), + sqrtPriceLimitX96: 0 + }, + { + gasLimit: GAS_LIMIT + } + ) - debug(`Tx Hash: ${tx.hash}`); - tx.expectedAmount = amountInMaximum; - return tx; + debug(`Tx Hash: ${tx.hash}`) + tx.expectedAmount = amountInMaximum + return tx } // LP section async getPosition(wallet, tokenId) { - const contract = this.get_contract('nft', wallet); - const position = await contract.positions(tokenId); + const contract = this.get_contract('nft', wallet) + const position = await contract.positions(tokenId) return { nonce: position[0].toString(), operator: position[1], @@ -163,96 +218,178 @@ export default class UniswapV3 { feeGrowthInside0LastX128: position[8].toString(), feeGrowthInside1LastX128: position[9].toString(), tokensOwed0: position[10].toString(), - tokensOwed1: position[11].toString(), - }; + tokensOwed1: position[11].toString() + } } getRemoveLiquidityData(wallet, contract, tokenId, liquidity) { - const decreaseLiquidityData = contract.interface.encodeFunctionData('decreaseLiquidity', [{ - tokenId, - liquidity, - amount0Min: 0, - amount1Min: 0, - deadline: Date.now() + TTL, - }]); - const collectFeesData = contract.interface.encodeFunctionData('collect', [{ - tokenId, - recipient: wallet.signer.address, - amount0Max: MaxUint128, - amount1Max: MaxUint128, - }]); - const burnData = contract.interface.encodeFunctionData('burn', [tokenId]); + const decreaseLiquidityData = contract.interface.encodeFunctionData( + 'decreaseLiquidity', + [ + { + tokenId, + liquidity, + amount0Min: 0, + amount1Min: 0, + deadline: Date.now() + TTL + } + ] + ) + const collectFeesData = contract.interface.encodeFunctionData('collect', [ + { + tokenId, + recipient: wallet.signer.address, + amount0Max: MaxUint128, + amount1Max: MaxUint128 + } + ]) + const burnData = contract.interface.encodeFunctionData('burn', [tokenId]) - return [decreaseLiquidityData, collectFeesData, burnData]; + return [decreaseLiquidityData, collectFeesData, burnData] } - getAddLiquidityData(wallet, contract, token0, token1, amount0, amount1, fee, lowerPrice, upperPrice) { - const mintData = contract.interface.encodeFunctionData('mint', [{ - token0: token0.address, - token1: token1.address, - tickLower: getTickFromPrice(lowerPrice, fee, 'UPPER'), - tickUpper: getTickFromPrice(upperPrice, fee, 'LOWER'), - amount0Desired: ethers.utils.parseUnits(amount0, token0.decimals), - amount1Desired: ethers.utils.parseUnits(amount1, token1.decimals), - // slippage isn't applied for now - amount0Min: 0, - amount1Min: 0, - recipient: wallet.signer.address, - deadline: Date.now() + TTL, - fee: FeeAmount[fee], - }]); + getAddLiquidityData( + wallet, + contract, + token0, + token1, + amount0, + amount1, + fee, + lowerPrice, + upperPrice + ) { + const mintData = contract.interface.encodeFunctionData('mint', [ + { + token0: token0.address, + token1: token1.address, + tickLower: getTickFromPrice(lowerPrice, fee, 'UPPER'), + tickUpper: getTickFromPrice(upperPrice, fee, 'LOWER'), + amount0Desired: ethers.utils.parseUnits(amount0, token0.decimals), + amount1Desired: ethers.utils.parseUnits(amount1, token1.decimals), + // slippage isn't applied for now + amount0Min: 0, + amount1Min: 0, + recipient: wallet.signer.address, + deadline: Date.now() + TTL, + fee: FeeAmount[fee] + } + ]) - return mintData; + return mintData } - async addPosition(wallet, token0, token1, amount0, amount1, fee, lowerPrice, upperPrice) { - const nftContract = this.get_contract('nft', wallet); - const coreContract = this.get_contract('core', wallet); - const pool = await coreContract.getPool(token0.address, token1.address, FeeAmount[fee]); - const midPrice = math.fraction((lowerPrice + upperPrice) / 2); // Use mid price to initialize uninitialized pool - - const initPoolData = nftContract.interface.encodeFunctionData('createAndInitializePoolIfNecessary', [ + async addPosition( + wallet, + token0, + token1, + amount0, + amount1, + fee, + lowerPrice, + upperPrice + ) { + const nftContract = this.get_contract('nft', wallet) + const coreContract = this.get_contract('core', wallet) + const pool = await coreContract.getPool( token0.address, token1.address, - FeeAmount[fee], - encodePriceSqrt(midPrice.n, midPrice.d)]); + FeeAmount[fee] + ) + const midPrice = math.fraction((lowerPrice + upperPrice) / 2) // Use mid price to initialize uninitialized pool + + const initPoolData = nftContract.interface.encodeFunctionData( + 'createAndInitializePoolIfNecessary', + [ + token0.address, + token1.address, + FeeAmount[fee], + encodePriceSqrt(midPrice.n, midPrice.d) + ] + ) - const mintData = this.getAddLiquidityData(wallet, nftContract, token0, token1, amount0, amount1, fee, lowerPrice, upperPrice); + const mintData = this.getAddLiquidityData( + wallet, + nftContract, + token0, + token1, + amount0, + amount1, + fee, + lowerPrice, + upperPrice + ) - const calls = [mintData]; + const calls = [mintData] if (pool === ethers.constants.AddressZero) { - const tx = await nftContract.multicall([initPoolData, mintData], { gasLimit: GAS_LIMIT }); - return tx; + const tx = await nftContract.multicall([initPoolData, mintData], { + gasLimit: GAS_LIMIT + }) + return tx } - const tx = await nftContract.multicall(calls, { gasLimit: GAS_LIMIT }); - return tx; + const tx = await nftContract.multicall(calls, { gasLimit: GAS_LIMIT }) + return tx } async removePosition(wallet, tokenId) { // Reduce position and burn - const positionData = await this.getPosition(wallet, tokenId); - const contract = this.get_contract('nft', wallet); - const data = this.getRemoveLiquidityData(wallet, contract, tokenId, positionData.liquidity); - return contract.multicall(data, { gasLimit: GAS_LIMIT }); + const positionData = await this.getPosition(wallet, tokenId) + const contract = this.get_contract('nft', wallet) + const data = this.getRemoveLiquidityData( + wallet, + contract, + tokenId, + positionData.liquidity + ) + return contract.multicall(data, { gasLimit: GAS_LIMIT }) } - async replacePosition(wallet, tokenId, token0, token1, amount0, amount1, fee, lowerPrice, upperPrice) { - const contract = this.get_contract('nft', wallet); - const positionData = await this.getPosition(wallet, tokenId); - const removeData = this.getRemoveLiquidityData(wallet, contract, tokenId, positionData.liquidity); - const mintData = this.getAddLiquidityData(wallet, contract, token0, token1, amount0, amount1, fee, lowerPrice, upperPrice); + async replacePosition( + wallet, + tokenId, + token0, + token1, + amount0, + amount1, + fee, + lowerPrice, + upperPrice + ) { + const contract = this.get_contract('nft', wallet) + const positionData = await this.getPosition(wallet, tokenId) + const removeData = this.getRemoveLiquidityData( + wallet, + contract, + tokenId, + positionData.liquidity + ) + const mintData = this.getAddLiquidityData( + wallet, + contract, + token0, + token1, + amount0, + amount1, + fee, + lowerPrice, + upperPrice + ) - return contract.multicall(removeData.concat(mintData), { gasLimit: GAS_LIMIT }); + return contract.multicall(removeData.concat(mintData), { + gasLimit: GAS_LIMIT + }) } async collectFees(wallet, tokenId) { - const contract = this.get_contract('nft', wallet); - return contract.collect({ - tokenId, - recipient: wallet.signer.address, - amount0Max: MaxUint128, - amount1Max: MaxUint128, - }, - { gasLimit: GAS_LIMIT }); + const contract = this.get_contract('nft', wallet) + return contract.collect( + { + tokenId, + recipient: wallet.signer.address, + amount0Max: MaxUint128, + amount1Max: MaxUint128 + }, + { gasLimit: GAS_LIMIT } + ) } } diff --git a/src/services/utils.js b/src/services/utils.js index db1ce93..bb7124c 100644 --- a/src/services/utils.js +++ b/src/services/utils.js @@ -1,9 +1,9 @@ /* Hummingbot Utils */ -const lodash = require('lodash'); -const moment = require('moment'); -const { NonceManager } = require('@ethersproject/experimental'); +const lodash = require('lodash') +const moment = require('moment') +const { NonceManager } = require('@ethersproject/experimental') export const statusMessages = { ssl_cert_required: 'SSL Certificate required', @@ -12,76 +12,81 @@ export const statusMessages = { no_pool_available: 'No Pool Available', invalid_token_symbol: 'Invalid Token Symbol', insufficient_reserves: 'Insufficient Liquidity Reserves', - page_not_found: 'Page not found. Invalid path', -}; + page_not_found: 'Page not found. Invalid path' +} -export const latency = (startTime, endTime) => parseFloat((endTime - startTime) / 1000); +export const latency = (startTime, endTime) => + parseFloat((endTime - startTime) / 1000) export const isValidParams = (params) => { - const values = Object.values(params); + const values = Object.values(params) // DO NOT use forEach, it returns callback without breaking the loop for (let i = 0; i < values.length; i++) { if (typeof values[i] === 'undefined') { - throw new Error('Invalid input params'); + throw new Error('Invalid input params') } } - return true; -}; + return true +} export const isValidData = (data, format) => { - if (typeof data !== 'undefined' && Object.keys(data).length !== 0 && lodash.isEqual(Object.keys(data).sort(), format.sort())) { - return true; + if ( + typeof data !== 'undefined' && + Object.keys(data).length !== 0 && + lodash.isEqual(Object.keys(data).sort(), format.sort()) + ) { + return true } - return false; -}; + return false +} export const getParamData = (data, format = null) => { - const dataObject = {}; + const dataObject = {} if (format !== null) { if (isValidData(data, format)) { format.forEach((key, _index) => { - dataObject[key] = data[key]; - }); + dataObject[key] = data[key] + }) } } else { Object.keys(data).forEach((key, _index) => { - dataObject[key] = data[key]; - }); + dataObject[key] = data[key] + }) } - return dataObject; -}; + return dataObject +} export const splitParamData = (param, separator = ',') => { - const dataArray = param.split(separator); - return dataArray; -}; + const dataArray = param.split(separator) + return dataArray +} export const getSymbols = (tradingPair) => { - const symbols = tradingPair.split('-'); + const symbols = tradingPair.split('-') const baseQuotePair = { base: symbols[0].toUpperCase(), - quote: symbols[1].toUpperCase(), - }; - return baseQuotePair; -}; + quote: symbols[1].toUpperCase() + } + return baseQuotePair +} export const reportConnectionError = (res, error) => { res.json({ error: error.errno, - code: error.code, - }); -}; + code: error.code + }) +} -export const strToDecimal = (str) => parseInt(str) / 100; +export const strToDecimal = (str) => parseInt(str) / 100 export const getHummingbotMemo = () => { - const prefix = 'hbot'; - const clientId = process.env.HUMMINGBOT_INSTANCE_ID; - if ((typeof clientId !== 'undefined' && clientId != null) && clientId !== '') { - return [prefix, clientId].join('-'); + const prefix = 'hbot' + const clientId = process.env.HUMMINGBOT_INSTANCE_ID + if (typeof clientId !== 'undefined' && clientId != null && clientId !== '') { + return [prefix, clientId].join('-') } - return prefix; -}; + return prefix +} export const loadConfig = () => { const config = { @@ -89,39 +94,58 @@ export const loadConfig = () => { ethereum_chain: process.env.ETHEREUM_CHAIN, exchange_proxy: process.env.EXCHANGE_PROXY, ethereum_token_list_url: process.env.ETHEREUM_TOKEN_LIST_URL, - enable_eth_gas_station: process.env.ENABLE_ETH_GAS_STATION != null ? (process.env.ENABLE_ETH_GAS_STATION.toLowerCase() === 'true') : false, + enable_eth_gas_station: + process.env.ENABLE_ETH_GAS_STATION != null + ? process.env.ENABLE_ETH_GAS_STATION.toLowerCase() === 'true' + : false, eth_gas_station_gas_level: process.env.ETH_GAS_STATION_GAS_LEVEL, - eth_gas_station_refresh_time: process.env.ETH_GAS_STATION_REFRESH_TIME != null ? parseFloat(process.env.ETH_GAS_STATION_REFRESH_TIME) : null, - manual_gas_price: process.env.MANUAL_GAS_PRICE != null ? parseFloat(process.env.MANUAL_GAS_PRICE) : null, + eth_gas_station_refresh_time: + process.env.ETH_GAS_STATION_REFRESH_TIME != null + ? parseFloat(process.env.ETH_GAS_STATION_REFRESH_TIME) + : null, + manual_gas_price: + process.env.MANUAL_GAS_PRICE != null + ? parseFloat(process.env.MANUAL_GAS_PRICE) + : null, react_app_subgraph_url: process.env.REACT_APP_SUBGRAPH_URL, - balancer_max_swaps: process.env.BALANCER_MAX_SWAPS != null ? parseInt(process.env.BALANCER_MAX_SWAPS) : null, + balancer_max_swaps: + process.env.BALANCER_MAX_SWAPS != null + ? parseInt(process.env.BALANCER_MAX_SWAPS) + : null, uniswap_router: process.env.UNISWAP_ROUTER, terra_lcd_url: process.env.TERRA_LCD_URL, - terra_chain: process.env.TERRA_CHAIN, - }; - return config; -}; + terra_chain: process.env.TERRA_CHAIN + } + return config +} export const getLocalDate = () => { - const gmtOffset = process.env.GMT_OFFSET; - let newDate = moment().format('YYYY-MM-DD hh:mm:ss').trim(); - if (typeof gmtOffset !== 'undefined' && gmtOffset !== null && gmtOffset !== '') { - newDate = moment().utcOffset(gmtOffset, false).format('YYYY-MM-DD hh:mm:ss').trim(); + const gmtOffset = process.env.GMT_OFFSET + let newDate = moment().format('YYYY-MM-DD hh:mm:ss').trim() + if ( + typeof gmtOffset !== 'undefined' && + gmtOffset !== null && + gmtOffset !== '' + ) { + newDate = moment() + .utcOffset(gmtOffset, false) + .format('YYYY-MM-DD hh:mm:ss') + .trim() } - return newDate; -}; + return newDate +} -export const nonceManagerCache = {}; +export const nonceManagerCache = {} export const getNonceManager = async (signer) => { - let key = await signer.getAddress(); + let key = await signer.getAddress() if (signer.provider) { - key += (await signer.provider.getNetwork()).chainId; + key += (await signer.provider.getNetwork()).chainId } - let nonceManager = nonceManagerCache[key]; + let nonceManager = nonceManagerCache[key] if (typeof nonceManager === 'undefined') { - nonceManager = new NonceManager(signer); - nonceManagerCache[key] = nonceManager; + nonceManager = new NonceManager(signer) + nonceManagerCache[key] = nonceManager } - return nonceManager; -}; + return nonceManager +} diff --git a/src/static/abi.js b/src/static/abi.js index 8762479..ec06099 100644 --- a/src/static/abi.js +++ b/src/static/abi.js @@ -2,233 +2,385 @@ const ERC20Abi = [ { - "constant": true, - "inputs": [], - "name": "name", - "outputs": [ - { - "name": "", - "type": "string" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_spender", - "type": "address" - }, - { - "name": "_value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_from", - "type": "address" - }, - { - "name": "_to", - "type": "address" - }, - { - "name": "_value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "decimals", - "outputs": [ - { - "name": "", - "type": "uint8" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_owner", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "name": "balance", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "symbol", - "outputs": [ - { - "name": "", - "type": "string" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { - "name": "_to", - "type": "address" - }, - { - "name": "_value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "name": "", - "type": "bool" - } - ], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [ - { - "name": "_owner", - "type": "address" - }, - { - "name": "_spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "name": "", - "type": "uint256" - } - ], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "payable": true, - "stateMutability": "payable", - "type": "fallback" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "name": "from", - "type": "address" - }, - { - "indexed": true, - "name": "to", - "type": "address" - }, - { - "indexed": false, - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" + constant: true, + inputs: [], + name: 'name', + outputs: [ + { + name: '', + type: 'string' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: false, + inputs: [ + { + name: '_spender', + type: 'address' + }, + { + name: '_value', + type: 'uint256' + } + ], + name: 'approve', + outputs: [ + { + name: '', + type: 'bool' + } + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: true, + inputs: [], + name: 'totalSupply', + outputs: [ + { + name: '', + type: 'uint256' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: false, + inputs: [ + { + name: '_from', + type: 'address' + }, + { + name: '_to', + type: 'address' + }, + { + name: '_value', + type: 'uint256' + } + ], + name: 'transferFrom', + outputs: [ + { + name: '', + type: 'bool' + } + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: true, + inputs: [], + name: 'decimals', + outputs: [ + { + name: '', + type: 'uint8' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [ + { + name: '_owner', + type: 'address' + } + ], + name: 'balanceOf', + outputs: [ + { + name: 'balance', + type: 'uint256' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [], + name: 'symbol', + outputs: [ + { + name: '', + type: 'string' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: false, + inputs: [ + { + name: '_to', + type: 'address' + }, + { + name: '_value', + type: 'uint256' + } + ], + name: 'transfer', + outputs: [ + { + name: '', + type: 'bool' + } + ], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: true, + inputs: [ + { + name: '_owner', + type: 'address' + }, + { + name: '_spender', + type: 'address' + } + ], + name: 'allowance', + outputs: [ + { + name: '', + type: 'uint256' + } + ], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + payable: true, + stateMutability: 'payable', + type: 'fallback' + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + name: 'owner', + type: 'address' + }, + { + indexed: true, + name: 'spender', + type: 'address' + }, + { + indexed: false, + name: 'value', + type: 'uint256' + } + ], + name: 'Approval', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + name: 'from', + type: 'address' + }, + { + indexed: true, + name: 'to', + type: 'address' + }, + { + indexed: false, + name: 'value', + type: 'uint256' + } + ], + name: 'Transfer', + type: 'event' } ] -const KovanWETHAbi = [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Withdrawal","type":"event"}] +const KovanWETHAbi = [ + { + constant: true, + inputs: [], + name: 'name', + outputs: [{ name: '', type: 'string' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: false, + inputs: [ + { name: 'guy', type: 'address' }, + { name: 'wad', type: 'uint256' } + ], + name: 'approve', + outputs: [{ name: '', type: 'bool' }], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: true, + inputs: [], + name: 'totalSupply', + outputs: [{ name: '', type: 'uint256' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: false, + inputs: [ + { name: 'src', type: 'address' }, + { name: 'dst', type: 'address' }, + { name: 'wad', type: 'uint256' } + ], + name: 'transferFrom', + outputs: [{ name: '', type: 'bool' }], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: false, + inputs: [{ name: 'wad', type: 'uint256' }], + name: 'withdraw', + outputs: [], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: true, + inputs: [], + name: 'decimals', + outputs: [{ name: '', type: 'uint8' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [{ name: '', type: 'address' }], + name: 'balanceOf', + outputs: [{ name: '', type: 'uint256' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: true, + inputs: [], + name: 'symbol', + outputs: [{ name: '', type: 'string' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { + constant: false, + inputs: [ + { name: 'dst', type: 'address' }, + { name: 'wad', type: 'uint256' } + ], + name: 'transfer', + outputs: [{ name: '', type: 'bool' }], + payable: false, + stateMutability: 'nonpayable', + type: 'function' + }, + { + constant: false, + inputs: [], + name: 'deposit', + outputs: [], + payable: true, + stateMutability: 'payable', + type: 'function' + }, + { + constant: true, + inputs: [ + { name: '', type: 'address' }, + { name: '', type: 'address' } + ], + name: 'allowance', + outputs: [{ name: '', type: 'uint256' }], + payable: false, + stateMutability: 'view', + type: 'function' + }, + { payable: true, stateMutability: 'payable', type: 'fallback' }, + { + anonymous: false, + inputs: [ + { indexed: true, name: 'src', type: 'address' }, + { indexed: true, name: 'guy', type: 'address' }, + { indexed: false, name: 'wad', type: 'uint256' } + ], + name: 'Approval', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: 'src', type: 'address' }, + { indexed: true, name: 'dst', type: 'address' }, + { indexed: false, name: 'wad', type: 'uint256' } + ], + name: 'Transfer', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: 'dst', type: 'address' }, + { indexed: false, name: 'wad', type: 'uint256' } + ], + name: 'Deposit', + type: 'event' + }, + { + anonymous: false, + inputs: [ + { indexed: true, name: 'src', type: 'address' }, + { indexed: false, name: 'wad', type: 'uint256' } + ], + name: 'Withdrawal', + type: 'event' + } +] const KovanFaucetAddress = '0xb48Cc42C45d262534e46d5965a9Ac496F1B7a830' module.exports = { ERC20Abi, KovanWETHAbi, - KovanFaucetAddress, -}; + KovanFaucetAddress +} diff --git a/src/static/uniswap-v3/helper_functions.js b/src/static/uniswap-v3/helper_functions.js index c6e90fd..6015333 100644 --- a/src/static/uniswap-v3/helper_functions.js +++ b/src/static/uniswap-v3/helper_functions.js @@ -1,26 +1,24 @@ -import bn from 'bignumber.js'; -import JSBI from 'jsbi'; -import { - BigNumber, mulShift, Q32, ZERO, ONE, MaxUint256, -} from 'ethers'; +import bn from 'bignumber.js' +import JSBI from 'jsbi' +import { BigNumber, mulShift, Q32, ZERO, ONE, MaxUint256 } from 'ethers' -const math = require('mathjs'); +const math = require('mathjs') -const TICK_SPACINGS = { LOW: 10, MEDIUM: 60, HIGH: 2000 }; +const TICK_SPACINGS = { LOW: 10, MEDIUM: 60, HIGH: 2000 } -bn.config({ EXPONENTIAL_AT: 999999, DECIMAL_PLACES: 40 }); +bn.config({ EXPONENTIAL_AT: 999999, DECIMAL_PLACES: 40 }) export function expandTo18Decimals(n) { - return BigNumber.from(n).mul(BigNumber.from(10).pow(18)); + return BigNumber.from(n).mul(BigNumber.from(10).pow(18)) } export function toHex(bigintIsh) { - const bigInt = JSBI.BigInt(bigintIsh); - let hex = bigInt.toString(16); + const bigInt = JSBI.BigInt(bigintIsh) + let hex = bigInt.toString(16) if (hex.length % 2 !== 0) { - hex = `0${hex}`; + hex = `0${hex}` } - return `0x${hex}`; + return `0x${hex}` } // returns the sqrt price as a 64x96 @@ -31,8 +29,8 @@ export function encodePriceSqrt(reserve1, reserve0) { .sqrt() .multipliedBy(new bn(2).pow(96)) .integerValue(3) - .toString(), - ); + .toString() + ) } export function getLiquidity(amount0, amount1) { @@ -40,8 +38,8 @@ export function getLiquidity(amount0, amount1) { new bn(amount0.toString()) .multipliedBy(amount1.toString()) .sqrt() - .toString(), - ); + .toString() + ) /* let tokenPrice0, tokenPrice1, tokenFraction; tokenFraction = math.fraction(amount1/amount0) tokenPrice0 = encodePriceSqrt(tokenFraction.n, tokenFraction.d) @@ -49,116 +47,160 @@ export function getLiquidity(amount0, amount1) { return tokenPrice0.mul(tokenPrice1) */ } -const TWO = JSBI.BigInt(2); +const TWO = JSBI.BigInt(2) const POWERS_OF_2 = [128, 64, 32, 16, 8, 4, 2, 1].map((pow) => [ pow, - JSBI.exponentiate(TWO, JSBI.BigInt(pow)), -]); + JSBI.exponentiate(TWO, JSBI.BigInt(pow)) +]) export function mostSignificantBit(x) { - let y = x; - let msb = 0; + let y = x + let msb = 0 for (const [power, min] of POWERS_OF_2) { if (JSBI.greaterThanOrEqual(y, min)) { - y = JSBI.signedRightShift(y, JSBI.BigInt(power)); - msb += power; + y = JSBI.signedRightShift(y, JSBI.BigInt(power)) + msb += power } } - return msb; + return msb } export function getSqrtRatioAtTick(tick) { - const absTick = tick < 0 ? tick * -1 : tick; - - let ratio = (absTick & 0x1) !== 0 - ? JSBI.BigInt('0xfffcb933bd6fad37aa2d162d1a594001') - : JSBI.BigInt('0x100000000000000000000000000000000'); - if ((absTick & 0x2) !== 0) ratio = mulShift(ratio, '0xfff97272373d413259a46990580e213a'); - if ((absTick & 0x4) !== 0) ratio = mulShift(ratio, '0xfff2e50f5f656932ef12357cf3c7fdcc'); - if ((absTick & 0x8) !== 0) ratio = mulShift(ratio, '0xffe5caca7e10e4e61c3624eaa0941cd0'); - if ((absTick & 0x10) !== 0) ratio = mulShift(ratio, '0xffcb9843d60f6159c9db58835c926644'); - if ((absTick & 0x20) !== 0) ratio = mulShift(ratio, '0xff973b41fa98c081472e6896dfb254c0'); - if ((absTick & 0x40) !== 0) ratio = mulShift(ratio, '0xff2ea16466c96a3843ec78b326b52861'); - if ((absTick & 0x80) !== 0) ratio = mulShift(ratio, '0xfe5dee046a99a2a811c461f1969c3053'); - if ((absTick & 0x100) !== 0) ratio = mulShift(ratio, '0xfcbe86c7900a88aedcffc83b479aa3a4'); - if ((absTick & 0x200) !== 0) ratio = mulShift(ratio, '0xf987a7253ac413176f2b074cf7815e54'); - if ((absTick & 0x400) !== 0) ratio = mulShift(ratio, '0xf3392b0822b70005940c7a398e4b70f3'); - if ((absTick & 0x800) !== 0) ratio = mulShift(ratio, '0xe7159475a2c29b7443b29c7fa6e889d9'); - if ((absTick & 0x1000) !== 0) ratio = mulShift(ratio, '0xd097f3bdfd2022b8845ad8f792aa5825'); - if ((absTick & 0x2000) !== 0) ratio = mulShift(ratio, '0xa9f746462d870fdf8a65dc1f90e061e5'); - if ((absTick & 0x4000) !== 0) ratio = mulShift(ratio, '0x70d869a156d2a1b890bb3df62baf32f7'); - if ((absTick & 0x8000) !== 0) ratio = mulShift(ratio, '0x31be135f97d08fd981231505542fcfa6'); - if ((absTick & 0x10000) !== 0) ratio = mulShift(ratio, '0x9aa508b5b7a84e1c677de54f3e99bc9'); - if ((absTick & 0x20000) !== 0) ratio = mulShift(ratio, '0x5d6af8dedb81196699c329225ee604'); - if ((absTick & 0x40000) !== 0) ratio = mulShift(ratio, '0x2216e584f5fa1ea926041bedfe98'); - if ((absTick & 0x80000) !== 0) ratio = mulShift(ratio, '0x48a170391f7dc42444e8fa2'); - - if (tick > 0) ratio = JSBI.divide(MaxUint256, ratio); + const absTick = tick < 0 ? tick * -1 : tick + + let ratio = + (absTick & 0x1) !== 0 + ? JSBI.BigInt('0xfffcb933bd6fad37aa2d162d1a594001') + : JSBI.BigInt('0x100000000000000000000000000000000') + if ((absTick & 0x2) !== 0) + ratio = mulShift(ratio, '0xfff97272373d413259a46990580e213a') + if ((absTick & 0x4) !== 0) + ratio = mulShift(ratio, '0xfff2e50f5f656932ef12357cf3c7fdcc') + if ((absTick & 0x8) !== 0) + ratio = mulShift(ratio, '0xffe5caca7e10e4e61c3624eaa0941cd0') + if ((absTick & 0x10) !== 0) + ratio = mulShift(ratio, '0xffcb9843d60f6159c9db58835c926644') + if ((absTick & 0x20) !== 0) + ratio = mulShift(ratio, '0xff973b41fa98c081472e6896dfb254c0') + if ((absTick & 0x40) !== 0) + ratio = mulShift(ratio, '0xff2ea16466c96a3843ec78b326b52861') + if ((absTick & 0x80) !== 0) + ratio = mulShift(ratio, '0xfe5dee046a99a2a811c461f1969c3053') + if ((absTick & 0x100) !== 0) + ratio = mulShift(ratio, '0xfcbe86c7900a88aedcffc83b479aa3a4') + if ((absTick & 0x200) !== 0) + ratio = mulShift(ratio, '0xf987a7253ac413176f2b074cf7815e54') + if ((absTick & 0x400) !== 0) + ratio = mulShift(ratio, '0xf3392b0822b70005940c7a398e4b70f3') + if ((absTick & 0x800) !== 0) + ratio = mulShift(ratio, '0xe7159475a2c29b7443b29c7fa6e889d9') + if ((absTick & 0x1000) !== 0) + ratio = mulShift(ratio, '0xd097f3bdfd2022b8845ad8f792aa5825') + if ((absTick & 0x2000) !== 0) + ratio = mulShift(ratio, '0xa9f746462d870fdf8a65dc1f90e061e5') + if ((absTick & 0x4000) !== 0) + ratio = mulShift(ratio, '0x70d869a156d2a1b890bb3df62baf32f7') + if ((absTick & 0x8000) !== 0) + ratio = mulShift(ratio, '0x31be135f97d08fd981231505542fcfa6') + if ((absTick & 0x10000) !== 0) + ratio = mulShift(ratio, '0x9aa508b5b7a84e1c677de54f3e99bc9') + if ((absTick & 0x20000) !== 0) + ratio = mulShift(ratio, '0x5d6af8dedb81196699c329225ee604') + if ((absTick & 0x40000) !== 0) + ratio = mulShift(ratio, '0x2216e584f5fa1ea926041bedfe98') + if ((absTick & 0x80000) !== 0) + ratio = mulShift(ratio, '0x48a170391f7dc42444e8fa2') + + if (tick > 0) ratio = JSBI.divide(MaxUint256, ratio) // back to Q96 return JSBI.greaterThan(JSBI.remainder(ratio, Q32), ZERO) ? JSBI.add(JSBI.divide(ratio, Q32), ONE) - : JSBI.divide(ratio, Q32); + : JSBI.divide(ratio, Q32) } export function getTickAtSqrtRatio(sqrtRatioX96) { - const sqrtRatioX128 = JSBI.leftShift(sqrtRatioX96, JSBI.BigInt(32)); + const sqrtRatioX128 = JSBI.leftShift(sqrtRatioX96, JSBI.BigInt(32)) - const msb = mostSignificantBit(sqrtRatioX128); + const msb = mostSignificantBit(sqrtRatioX128) - let r; + let r if (JSBI.greaterThanOrEqual(JSBI.BigInt(msb), JSBI.BigInt(128))) { - r = JSBI.signedRightShift(sqrtRatioX128, JSBI.BigInt(msb - 127)); + r = JSBI.signedRightShift(sqrtRatioX128, JSBI.BigInt(msb - 127)) } else { - r = JSBI.leftShift(sqrtRatioX128, JSBI.BigInt(127 - msb)); + r = JSBI.leftShift(sqrtRatioX128, JSBI.BigInt(127 - msb)) } - let log_2 = JSBI.leftShift(JSBI.subtract(JSBI.BigInt(msb), JSBI.BigInt(128)), JSBI.BigInt(64)); + let log_2 = JSBI.leftShift( + JSBI.subtract(JSBI.BigInt(msb), JSBI.BigInt(128)), + JSBI.BigInt(64) + ) for (let i = 0; i < 14; i++) { - r = JSBI.signedRightShift(JSBI.multiply(r, r), JSBI.BigInt(127)); - const f = JSBI.signedRightShift(r, JSBI.BigInt(128)); - log_2 = JSBI.bitwiseOr(log_2, JSBI.leftShift(f, JSBI.BigInt(63 - i))); - r = JSBI.signedRightShift(r, f); + r = JSBI.signedRightShift(JSBI.multiply(r, r), JSBI.BigInt(127)) + const f = JSBI.signedRightShift(r, JSBI.BigInt(128)) + log_2 = JSBI.bitwiseOr(log_2, JSBI.leftShift(f, JSBI.BigInt(63 - i))) + r = JSBI.signedRightShift(r, f) } - const log_sqrt10001 = JSBI.multiply(log_2, JSBI.BigInt('255738958999603826347141')); + const log_sqrt10001 = JSBI.multiply( + log_2, + JSBI.BigInt('255738958999603826347141') + ) const tickLow = JSBI.toNumber( JSBI.signedRightShift( - JSBI.subtract(log_sqrt10001, JSBI.BigInt('3402992956809132418596140100660247210')), - JSBI.BigInt(128), - ), - ); + JSBI.subtract( + log_sqrt10001, + JSBI.BigInt('3402992956809132418596140100660247210') + ), + JSBI.BigInt(128) + ) + ) const tickHigh = JSBI.toNumber( JSBI.signedRightShift( - JSBI.add(log_sqrt10001, JSBI.BigInt('291339464771989622907027621153398088495')), - JSBI.BigInt(128), - ), - ); + JSBI.add( + log_sqrt10001, + JSBI.BigInt('291339464771989622907027621153398088495') + ), + JSBI.BigInt(128) + ) + ) if (tickLow === tickHigh) { - return tickLow; + return tickLow } return JSBI.lessThanOrEqual(getSqrtRatioAtTick(tickHigh), sqrtRatioX96) ? tickHigh - : tickLow; + : tickLow } -export function getMinTick(tier) { return Math.ceil(-887272 / TICK_SPACINGS[tier]) * TICK_SPACINGS[tier]; } +export function getMinTick(tier) { + return Math.ceil(-887272 / TICK_SPACINGS[tier]) * TICK_SPACINGS[tier] +} -export function getMaxTick(tier) { return Math.floor(887272 / TICK_SPACINGS[tier]) * TICK_SPACINGS[tier]; } +export function getMaxTick(tier) { + return Math.floor(887272 / TICK_SPACINGS[tier]) * TICK_SPACINGS[tier] +} export function getTickFromPrice(price, tier, side) { - let tick = 0; + let tick = 0 if (side === 'UPPER') { - tick = math.ceil(math.log(price, 1.0001) / TICK_SPACINGS[tier]) * TICK_SPACINGS[tier]; + tick = + math.ceil(math.log(price, 1.0001) / TICK_SPACINGS[tier]) * + TICK_SPACINGS[tier] } else { - tick = math.floor(math.log(price, 1.0001) / TICK_SPACINGS[tier]) * TICK_SPACINGS[tier]; + tick = + math.floor(math.log(price, 1.0001) / TICK_SPACINGS[tier]) * + TICK_SPACINGS[tier] } - if (tick >= getMaxTick(tier)) { return getMaxTick(tier); } - if (tick <= getMinTick(tier)) { return getMinTick(tier); } - return tick; + if (tick >= getMaxTick(tier)) { + return getMaxTick(tier) + } + if (tick <= getMinTick(tier)) { + return getMinTick(tier) + } + return tick } diff --git a/src/static/uniswap_route_tokens.json b/src/static/uniswap_route_tokens.json index 08c66bf..8a2d5e2 100644 --- a/src/static/uniswap_route_tokens.json +++ b/src/static/uniswap_route_tokens.json @@ -1,15 +1,72 @@ -{"mainnet": [ - {"address":"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2","name":"WrappedEther","symbol":"WETH","decimals":18}, - {"address":"0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599","name":"WrappedBTC","symbol":"WBTC","decimals":8}, - {"address":"0x6B175474E89094C44Da98b954EedeAC495271d0F","name":"DaiStablecoin","symbol":"DAI","decimals":18}, - {"address":"0xdAC17F958D2ee523a2206206994597C13D831ec7","name":"TetherUSD","symbol":"USDT","decimals":6}, - {"address":"0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48","name":"USDCoin","symbol":"USDC","decimals":6}, - {"address":"0xba100000625a3754423978a60c9317c58a424e3D","name":"Balancer","symbol":"BAL","decimals":18}, - {"address":"0xBBbbCA6A901c926F240b89EacB641d8Aec7AEafD","name":"Loopring","symbol":"LRC","decimals":18} -], -"kovan":[ - {"address":"0xd0A1E359811322d97991E03f863a0C30C2cF029C","name":"WrappedEther","symbol":"WETH","decimals":18}, - {"address":"0xe0C9275E44Ea80eF17579d33c55136b7DA269aEb","name":"WrappedBTC","symbol":"WBTC","decimals":8}, - {"address":"0x1528F3FCc26d13F7079325Fb78D9442607781c8C","name":"DaiStablecoin","symbol":"DAI","decimals":18}, - {"address":"0x2F375e94FC336Cdec2Dc0cCB5277FE59CBf1cAe5","name":"USDCoin","symbol":"USDC","decimals":6} -]} +{ + "mainnet": [ + { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "name": "WrappedEther", + "symbol": "WETH", + "decimals": 18 + }, + { + "address": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", + "name": "WrappedBTC", + "symbol": "WBTC", + "decimals": 8 + }, + { + "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", + "name": "DaiStablecoin", + "symbol": "DAI", + "decimals": 18 + }, + { + "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", + "name": "TetherUSD", + "symbol": "USDT", + "decimals": 6 + }, + { + "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", + "name": "USDCoin", + "symbol": "USDC", + "decimals": 6 + }, + { + "address": "0xba100000625a3754423978a60c9317c58a424e3D", + "name": "Balancer", + "symbol": "BAL", + "decimals": 18 + }, + { + "address": "0xBBbbCA6A901c926F240b89EacB641d8Aec7AEafD", + "name": "Loopring", + "symbol": "LRC", + "decimals": 18 + } + ], + "kovan": [ + { + "address": "0xd0A1E359811322d97991E03f863a0C30C2cF029C", + "name": "WrappedEther", + "symbol": "WETH", + "decimals": 18 + }, + { + "address": "0xe0C9275E44Ea80eF17579d33c55136b7DA269aEb", + "name": "WrappedBTC", + "symbol": "WBTC", + "decimals": 8 + }, + { + "address": "0x1528F3FCc26d13F7079325Fb78D9442607781c8C", + "name": "DaiStablecoin", + "symbol": "DAI", + "decimals": 18 + }, + { + "address": "0x2F375e94FC336Cdec2Dc0cCB5277FE59CBf1cAe5", + "name": "USDCoin", + "symbol": "USDC", + "decimals": 6 + } + ] +} diff --git a/yarn.lock b/yarn.lock index 7e28c89..5435848 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2368,6 +2368,11 @@ eslint-config-airbnb-base@^14.2.1: object.assign "^4.1.2" object.entries "^1.1.2" +eslint-config-prettier@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" + integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew== + eslint-config-standard@^14.1.1: version "14.1.1" resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea" @@ -2430,6 +2435,13 @@ eslint-plugin-node@^11.1.0: resolve "^1.10.1" semver "^6.1.0" +eslint-plugin-prettier@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz#cdbad3bf1dbd2b177e9825737fe63b476a08f0c7" + integrity sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw== + dependencies: + prettier-linter-helpers "^1.0.0" + eslint-plugin-promise@^4.2.1: version "4.3.1" resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz#61485df2a359e03149fdafc0a68b0e030ad2ac45" @@ -2669,6 +2681,11 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -4044,6 +4061,18 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.0.tgz#b6a5bf1284026ae640f17f7ff5658a7567fc0d18" + integrity sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w== + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" From ecbbd6dac1ae5f28544472c7137f0135febf2f6c Mon Sep 17 00:00:00 2001 From: james-hummingbot Date: Fri, 4 Jun 2021 10:18:04 +0200 Subject: [PATCH 5/7] Use eslint:recommended and clean up rules --- .eslintrc.js | 33 +- .prettierrc | 2 +- README.md | 19 +- package.json | 9 +- src/app.js | 78 ++--- src/index.js | 80 ++--- src/routes/balancer.route.js | 251 +++++++------- src/routes/celo.route.js | 220 ++++++------ src/routes/eth.route.js | 314 ++++++++--------- src/routes/index.route.js | 12 +- src/routes/perpetual_finance.route.js | 388 +++++++++++----------- src/routes/terra.route.js | 178 +++++----- src/routes/uniswap.route.js | 248 +++++++------- src/routes/uniswap_v3.route.js | 380 ++++++++++----------- src/services/access.js | 28 +- src/services/balancer.js | 183 +++++----- src/services/eth.js | 146 ++++---- src/services/fees.js | 56 ++-- src/services/logger.js | 34 +- src/services/perpetual_finance.js | 301 ++++++++--------- src/services/terra.js | 328 +++++++++--------- src/services/uniswap.js | 222 +++++++------ src/services/uniswap_v3.js | 213 ++++++------ src/services/utils.js | 100 +++--- src/static/abi.js | 8 +- src/static/uniswap-v3/helper_functions.js | 132 ++++---- yarn.lock | 65 ++-- 27 files changed, 2030 insertions(+), 1998 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 7d65f3a..f8b2ed8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,32 +1,17 @@ module.exports = { - extends: ['airbnb-base', 'eslint:recommended', 'prettier'], + extends: ['eslint:recommended', 'prettier'], + parser: 'babel-eslint', plugins: ['prettier'], env: { - node: true + node: true, + es6: true }, rules: { - camelcase: 'off', - 'consistent-return': 'off', - 'class-methods-use-this': 'off', - 'guard-for-in': 'off', - 'import/prefer-default-export': 'off', - 'max-len': 'off', - 'new-cap': 'off', - 'no-await-in-loop': 'off', - 'no-bitwise': 'off', - 'no-case-declarations': 'off', - 'no-console': 'off', - 'no-mixed-operators': 'off', - 'no-multi-assign': 'off', - 'no-plusplus': 'off', - 'no-prototype-builtins': 'off', - 'no-restricted-syntax': 'off', - 'no-return-assign': 'off', - 'no-unused-expressions': 'off', - 'no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + 'comma-dangle': ['error', 'never'], + 'no-multi-spaces': 'off', 'no-underscore-dangle': 'off', - 'prefer-destructuring': 'off', + 'no-unused-vars': ['error', { argsIgnorePattern: '^_' }], 'prettier/prettier': 'error', - radix: 'off' + semi: [2, 'always'] } -} +}; diff --git a/.prettierrc b/.prettierrc index 0d1aa74..0acea4c 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,6 +1,6 @@ { "trailingComma": "none", - "semi": false, + "semi": true, "singleQuote": true, "tabWidth": 2 } diff --git a/README.md b/README.md index 01aa595..d5efbf7 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,6 @@ Hummingbot Gateway is an open-source project that integrates cryptocurrency trad We created hummingbot to promote **decentralized market-making**: enabling members of the community to contribute to the liquidity and trading efficiency in cryptocurrency markets. - - ## Getting Started ### Learn more about Hummingbot @@ -46,3 +44,20 @@ Hummingbot Gateway was created and is maintained by CoinAlpha, Inc. We are [a gl ## Legal - **License**: Hummingbot is licensed under [Apache 2.0](./LICENSE). + +## Development + +This repo uses `eslint` and `prettier`. When you run `git commit` it will trigger the `pre-commit` hook. +This will run `eslint` on the `src` and `test` directories. + +You can lint before committing with: + +```bash +yarn run lint +``` + +You can run the prettifier before committing with: + +```bash +yarn run prettier +``` diff --git a/package.json b/package.json index 02f1555..55933c6 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "dev": "nodemon --exec babel-node src/index.js", "debug": "DEBUG=*router nodemon --exec babel-node src/index.js", "lint": "node_modules/.bin/eslint src --format table", + "prettier": "node_modules/.bin/prettier . --write", "test": "echo \"Error: no test specified\" && exit 1" }, "dependencies": { @@ -47,14 +48,14 @@ "@babel/core": "^7.14.0", "@babel/node": "^7.10.5", "@babel/preset-env": "^7.14.1", + "babel-eslint": "^10.1.0", "eslint": "^7.25.0", - "eslint-config-airbnb-base": "^14.2.1", "eslint-config-prettier": "^8.3.0", - "eslint-config-standard": "^14.1.1", - "eslint-plugin-import": "^2.23.3", + "eslint-config-standard": "^16.0.3", + "eslint-plugin-import": "^2.23.4", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^3.4.0", - "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-promise": "^5.1.0", "eslint-plugin-standard": "^4.0.1", "nodemon": "^2.0.4", "prettier": "^2.3.0" diff --git a/src/app.js b/src/app.js index 811c3f8..5225a31 100644 --- a/src/app.js +++ b/src/app.js @@ -1,69 +1,69 @@ -import dotenv from 'dotenv' -import bodyParser from 'body-parser' -import express from 'express' -import helmet from 'helmet' -import { IpFilter } from 'express-ipfilter' -import { statusMessages } from './services/utils' -import { validateAccess } from './services/access' -import { logger } from './services/logger' +import dotenv from 'dotenv'; +import bodyParser from 'body-parser'; +import express from 'express'; +import helmet from 'helmet'; +import { IpFilter } from 'express-ipfilter'; +import { statusMessages } from './services/utils'; +import { validateAccess } from './services/access'; +import { logger } from './services/logger'; // Routes -import apiRoutes from './routes/index.route' -import balancerRoutes from './routes/balancer.route' -import ethRoutes from './routes/eth.route' -import terraRoutes from './routes/terra.route' -import uniswapRoutes from './routes/uniswap.route' -import uniswapV3Routes from './routes/uniswap_v3.route' -import perpFiRoutes from './routes/perpetual_finance.route' +import apiRoutes from './routes/index.route'; +import balancerRoutes from './routes/balancer.route'; +import ethRoutes from './routes/eth.route'; +import terraRoutes from './routes/terra.route'; +import uniswapRoutes from './routes/uniswap.route'; +import uniswapV3Routes from './routes/uniswap_v3.route'; +import perpFiRoutes from './routes/perpetual_finance.route'; // terminate if environment not found -const result = dotenv.config() +const result = dotenv.config(); if (result.error) { - logger.error(result.error) - process.exit(1) + logger.error(result.error); + process.exit(1); } // create app -const app = express() +const app = express(); // middleware // #security: remove response headers from middleware // https://www.npmjs.com/package/helmet -app.use(helmet()) +app.use(helmet()); -const ipWhitelist = process.env.IP_WHITELIST +const ipWhitelist = process.env.IP_WHITELIST; if (ipWhitelist) { - app.use(IpFilter(JSON.parse(ipWhitelist), { mode: 'allow' })) + app.use(IpFilter(JSON.parse(ipWhitelist), { mode: 'allow' })); } -app.use(bodyParser.json()) -app.use(bodyParser.urlencoded({ extended: true })) +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); -app.use(validateAccess) +app.use(validateAccess); // mount routes to specific path -app.use('/api', apiRoutes) -app.use('/eth', ethRoutes) -app.use('/eth/uniswap', uniswapRoutes) -app.use('/eth/uniswap/v3', uniswapV3Routes) -app.use('/eth/balancer', balancerRoutes) -app.use('/terra', terraRoutes) -app.use('/perpfi', perpFiRoutes) +app.use('/api', apiRoutes); +app.use('/eth', ethRoutes); +app.use('/eth/uniswap', uniswapRoutes); +app.use('/eth/uniswap/v3', uniswapV3Routes); +app.use('/eth/balancer', balancerRoutes); +app.use('/terra', terraRoutes); +app.use('/perpfi', perpFiRoutes); // app.use('/celo', celoRoutes); app.get('/', (req, res, _next) => { - res.send('ok') -}) + res.send('ok'); +}); /** * Catch all 404 response when routes are not found */ app.use((req, res, _next) => { - const message = `${statusMessages.page_not_found} at ${req.originalUrl}` - logger.error(message) + const message = `${statusMessages.page_not_found} at ${req.originalUrl}`; + logger.error(message); res.status(404).send({ error: 'Page not found', message - }) -}) + }); +}); -export default app +export default app; diff --git a/src/index.js b/src/index.js index f7480db..b747328 100644 --- a/src/index.js +++ b/src/index.js @@ -1,37 +1,37 @@ #!/usr/bin/env node // absolute imports -import https from 'https' -import dotenv from 'dotenv' -import fs from 'fs' +import https from 'https'; +import dotenv from 'dotenv'; +import fs from 'fs'; // relative imports -import app from './app' -import { logger } from './services/logger' +import app from './app'; +import { logger } from './services/logger'; // terminate if environment not found -const result = dotenv.config() +const result = dotenv.config(); if (result.error) { - logger.info(result.error) - process.exit(1) + logger.info(result.error); + process.exit(1); } -const env = process.env.NODE_ENV -const port = process.env.PORT -const certPassphrase = process.env.CERT_PASSPHRASE -const ethereumChain = process.env.ETHEREUM_CHAIN -const terraChain = process.env.TERRA_CHAIN -let certPath = process.env.CERT_PATH +const env = process.env.NODE_ENV; +const port = process.env.PORT; +const certPassphrase = process.env.CERT_PASSPHRASE; +const ethereumChain = process.env.ETHEREUM_CHAIN; +const terraChain = process.env.TERRA_CHAIN; +let certPath = process.env.CERT_PATH; if ((typeof certPath === 'undefined' && certPath == null) || certPath === '') { // assuming it is local development using test script to generate certs - certPath = './certs' + certPath = './certs'; } else { - certPath = certPath.replace(/\/$/, '') + certPath = certPath.replace(/\/$/, ''); } // set app environment -app.set('env', env) +app.set('env', env); const options = { key: fs.readFileSync(certPath.concat('/server_key.pem'), { encoding: 'utf-8' @@ -46,52 +46,52 @@ const options = { // use ca cert created with own key for self-signed ca: [fs.readFileSync(certPath.concat('/ca_cert.pem'), { encoding: 'utf-8' })], passphrase: certPassphrase -} +}; -const server = https.createServer(options, app) +const server = https.createServer(options, app); // event listener for "error" event const onError = (error) => { if (error.syscall !== 'listen') { - throw error + throw error; } - const bind = typeof port === 'string' ? `Pipe ${port}` : `Port ${port}` + const bind = typeof port === 'string' ? `Pipe ${port}` : `Port ${port}`; // handle specific listen errors with friendly messages switch (error.code) { case 'EACCES': - console.error(`${bind} requires elevated privileges`) - process.exit(1) - break + console.error(`${bind} requires elevated privileges`); + process.exit(1); + break; case 'EADDRINUSE': - console.error(`${bind} is already in use`) - process.exit(1) - break + console.error(`${bind} is already in use`); + process.exit(1); + break; default: - throw error + throw error; } -} +}; // event listener for "listening" event. const onListening = () => { - const addr = server.address() - const bind = typeof addr === 'string' ? `pipe ${addr}` : `port ${addr.port}` - console.log(`listening on ${bind}`) - logger.debug(`listening on ${bind}`) -} + const addr = server.address(); + const bind = typeof addr === 'string' ? `pipe ${addr}` : `port ${addr.port}`; + console.log(`listening on ${bind}`); + logger.debug(`listening on ${bind}`); +}; // listen on provided port, on all network interfaces. -server.listen(port) -server.on('error', onError) -server.on('listening', onListening) +server.listen(port); +server.on('error', onError); +server.on('listening', onListening); const serverConfig = { app: 'gateway-api', port, ethereumChain, terraChain -} +}; -logger.info(JSON.stringify(serverConfig)) -console.log(serverConfig) +logger.info(JSON.stringify(serverConfig)); +console.log(serverConfig); diff --git a/src/routes/balancer.route.js b/src/routes/balancer.route.js index ddc17e6..1b75e4b 100644 --- a/src/routes/balancer.route.js +++ b/src/routes/balancer.route.js @@ -1,28 +1,28 @@ -import BigNumber from 'bignumber.js' -import { ethers } from 'ethers' -import express from 'express' +import BigNumber from 'bignumber.js'; +import { ethers } from 'ethers'; +import express from 'express'; -import { getParamData, latency, statusMessages } from '../services/utils' +import { getParamData, latency, statusMessages } from '../services/utils'; -import Ethereum from '../services/eth' -import Balancer from '../services/balancer' -import Fees from '../services/fees' -import { logger } from '../services/logger' +import Ethereum from '../services/eth'; +import Balancer from '../services/balancer'; +import Fees from '../services/fees'; +import { logger } from '../services/logger'; -const debug = require('debug')('router') +const debug = require('debug')('router'); -const router = express.Router() -const eth = new Ethereum(process.env.ETHEREUM_CHAIN) -const balancer = new Balancer(process.env.ETHEREUM_CHAIN) -const fees = new Fees() +const router = express.Router(); +const eth = new Ethereum(process.env.ETHEREUM_CHAIN); +const balancer = new Balancer(process.env.ETHEREUM_CHAIN); +const fees = new Fees(); -const swapMoreThanMaxPriceError = 'Price too high' -const swapLessThanMaxPriceError = 'Price too low' +const swapMoreThanMaxPriceError = 'Price too high'; +const swapLessThanMaxPriceError = 'Price too low'; const estimateGasLimit = (maxswaps) => { - const gasLimit = balancer.gasBase + maxswaps * balancer.gasPerSwap - return gasLimit -} + const gasLimit = balancer.gasBase + maxswaps * balancer.gasPerSwap; + return gasLimit; +}; router.post('/', async (req, res) => { /* @@ -35,8 +35,8 @@ router.post('/', async (req, res) => { subgraphUrl: balancer.subgraphUrl, connection: true, timestamp: Date.now() - }) -}) + }); +}); router.post('/gas-limit', async (req, res) => { /* @@ -45,33 +45,33 @@ router.post('/gas-limit', async (req, res) => { "maxSwaps":4 } */ - const paramData = getParamData(req.body) + const paramData = getParamData(req.body); try { - const swaps = paramData.maxSwaps + const swaps = paramData.maxSwaps; const maxSwaps = typeof swaps === 'undefined' || parseInt(swaps) === 0 ? balancer.maxSwaps - : parseInt(swaps) - const gasLimit = estimateGasLimit(maxSwaps) + : parseInt(swaps); + const gasLimit = estimateGasLimit(maxSwaps); res.status(200).json({ network: balancer.network, gasLimit, timestamp: Date.now() - }) + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.get('/start', async (req, res) => { /* @@ -81,23 +81,23 @@ router.get('/start', async (req, res) => { "gasPrice":30 } */ - const initTime = Date.now() - const paramData = getParamData(req.query) - const pairs = JSON.parse(paramData.pairs) - let gasPrice + const initTime = Date.now(); + const paramData = getParamData(req.query); + const pairs = JSON.parse(paramData.pairs); + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } // get token contract address and cache pools for (let pair of pairs) { - pair = pair.split('-') - const baseTokenSymbol = pair[0] - const quoteTokenSymbol = pair[1] - const baseTokenContractInfo = eth.getERC20TokenAddresses(baseTokenSymbol) - const quoteTokenContractInfo = eth.getERC20TokenAddresses(quoteTokenSymbol) + pair = pair.split('-'); + const baseTokenSymbol = pair[0]; + const quoteTokenSymbol = pair[1]; + const baseTokenContractInfo = eth.getERC20TokenAddresses(baseTokenSymbol); + const quoteTokenContractInfo = eth.getERC20TokenAddresses(quoteTokenSymbol); // check for valid token symbols if ( @@ -105,12 +105,14 @@ router.get('/start', async (req, res) => { quoteTokenContractInfo === undefined ) { const undefinedToken = - baseTokenContractInfo === undefined ? baseTokenSymbol : quoteTokenSymbol + baseTokenContractInfo === undefined + ? baseTokenSymbol + : quoteTokenSymbol; res.status(500).json({ error: `Token ${undefinedToken} contract address not found`, message: `Token contract address not found for ${undefinedToken}. Check token list source` - }) - return + }); + return; } await Promise.allSettled([ balancer.fetchPool( @@ -121,11 +123,11 @@ router.get('/start', async (req, res) => { quoteTokenContractInfo.address, baseTokenContractInfo.address ) - ]) + ]); } - const gasLimit = estimateGasLimit(balancer.maxSwaps) - const gasCost = await fees.getGasCost(gasPrice, gasLimit) + const gasLimit = estimateGasLimit(balancer.maxSwaps); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); const result = { network: eth.network, @@ -136,10 +138,10 @@ router.get('/start', async (req, res) => { gasPrice, gasLimit, gasCost - } - console.log('Initializing balancer') - res.status(200).json(result) -}) + }; + console.log('Initializing balancer'); + res.status(200).json(result); +}); router.post('/price', async (req, res) => { /* @@ -151,23 +153,25 @@ router.post('/price', async (req, res) => { "side":buy } */ - const initTime = Date.now() + const initTime = Date.now(); // params: base (required), quote (required), amount (required) - const paramData = getParamData(req.body) - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base) - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote) - const baseTokenAddress = baseTokenContractInfo.address - const quoteTokenAddress = quoteTokenContractInfo.address - const baseDenomMultiplier = 10 ** baseTokenContractInfo.decimals - const quoteDenomMultiplier = 10 ** quoteTokenContractInfo.decimals - const amount = new BigNumber(parseInt(paramData.amount * baseDenomMultiplier)) - const maxSwaps = balancer.maxSwaps - const side = paramData.side.toUpperCase() - let gasPrice + const paramData = getParamData(req.body); + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base); + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote); + const baseTokenAddress = baseTokenContractInfo.address; + const quoteTokenAddress = quoteTokenContractInfo.address; + const baseDenomMultiplier = 10 ** baseTokenContractInfo.decimals; + const quoteDenomMultiplier = 10 ** quoteTokenContractInfo.decimals; + const amount = new BigNumber( + parseInt(paramData.amount * baseDenomMultiplier) + ); + const maxSwaps = balancer.maxSwaps; + const side = paramData.side.toUpperCase(); + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } try { @@ -185,17 +189,18 @@ router.post('/price', async (req, res) => { quoteTokenAddress, // tokenOut is quote asset amount, maxSwaps - ) + ); if (swaps != null && expectedAmount != null) { - const gasLimit = estimateGasLimit(swaps.length) - const gasCost = await fees.getGasCost(gasPrice, gasLimit) + const gasLimit = estimateGasLimit(swaps.length); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); - const tradeAmount = parseFloat(amount) + const tradeAmount = parseFloat(amount); const expectedTradeAmount = - parseInt(expectedAmount) / quoteDenomMultiplier + parseInt(expectedAmount) / quoteDenomMultiplier; const tradePrice = - ((expectedAmount / amount) * baseDenomMultiplier) / quoteDenomMultiplier + ((expectedAmount / amount) * baseDenomMultiplier) / + quoteDenomMultiplier; const result = { network: balancer.network, @@ -211,30 +216,30 @@ router.post('/price', async (req, res) => { gasLimit, gasCost, swaps - } + }; debug( `Price ${side} ${baseTokenContractInfo.symbol}-${quoteTokenContractInfo.symbol} | amount:${amount} (rate:${tradePrice}) - gasPrice:${gasPrice} gasLimit:${gasLimit} estimated fee:${gasCost} ETH` - ) - res.status(200).json(result) + ); + res.status(200).json(result); } else { // no pool available res.status(200).json({ info: statusMessages.no_pool_available, message: statusMessages.no_pool_available - }) + }); } } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/trade', async (req, res) => { /* @@ -249,31 +254,33 @@ router.post('/trade', async (req, res) => { "privateKey":{{privateKey}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - const wallet = new ethers.Wallet(privateKey, balancer.provider) + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + const wallet = new ethers.Wallet(privateKey, balancer.provider); - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base) - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote) - const baseTokenAddress = baseTokenContractInfo.address - const quoteTokenAddress = quoteTokenContractInfo.address - const baseDenomMultiplier = 10 ** baseTokenContractInfo.decimals - const quoteDenomMultiplier = 10 ** quoteTokenContractInfo.decimals - const amount = new BigNumber(parseInt(paramData.amount * baseDenomMultiplier)) + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base); + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote); + const baseTokenAddress = baseTokenContractInfo.address; + const quoteTokenAddress = quoteTokenContractInfo.address; + const baseDenomMultiplier = 10 ** baseTokenContractInfo.decimals; + const quoteDenomMultiplier = 10 ** quoteTokenContractInfo.decimals; + const amount = new BigNumber( + parseInt(paramData.amount * baseDenomMultiplier) + ); - const maxSwaps = balancer.maxSwaps - const side = paramData.side.toUpperCase() + const maxSwaps = balancer.maxSwaps; + const side = paramData.side.toUpperCase(); - let limitPrice + let limitPrice; if (paramData.limitPrice) { - limitPrice = parseFloat(paramData.limitPrice) + limitPrice = parseFloat(paramData.limitPrice); } - let gasPrice + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } try { @@ -291,15 +298,16 @@ router.post('/trade', async (req, res) => { quoteTokenAddress, // tokenOut is quote asset amount, maxSwaps - ) + ); - const gasLimit = estimateGasLimit(swaps.length) - const gasCost = await fees.getGasCost(gasPrice, gasLimit) + const gasLimit = estimateGasLimit(swaps.length); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); if (side === 'BUY') { const price = - ((expectedAmount / amount) * baseDenomMultiplier) / quoteDenomMultiplier - logger.info(`Price: ${price.toString()}`) + ((expectedAmount / amount) * baseDenomMultiplier) / + quoteDenomMultiplier; + logger.info(`Price: ${price.toString()}`); if (!limitPrice || price <= limitPrice) { // pass swaps to exchange-proxy to complete trade const tx = await balancer.swapExactOut( @@ -309,7 +317,7 @@ router.post('/trade', async (req, res) => { baseTokenAddress, // tokenOut is base asset expectedAmount.toString(), gasPrice - ) + ); // submit response res.status(200).json({ @@ -325,21 +333,22 @@ router.post('/trade', async (req, res) => { gasLimit, gasCost, txHash: tx.hash - }) + }); } else { res.status(200).json({ error: swapMoreThanMaxPriceError, message: `Swap price ${price} exceeds limitPrice ${limitPrice}` - }) - debug(`Swap price ${price} exceeds limitPrice ${limitPrice}`) + }); + debug(`Swap price ${price} exceeds limitPrice ${limitPrice}`); } } else { // sell - const minAmountOut = (limitPrice / amount) * baseDenomMultiplier - debug('minAmountOut', minAmountOut) + const minAmountOut = (limitPrice / amount) * baseDenomMultiplier; + debug('minAmountOut', minAmountOut); const price = - ((expectedAmount / amount) * baseDenomMultiplier) / quoteDenomMultiplier - logger.info(`Price: ${price.toString()}`) + ((expectedAmount / amount) * baseDenomMultiplier) / + quoteDenomMultiplier; + logger.info(`Price: ${price.toString()}`); if (!limitPrice || price >= limitPrice) { // pass swaps to exchange-proxy to complete trade const tx = await balancer.swapExactIn( @@ -350,7 +359,7 @@ router.post('/trade', async (req, res) => { amount.toString(), parseInt(expectedAmount) / quoteDenomMultiplier, gasPrice - ) + ); // submit response res.status(200).json({ network: balancer.network, @@ -365,26 +374,26 @@ router.post('/trade', async (req, res) => { gasLimit, gasCost, txHash: tx.hash - }) + }); } else { res.status(200).json({ error: swapLessThanMaxPriceError, message: `Swap price ${price} lower than limitPrice ${limitPrice}` - }) - debug(`Swap price ${price} lower than limitPrice ${limitPrice}`) + }); + debug(`Swap price ${price} lower than limitPrice ${limitPrice}`); } } } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); -export default router +export default router; diff --git a/src/routes/celo.route.js b/src/routes/celo.route.js index 0581c4c..933ff92 100644 --- a/src/routes/celo.route.js +++ b/src/routes/celo.route.js @@ -1,146 +1,146 @@ -const express = require('express') +const express = require('express'); -const router = express.Router() -const BigNumber = require('bignumber.js') -const debug = require('debug')('router') -const spawn = require('child_process').spawn +const router = express.Router(); +const BigNumber = require('bignumber.js'); +const debug = require('debug')('router'); +const spawn = require('child_process').spawn; -const network = 'celo' -const celocli = 'celocli' -const DENOM_UNIT_MULTIPLIER = BigNumber('1e+18') +const network = 'celo'; +const celocli = 'celocli'; +const DENOM_UNIT_MULTIPLIER = BigNumber('1e+18'); -const hbUtils = require('../services/utils') +const hbUtils = require('../services/utils'); -const separator = '=>' +const separator = '=>'; router.use((req, res, next) => { - debug('celo route:', Date.now()) - next() -}) + debug('celo route:', Date.now()); + next(); +}); router.get('/', (req, res) => { - res.status(200).send(network) -}) + res.status(200).send(network); +}); router.get('/status', (req, res) => { /* return if the celocli ultralight node is synced */ - const nodeSync = spawn(celocli, ['node:synced']) + const nodeSync = spawn(celocli, ['node:synced']); - const err_message = [] - const out_message = [] + const err_message = []; + const out_message = []; nodeSync.stdout.on('data', (out) => { - out_message.push(out.toString().trim()) - debug('out_message', out_message) - }) + out_message.push(out.toString().trim()); + debug('out_message', out_message); + }); nodeSync.stderr.on('data', (err) => { - err_message.push(err.toString().trim()) - debug('err_message', err_message) - }) + err_message.push(err.toString().trim()); + debug('err_message', err_message); + }); nodeSync.on('close', (code) => { if (code === 0) { res.status(200).json({ synced: out_message[0].toLowerCase() === 'true', message: err_message.join('') - }) + }); } else { res.status(401).json({ error: err_message.join('') - }) + }); } - }) -}) + }); +}); router.get('/price', (req, res) => { /* api request format: /price?trading_pair=CELO-CUSD&trade_type=sell&amount=1.2345 */ - const keyFormat = ['trading_pair', 'trade_type', 'amount'] + const keyFormat = ['trading_pair', 'trade_type', 'amount']; - const initTime = Date.now() + const initTime = Date.now(); - const paramData = hbUtils.getParamData(req.query, keyFormat) - const tradingPair = paramData.trading_pair - const requestAmount = paramData.amount - const amount = parseFloat(requestAmount) * DENOM_UNIT_MULTIPLIER - debug('params', req.params) - debug('paramData', paramData) + const paramData = hbUtils.getParamData(req.query, keyFormat); + const tradingPair = paramData.trading_pair; + const requestAmount = paramData.amount; + const amount = parseFloat(requestAmount) * DENOM_UNIT_MULTIPLIER; + debug('params', req.params); + debug('paramData', paramData); - const nodeSync = spawn(celocli, ['exchange:show', '--amount', amount]) + const nodeSync = spawn(celocli, ['exchange:show', '--amount', amount]); - const err_message = [] - const out_message = [] + const err_message = []; + const out_message = []; nodeSync.stdout.on('data', (out) => { - out_message.push(out.toString().trim()) - }) + out_message.push(out.toString().trim()); + }); nodeSync.stderr.on('data', (err) => { - err_message.push(err.toString().trim()) - }) + err_message.push(err.toString().trim()); + }); nodeSync.on('close', (code) => { - const exchange_rates = {} - let price + const exchange_rates = {}; + let price; if (code === 0) { // extract exchange rate from cli output out_message.forEach((item, _index) => { if (item.includes(separator)) { - const exchangeInfo = item.split(separator) - const base = exchangeInfo[0].trim().split(' ') - const quote = exchangeInfo[1].trim().split(' ') + const exchangeInfo = item.split(separator); + const base = exchangeInfo[0].trim().split(' '); + const quote = exchangeInfo[1].trim().split(' '); const market = [base[1].toUpperCase(), quote[1].toUpperCase()].join( '-' - ) - exchange_rates[market] = quote[0] / DENOM_UNIT_MULTIPLIER - debug(exchangeInfo, exchange_rates) + ); + exchange_rates[market] = quote[0] / DENOM_UNIT_MULTIPLIER; + debug(exchangeInfo, exchange_rates); } - }) + }); - price = exchange_rates[tradingPair] + price = exchange_rates[tradingPair]; const result = Object.assign(paramData, { price, timestamp: initTime, latency: hbUtils.latency(initTime, Date.now()) - }) - res.status(200).json(result) + }); + res.status(200).json(result); } - }) -}) + }); +}); router.get('/balance', (req, res) => { /* api request format: /balance?address=0x87A4...b120 */ - const keyFormat = ['address'] - const paramData = hbUtils.getParamData(req.query, keyFormat) - const address = paramData.address - debug(paramData) + const keyFormat = ['address']; + const paramData = hbUtils.getParamData(req.query, keyFormat); + const address = paramData.address; + debug(paramData); - const balance = spawn(celocli, ['account:balance', address]) + const balance = spawn(celocli, ['account:balance', address]); - const err_message = [] - const out_message = [] - const walletBalances = {} + const err_message = []; + const out_message = []; + const walletBalances = {}; balance.stdout.on('data', (out) => { - out_message.push(out.toString().trim()) - debug(out_message) - }) + out_message.push(out.toString().trim()); + debug(out_message); + }); balance.stderr.on('data', (err) => { - err_message.push(err.toString().trim()) - debug(err_message) - }) + err_message.push(err.toString().trim()); + debug(err_message); + }); balance.on('close', (code) => { if (code === 0) { @@ -150,28 +150,28 @@ router.get('/balance', (req, res) => { item.toLowerCase().includes('lockedcelo') || item.toLowerCase().includes('lockedgold') ) { - const balanceArray = item.split('\n') + const balanceArray = item.split('\n'); balanceArray.forEach((x) => { - const keyValue = x.split(':') + const keyValue = x.split(':'); walletBalances[keyValue[0].trim()] = - keyValue[1].trim() / DENOM_UNIT_MULTIPLIER - }) - debug('walletBalances', walletBalances) + keyValue[1].trim() / DENOM_UNIT_MULTIPLIER; + }); + debug('walletBalances', walletBalances); } - }) + }); res.status(200).json({ address, balance: walletBalances, timestamp: Date.now() - }) + }); } else { res.status(401).json({ error: err_message - }) + }); } - }) -}) + }); +}); router.post('/unlock', (req, res) => { /* @@ -182,58 +182,58 @@ router.post('/unlock', (req, res) => { "secret": "mysupersecret" } */ - const keyFormat = ['address', 'secret'] - const paramData = hbUtils.getParamData(req.body, keyFormat) - const address = paramData.address - const secret = paramData.secret + const keyFormat = ['address', 'secret']; + const paramData = hbUtils.getParamData(req.body, keyFormat); + const address = paramData.address; + const secret = paramData.secret; - debug(paramData) - debug(req.body) + debug(paramData); + debug(req.body); const lockStatus = spawn(celocli, [ 'account:unlock', address, '--password', secret - ]) + ]); - const err_message = [] - const out_message = [] + const err_message = []; + const out_message = []; lockStatus.stdout.on('data', (out) => { - out_message.push(out.toString().trim()) - debug(out_message) - }) + out_message.push(out.toString().trim()); + debug(out_message); + }); lockStatus.stderr.on('data', (err) => { - err_message.push(err.toString().trim()) - debug(err_message) - }) + err_message.push(err.toString().trim()); + debug(err_message); + }); lockStatus.on('close', (code) => { - let unlocked = false + let unlocked = false; if (code === 0) { if (out_message.length > 0) { out_message.forEach((item, _index) => { if (item.includes(separator)) { - debug('item', item) + debug('item', item); } - }) + }); } else { - unlocked = true + unlocked = true; } res.status(200).json({ unlocked, message: out_message.join(), timestamp: Date.now() - }) + }); } else { res.status(401).json({ error: err_message.join() - }) + }); } - }) -}) + }); +}); router.post('/trade', (req, res) => { /* @@ -246,14 +246,14 @@ router.post('/trade', (req, res) => { "price": 3.512 } */ - const keyFormat = ['trading_pair', 'trade_type', 'amount', 'price'] - const paramData = hbUtils.getParamData(req.body, keyFormat) - debug(paramData) + const keyFormat = ['trading_pair', 'trade_type', 'amount', 'price']; + const paramData = hbUtils.getParamData(req.body, keyFormat); + debug(paramData); // const result = Object.assign(paramData, { // message: 'WIP', // timestamp: Date.now() // }) - res.status(200).json({ status: 'WIP' }) -}) + res.status(200).json({ status: 'WIP' }); +}); -module.exports = router +module.exports = router; diff --git a/src/routes/eth.route.js b/src/routes/eth.route.js index 09dac12..9943bca 100644 --- a/src/routes/eth.route.js +++ b/src/routes/eth.route.js @@ -1,22 +1,22 @@ -import { ethers, BigNumber } from 'ethers' -import express from 'express' +import { ethers, BigNumber } from 'ethers'; +import express from 'express'; -import { getParamData, latency, statusMessages } from '../services/utils' -import Ethereum from '../services/eth' -import Fees from '../services/fees' -import { logger } from '../services/logger' +import { getParamData, latency, statusMessages } from '../services/utils'; +import Ethereum from '../services/eth'; +import Fees from '../services/fees'; +import { logger } from '../services/logger'; -const debug = require('debug')('router') +const debug = require('debug')('router'); -const router = express.Router() -const eth = new Ethereum(process.env.ETHEREUM_CHAIN) +const router = express.Router(); +const eth = new Ethereum(process.env.ETHEREUM_CHAIN); const spenders = { balancer: process.env.EXCHANGE_PROXY, uniswap: process.env.UNISWAP_ROUTER, uniswapV3Router: process.env.UNISWAP_V3_ROUTER, uniswapV3NFTManager: process.env.UNISWAP_V3_NFT_MANAGER -} -const fees = new Fees() +}; +const fees = new Fees(); router.post('/', async (req, res) => { /* @@ -27,8 +27,8 @@ router.post('/', async (req, res) => { rpcUrl: eth.provider.connection.url, connection: true, timestamp: Date.now() - }) -}) + }); +}); router.post('/balances', async (req, res) => { /* @@ -38,73 +38,73 @@ router.post('/balances', async (req, res) => { tokenList:{{tokenList}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + let wallet; try { - wallet = new ethers.Wallet(privateKey, eth.provider) + wallet = new ethers.Wallet(privateKey, eth.provider); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet'); res.status(500).json({ error: reason, message: err - }) - return + }); + return; } // populate token contract info using token symbol list - const tokenContractList = [] - const tokenList = JSON.parse(paramData.tokenList) + const tokenContractList = []; + const tokenList = JSON.parse(paramData.tokenList); tokenList.forEach((symbol) => { - const tokenContractInfo = eth.getERC20TokenAddresses(symbol) - tokenContractList[symbol] = tokenContractInfo - }) + const tokenContractInfo = eth.getERC20TokenAddresses(symbol); + tokenContractList[symbol] = tokenContractInfo; + }); - const balances = {} - balances.ETH = await eth.getETHBalance(wallet, privateKey) + const balances = {}; + balances.ETH = await eth.getETHBalance(wallet, privateKey); try { Promise.all( Object.keys(tokenContractList).map(async (symbol, _index) => { if (tokenContractList[symbol] !== undefined) { - const address = tokenContractList[symbol].address - const decimals = tokenContractList[symbol].decimals + const address = tokenContractList[symbol].address; + const decimals = tokenContractList[symbol].decimals; balances[symbol] = await eth.getERC20Balance( wallet, address, decimals - ) + ); } else { - const err = `Token contract info for ${symbol} not found` - logger.error('Token info not found', { message: err }) - debug(err) + const err = `Token contract info for ${symbol} not found`; + logger.error('Token info not found', { message: err }); + debug(err); } }) ).then(() => { debug('eth.route - Get Account Balance', { message: JSON.stringify(tokenList) - }) + }); res.status(200).json({ network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), balances - }) - }) + }); + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/allowances', async (req, res) => { /* @@ -115,69 +115,69 @@ router.post('/allowances', async (req, res) => { connector:{{connector_name}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - const spender = spenders[paramData.connector] - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + const spender = spenders[paramData.connector]; + let wallet; try { - wallet = new ethers.Wallet(privateKey, eth.provider) + wallet = new ethers.Wallet(privateKey, eth.provider); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet'); res.status(500).json({ error: reason, message: err - }) - return + }); + return; } // populate token contract info using token symbol list - const tokenContractList = [] - const tokenList = JSON.parse(paramData.tokenList) + const tokenContractList = []; + const tokenList = JSON.parse(paramData.tokenList); tokenList.forEach((symbol) => { - const tokenContractInfo = eth.getERC20TokenAddresses(symbol) - tokenContractList[symbol] = tokenContractInfo - }) + const tokenContractInfo = eth.getERC20TokenAddresses(symbol); + tokenContractList[symbol] = tokenContractInfo; + }); - const approvals = {} + const approvals = {}; try { Promise.all( Object.keys(tokenContractList).map(async (symbol, _index) => { - const address = tokenContractList[symbol].address - const decimals = tokenContractList[symbol].decimals + const address = tokenContractList[symbol].address; + const decimals = tokenContractList[symbol].decimals; approvals[symbol] = await eth.getERC20Allowance( wallet, spender, address, decimals - ) + ); }) ).then(() => { logger.info('eth.route - Getting allowances', { message: JSON.stringify(tokenList) - }) + }); res.status(200).json({ network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), spender, approvals - }) - }) + }); + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/balances-2', async (req, res) => { /* @@ -188,32 +188,32 @@ router.post('/balances-2', async (req, res) => { tokenDecimalList:{{tokenDecimalList}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + let wallet; try { - wallet = new ethers.Wallet(privateKey, eth.provider) + wallet = new ethers.Wallet(privateKey, eth.provider); } catch (err) { - let reason - err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') + let reason; + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet'); res.status(500).json({ error: reason, message: err - }) - return + }); + return; } - let tokenAddressList + let tokenAddressList; if (paramData.tokenAddressList) { - tokenAddressList = paramData.tokenAddressList.split(',') + tokenAddressList = paramData.tokenAddressList.split(','); } - let tokenDecimalList + let tokenDecimalList; if (paramData.tokenDecimalList) { - tokenDecimalList = paramData.tokenDecimalList.split(',') + tokenDecimalList = paramData.tokenDecimalList.split(','); } - const balances = {} - balances.ETH = await eth.getETHBalance(wallet, privateKey) + const balances = {}; + balances.ETH = await eth.getETHBalance(wallet, privateKey); try { Promise.all( tokenAddressList.map( @@ -230,19 +230,19 @@ router.post('/balances-2', async (req, res) => { timestamp: initTime, latency: latency(initTime, Date.now()), balances - }) - }) + }); + }); } catch (err) { - let reason + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/allowances-2', async (req, res) => { /* @@ -254,32 +254,32 @@ router.post('/allowances-2', async (req, res) => { connector:{{connector_name}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - const spender = spenders[paramData.connector] - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + const spender = spenders[paramData.connector]; + let wallet; try { - wallet = new ethers.Wallet(privateKey, eth.provider) + wallet = new ethers.Wallet(privateKey, eth.provider); } catch (err) { - let reason - err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') + let reason; + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet'); res.status(500).json({ error: reason, message: err - }) - return + }); + return; } - let tokenAddressList + let tokenAddressList; if (paramData.tokenAddressList) { - tokenAddressList = paramData.tokenAddressList.split(',') + tokenAddressList = paramData.tokenAddressList.split(','); } - let tokenDecimalList + let tokenDecimalList; if (paramData.tokenDecimalList) { - tokenDecimalList = paramData.tokenDecimalList.split(',') + tokenDecimalList = paramData.tokenDecimalList.split(','); } - const approvals = {} + const approvals = {}; try { Promise.all( tokenAddressList.map( @@ -298,19 +298,19 @@ router.post('/allowances-2', async (req, res) => { latency: latency(initTime, Date.now()), spender, approvals - }) - }) + }); + }); } catch (err) { - let reason + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/approve', async (req, res) => { /* @@ -323,37 +323,37 @@ router.post('/approve', async (req, res) => { amount:{{amount}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - const spender = spenders[paramData.connector] - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + const spender = spenders[paramData.connector]; + let wallet; try { - wallet = new ethers.Wallet(privateKey, eth.provider) + wallet = new ethers.Wallet(privateKey, eth.provider); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet'); res.status(500).json({ error: reason, message: err - }) - return + }); + return; } - const token = paramData.token - const tokenContractInfo = eth.getERC20TokenAddresses(token) - const tokenAddress = tokenContractInfo.address - const decimals = tokenContractInfo.decimals + const token = paramData.token; + const tokenContractInfo = eth.getERC20TokenAddresses(token); + const tokenAddress = tokenContractInfo.address; + const decimals = tokenContractInfo.decimals; - let amount + let amount; paramData.amount ? (amount = ethers.utils.parseUnits(paramData.amount, decimals)) - : (amount = ethers.constants.MaxUint256) // approve max possible units if no amount specified - let gasPrice + : (amount = ethers.constants.MaxUint256); // approve max possible units if no amount specified + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } try { @@ -364,7 +364,7 @@ router.post('/approve', async (req, res) => { tokenAddress, amount, gasPrice - ) + ); // console.log('eth.route - Approving allowance', { message: approval }) // submit response res.status(200).json({ @@ -375,37 +375,37 @@ router.post('/approve', async (req, res) => { spender, amount: amount / (1e18).toString(), approval - }) + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/poll', async (req, res) => { - const initTime = Date.now() - const paramData = getParamData(req.body) - const txHash = paramData.txHash - const txReceipt = await eth.provider.getTransactionReceipt(txHash) - const receipt = {} - const confirmed = !!(txReceipt && txReceipt.blockNumber) + const initTime = Date.now(); + const paramData = getParamData(req.body); + const txHash = paramData.txHash; + const txReceipt = await eth.provider.getTransactionReceipt(txHash); + const receipt = {}; + const confirmed = !!(txReceipt && txReceipt.blockNumber); if (confirmed) { - receipt.gasUsed = BigNumber.from(txReceipt.gasUsed).toNumber() - receipt.blockNumber = txReceipt.blockNumber - receipt.confirmations = txReceipt.confirmations - receipt.status = txReceipt.status - receipt.logs = txReceipt.logs + receipt.gasUsed = BigNumber.from(txReceipt.gasUsed).toNumber(); + receipt.blockNumber = txReceipt.blockNumber; + receipt.confirmations = txReceipt.confirmations; + receipt.status = txReceipt.status; + receipt.logs = txReceipt.logs; } logger.info(`eth.route - Get TX Receipt: ${txHash}`, { message: JSON.stringify(receipt) - }) + }); res.status(200).json({ network: eth.network, timestamp: initTime, @@ -413,9 +413,9 @@ router.post('/poll', async (req, res) => { txHash, confirmed, receipt - }) - return txReceipt -}) + }); + return txReceipt; +}); // Kovan faucet to get test tokens (wip) & weth conversion // router.post('/get-weth', async (req, res) => { @@ -472,4 +472,4 @@ router.post('/poll', async (req, res) => { // } // }) -module.exports = router +module.exports = router; diff --git a/src/routes/index.route.js b/src/routes/index.route.js index 1116b5c..dc02e08 100644 --- a/src/routes/index.route.js +++ b/src/routes/index.route.js @@ -1,8 +1,8 @@ -import { loadConfig } from '../services/utils' +import { loadConfig } from '../services/utils'; -const express = require('express') +const express = require('express'); -const router = express.Router() +const router = express.Router(); router.get('/', (req, res) => { res.status(200).json({ @@ -10,7 +10,7 @@ router.get('/', (req, res) => { image: process.env.IMAGE, config: loadConfig(), status: 'ok' - }) -}) + }); +}); -module.exports = router +module.exports = router; diff --git a/src/routes/perpetual_finance.route.js b/src/routes/perpetual_finance.route.js index 0441a39..e0858bc 100644 --- a/src/routes/perpetual_finance.route.js +++ b/src/routes/perpetual_finance.route.js @@ -1,15 +1,15 @@ -import { ethers } from 'ethers' -import express from 'express' +import { ethers } from 'ethers'; +import express from 'express'; -import { getParamData, latency, statusMessages } from '../services/utils' -import { logger } from '../services/logger' -import PerpetualFinance from '../services/perpetual_finance' +import { getParamData, latency, statusMessages } from '../services/utils'; +import { logger } from '../services/logger'; +import PerpetualFinance from '../services/perpetual_finance'; -require('dotenv').config() +require('dotenv').config(); -const router = express.Router() -const perpFi = new PerpetualFinance(process.env.ETHEREUM_CHAIN) -setTimeout(perpFi.update_price_loop.bind(perpFi), 2000) +const router = express.Router(); +const perpFi = new PerpetualFinance(process.env.ETHEREUM_CHAIN); +setTimeout(perpFi.update_price_loop.bind(perpFi), 2000); router.get('/', async (req, res) => { /* @@ -21,22 +21,22 @@ router.get('/', async (req, res) => { loadedMetadata: perpFi.loadedMetadata, connection: true, timestamp: Date.now() - }) -}) + }); +}); router.get('/load-metadata', async (req, res) => { /* GET / */ - const loadedMetadata = await perpFi.load_metadata() + const loadedMetadata = await perpFi.load_metadata(); res.status(200).json({ network: perpFi.network, provider: perpFi.provider.connection.url, loadedMetadata, connection: true, timestamp: Date.now() - }) -}) + }); +}); router.post('/balances', async (req, res) => { /* @@ -45,43 +45,43 @@ router.post('/balances', async (req, res) => { privateKey:{{privateKey}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + let wallet; try { - wallet = new ethers.Wallet(privateKey, perpFi.provider) + wallet = new ethers.Wallet(privateKey, perpFi.provider); } catch (err) { - let reason - err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') + let reason; + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet'); res.status(500).json({ error: reason, message: err - }) - return + }); + return; } - const balances = {} - balances.XDAI = await perpFi.getXdaiBalance(wallet) - balances.USDC = await perpFi.getUSDCBalance(wallet) + const balances = {}; + balances.XDAI = await perpFi.getXdaiBalance(wallet); + balances.USDC = await perpFi.getUSDCBalance(wallet); try { res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), balances - }) + }); } catch (err) { - let reason + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/allowances', async (req, res) => { /* @@ -90,42 +90,42 @@ router.post('/allowances', async (req, res) => { privateKey:{{privateKey}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + let wallet; try { - wallet = new ethers.Wallet(privateKey, perpFi.provider) + wallet = new ethers.Wallet(privateKey, perpFi.provider); } catch (err) { - let reason - err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') + let reason; + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet'); res.status(500).json({ error: reason, message: err - }) - return + }); + return; } - const approvals = {} - approvals.USDC = await perpFi.getAllowance(wallet) + const approvals = {}; + approvals.USDC = await perpFi.getAllowance(wallet); try { res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), approvals - }) + }); } catch (err) { - let reason + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/approve', async (req, res) => { /* @@ -135,29 +135,29 @@ router.post('/approve', async (req, res) => { amount:{{amount}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - let amount - paramData.amount ? (amount = paramData.amount) : (amount = '1000000000') - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + let amount; + paramData.amount ? (amount = paramData.amount) : (amount = '1000000000'); + let wallet; try { - wallet = new ethers.Wallet(privateKey, perpFi.provider) + wallet = new ethers.Wallet(privateKey, perpFi.provider); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet'); res.status(500).json({ error: reason, message: err - }) - return + }); + return; } try { // call approve function - const approval = await perpFi.approve(wallet, amount) - logger.info('perpFi.route - Approving allowance') + const approval = await perpFi.approve(wallet, amount); + logger.info('perpFi.route - Approving allowance'); // submit response res.status(200).json({ network: perpFi.network, @@ -165,19 +165,19 @@ router.post('/approve', async (req, res) => { latency: latency(initTime, Date.now()), amount, approval - }) + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/open', async (req, res) => { /* @@ -191,27 +191,27 @@ router.post('/open', async (req, res) => { privateKey:{{privateKey}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const side = paramData.side - const pair = paramData.pair - const margin = paramData.margin - const leverage = paramData.leverage - const minBaseAssetAmount = paramData.minBaseAssetAmount - console.log(minBaseAssetAmount) - const privateKey = paramData.privateKey - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const side = paramData.side; + const pair = paramData.pair; + const margin = paramData.margin; + const leverage = paramData.leverage; + const minBaseAssetAmount = paramData.minBaseAssetAmount; + console.log(minBaseAssetAmount); + const privateKey = paramData.privateKey; + let wallet; try { - wallet = new ethers.Wallet(privateKey, perpFi.provider) + wallet = new ethers.Wallet(privateKey, perpFi.provider); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet'); res.status(500).json({ error: reason, message: err - }) - return + }); + return; } try { @@ -223,8 +223,8 @@ router.post('/open', async (req, res) => { pair, minBaseAssetAmount, wallet - ) - logger.info('perpFi.route - Opening position') + ); + logger.info('perpFi.route - Opening position'); // submit response res.status(200).json({ network: perpFi.network, @@ -235,19 +235,19 @@ router.post('/open', async (req, res) => { leverage, minBaseAssetAmount, txHash: tx.hash - }) + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/close', async (req, res) => { /* @@ -258,29 +258,29 @@ router.post('/close', async (req, res) => { pair:{{pair}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const minimalQuoteAsset = paramData.minimalQuoteAsset - const privateKey = paramData.privateKey - const pair = paramData.pair - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const minimalQuoteAsset = paramData.minimalQuoteAsset; + const privateKey = paramData.privateKey; + const pair = paramData.pair; + let wallet; try { - wallet = new ethers.Wallet(privateKey, perpFi.provider) + wallet = new ethers.Wallet(privateKey, perpFi.provider); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet'); res.status(500).json({ error: reason, message: err - }) - return + }); + return; } try { // call closePosition function - const tx = await perpFi.closePosition(wallet, pair, minimalQuoteAsset) - logger.info('perpFi.route - Closing position') + const tx = await perpFi.closePosition(wallet, pair, minimalQuoteAsset); + logger.info('perpFi.route - Closing position'); // submit response res.status(200).json({ network: perpFi.network, @@ -288,19 +288,19 @@ router.post('/close', async (req, res) => { latency: latency(initTime, Date.now()), minimalQuoteAsset, txHash: tx.hash - }) + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/position', async (req, res) => { /* @@ -310,47 +310,47 @@ router.post('/position', async (req, res) => { pair:{{pair}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - const pair = paramData.pair - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + const pair = paramData.pair; + let wallet; try { - wallet = new ethers.Wallet(privateKey, perpFi.provider) + wallet = new ethers.Wallet(privateKey, perpFi.provider); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet'); res.status(500).json({ error: reason, message: err - }) - return + }); + return; } try { // call getPosition function - const position = await perpFi.getPosition(wallet, pair) - logger.info('perpFi.route - getting active position') + const position = await perpFi.getPosition(wallet, pair); + logger.info('perpFi.route - getting active position'); // submit response res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), position - }) + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/margin', async (req, res) => { /* @@ -359,46 +359,46 @@ router.post('/margin', async (req, res) => { privateKey:{{privateKey}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - let wallet + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + let wallet; try { - wallet = new ethers.Wallet(privateKey, perpFi.provider) + wallet = new ethers.Wallet(privateKey, perpFi.provider); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - err.reason ? (reason = err.reason) : (reason = 'Error getting wallet') + logger.error(req.originalUrl, { message: err }); + let reason; + err.reason ? (reason = err.reason) : (reason = 'Error getting wallet'); res.status(500).json({ error: reason, message: err - }) - return + }); + return; } try { // call getAllBalances function - const allBalances = await perpFi.getActiveMargin(wallet) - logger.info('perpFi.route - Getting all balances') + const allBalances = await perpFi.getActiveMargin(wallet); + logger.info('perpFi.route - Getting all balances'); // submit response res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), margin: allBalances - }) + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/receipt', async (req, res) => { /* @@ -407,21 +407,21 @@ router.post('/receipt', async (req, res) => { txHash:{{txHash}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const txHash = paramData.txHash - const txReceipt = await perpFi.provider.getTransactionReceipt(txHash) - const receipt = {} - const confirmed = !!(txReceipt && txReceipt.blockNumber) + const initTime = Date.now(); + const paramData = getParamData(req.body); + const txHash = paramData.txHash; + const txReceipt = await perpFi.provider.getTransactionReceipt(txHash); + const receipt = {}; + const confirmed = !!(txReceipt && txReceipt.blockNumber); if (txReceipt !== null) { - receipt.gasUsed = ethers.utils.formatEther(txReceipt.gasUsed) - receipt.blockNumber = txReceipt.blockNumber - receipt.confirmations = txReceipt.confirmations - receipt.status = txReceipt.status + receipt.gasUsed = ethers.utils.formatEther(txReceipt.gasUsed); + receipt.blockNumber = txReceipt.blockNumber; + receipt.confirmations = txReceipt.confirmations; + receipt.status = txReceipt.status; } logger.info(`eth.route - Get TX Receipt: ${txHash}`, { message: JSON.stringify(receipt) - }) + }); res.status(200).json({ network: perpFi.network, timestamp: initTime, @@ -429,9 +429,9 @@ router.post('/receipt', async (req, res) => { txHash, confirmed, receipt - }) - return txReceipt -}) + }); + return txReceipt; +}); router.post('/price', async (req, res) => { /* @@ -442,16 +442,16 @@ router.post('/price', async (req, res) => { amount:{{amount}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const side = paramData.side - const pair = paramData.pair - const amount = paramData.amount + const initTime = Date.now(); + const paramData = getParamData(req.body); + const side = paramData.side; + const pair = paramData.pair; + const amount = paramData.amount; try { // call getPrice function - const price = await perpFi.getPrice(side, amount, pair) - logger.info('perpFi.route - Getting price') + const price = await perpFi.getPrice(side, amount, pair); + logger.info('perpFi.route - Getting price'); // submit response res.status(200).json({ network: perpFi.network, @@ -459,25 +459,25 @@ router.post('/price', async (req, res) => { latency: latency(initTime, Date.now()), side, price - }) + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.get('/pairs', async (req, res) => { /* GET */ - const initTime = Date.now() + const initTime = Date.now(); try { res.status(200).json({ @@ -485,19 +485,19 @@ router.get('/pairs', async (req, res) => { timestamp: initTime, latency: latency(initTime, Date.now()), pairs: Object.keys(perpFi.amm) - }) + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/funding', async (req, res) => { /* @@ -506,32 +506,32 @@ router.post('/funding', async (req, res) => { pair:{{pair}} } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const pair = paramData.pair + const initTime = Date.now(); + const paramData = getParamData(req.body); + const pair = paramData.pair; try { // call getFundingRate function - const fr = await perpFi.getFundingRate(pair) - logger.info('perpFi.route - Getting funding info') + const fr = await perpFi.getFundingRate(pair); + logger.info('perpFi.route - Getting funding info'); // submit response res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), fr - }) + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); -export default router +export default router; diff --git a/src/routes/terra.route.js b/src/routes/terra.route.js index 6f9058f..48cb9be 100644 --- a/src/routes/terra.route.js +++ b/src/routes/terra.route.js @@ -1,20 +1,20 @@ -import express from 'express' +import express from 'express'; import { getParamData, latency, reportConnectionError, statusMessages -} from '../services/utils' -import { logger } from '../services/logger' +} from '../services/utils'; +import { logger } from '../services/logger'; -import Terra from '../services/terra' +import Terra from '../services/terra'; -const router = express.Router() -const terra = new Terra() +const router = express.Router(); +const terra = new Terra(); // constants -const network = terra.lcd.config.chainID -const denomUnitMultiplier = terra.denomUnitMultiplier +const network = terra.lcd.config.chainID; +const denomUnitMultiplier = terra.denomUnitMultiplier; router.post('/', async (req, res) => { /* @@ -27,58 +27,58 @@ router.post('/', async (req, res) => { gasAdjustment: terra.lcd.config.gasAdjustment, connection: true, timestamp: Date.now() - }) -}) + }); +}); router.post('/balances', async (req, res) => { /* POST: address:{{address}} */ - const initTime = Date.now() + const initTime = Date.now(); - const paramData = getParamData(req.body) - const address = paramData.address + const paramData = getParamData(req.body); + const address = paramData.address; - const balances = {} + const balances = {}; try { await terra.lcd.bank.balance(address).then((bal) => { bal.toArray().forEach(async (x) => { - const item = x.toData() - const denom = item.denom - const amount = item.amount / denomUnitMultiplier - const symbol = terra.tokens[denom].symbol - balances[symbol] = amount - }) - }) - logger.info('terra.route - Get Account Balance') + const item = x.toData(); + const denom = item.denom; + const amount = item.amount / denomUnitMultiplier; + const symbol = terra.tokens[denom].symbol; + balances[symbol] = amount; + }); + }); + logger.info('terra.route - Get Account Balance'); res.status(200).json({ network, timestamp: initTime, latency: latency(initTime, Date.now()), balances - }) + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let message - let reason + logger.error(req.originalUrl, { message: err }); + let message; + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) - const isAxiosError = err.isAxiosError + : (reason = statusMessages.operation_error); + const isAxiosError = err.isAxiosError; if (isAxiosError) { - reason = err.response.status - message = err.response.statusText + reason = err.response.status; + message = err.response.statusText; } else { - message = err + message = err; } res.status(500).json({ error: reason, message - }) + }); } -}) +}); router.post('/start', async (req, res) => { /* @@ -89,10 +89,10 @@ router.post('/start', async (req, res) => { "amount":1 } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const baseTokenSymbol = paramData.base - const quoteTokenSymbol = paramData.quote + const initTime = Date.now(); + const paramData = getParamData(req.body); + const baseTokenSymbol = paramData.base; + const quoteTokenSymbol = paramData.quote; const result = { network, @@ -101,9 +101,9 @@ router.post('/start', async (req, res) => { success: true, base: baseTokenSymbol, quote: quoteTokenSymbol - } - res.status(200).json(result) -}) + }; + res.status(200).json(result); +}); router.post('/price', async (req, res) => { /* @@ -115,25 +115,25 @@ router.post('/price', async (req, res) => { "amount":1 } */ - const initTime = Date.now() + const initTime = Date.now(); - const paramData = getParamData(req.body) - const baseToken = paramData.base - const quoteToken = paramData.quote - const tradeType = paramData.side.toUpperCase() - const amount = parseFloat(paramData.amount) + const paramData = getParamData(req.body); + const baseToken = paramData.base; + const quoteToken = paramData.quote; + const tradeType = paramData.side.toUpperCase(); + const amount = parseFloat(paramData.amount); - let exchangeRate + let exchangeRate; try { await terra .getSwapRate(baseToken, quoteToken, amount, tradeType) .then((rate) => { - exchangeRate = rate + exchangeRate = rate; }) .catch((err) => { - reportConnectionError(res, err) - }) + reportConnectionError(res, err); + }); res.status(200).json({ network, @@ -146,27 +146,27 @@ router.post('/price', async (req, res) => { price: exchangeRate.price.amount, cost: exchangeRate.cost.amount, txFee: exchangeRate.txFee.amount - }) + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let message - let reason + logger.error(req.originalUrl, { message: err }); + let message; + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) - const isAxiosError = err.isAxiosError + : (reason = statusMessages.operation_error); + const isAxiosError = err.isAxiosError; if (isAxiosError) { - reason = err.response.status - message = err.response.statusText + reason = err.response.status; + message = err.response.statusText; } else { - message = err + message = err; } res.status(500).json({ error: reason, message - }) + }); } -}) +}); router.post('/trade', async (req, res) => { /* @@ -179,20 +179,20 @@ router.post('/trade', async (req, res) => { "secret": "mysupersecret" } */ - const initTime = Date.now() + const initTime = Date.now(); - const paramData = getParamData(req.body) - const baseToken = paramData.base - const quoteToken = paramData.quote - const tradeType = paramData.side.toUpperCase() - const amount = parseFloat(paramData.amount) + const paramData = getParamData(req.body); + const baseToken = paramData.base; + const quoteToken = paramData.quote; + const tradeType = paramData.side.toUpperCase(); + const amount = parseFloat(paramData.amount); const gasPrice = - parseFloat(paramData.gas_price) || terra.lcd.config.gasPrices.uluna + parseFloat(paramData.gas_price) || terra.lcd.config.gasPrices.uluna; const gasAdjustment = - paramData.gas_adjustment || terra.lcd.config.gasAdjustment - const secret = paramData.privateKey + paramData.gas_adjustment || terra.lcd.config.gasAdjustment; + const secret = paramData.privateKey; - let tokenSwaps + let tokenSwaps; try { await terra @@ -206,11 +206,11 @@ router.post('/trade', async (req, res) => { secret ) .then((swap) => { - tokenSwaps = swap + tokenSwaps = swap; }) .catch((err) => { - reportConnectionError(res, err) - }) + reportConnectionError(res, err); + }); const swapResult = { network, @@ -220,31 +220,31 @@ router.post('/trade', async (req, res) => { tradeType, quote: quoteToken, amount - } - Object.assign(swapResult, tokenSwaps) + }; + Object.assign(swapResult, tokenSwaps); logger.info( `terra.route - ${tradeType}: ${baseToken}-${quoteToken} - Amount: ${amount}` - ) - res.status(200).json(swapResult) + ); + res.status(200).json(swapResult); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let message - let reason + logger.error(req.originalUrl, { message: err }); + let message; + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) - const isAxiosError = err.isAxiosError + : (reason = statusMessages.operation_error); + const isAxiosError = err.isAxiosError; if (isAxiosError) { - reason = err.response.status - message = err.response.statusText + reason = err.response.status; + message = err.response.statusText; } else { - message = err + message = err; } res.status(500).json({ error: reason, message - }) + }); } -}) +}); -module.exports = router +module.exports = router; diff --git a/src/routes/uniswap.route.js b/src/routes/uniswap.route.js index 6201ae0..2803e1c 100644 --- a/src/routes/uniswap.route.js +++ b/src/routes/uniswap.route.js @@ -1,44 +1,44 @@ -import { ethers } from 'ethers' -import express from 'express' +import { ethers } from 'ethers'; +import express from 'express'; -import { getParamData, latency, statusMessages } from '../services/utils' -import { logger } from '../services/logger' -import Ethereum from '../services/eth' -import Uniswap from '../services/uniswap' -import Fees from '../services/fees' +import { getParamData, latency, statusMessages } from '../services/utils'; +import { logger } from '../services/logger'; +import Ethereum from '../services/eth'; +import Uniswap from '../services/uniswap'; +import Fees from '../services/fees'; -require('dotenv').config() +require('dotenv').config(); -const debug = require('debug')('router') +const debug = require('debug')('router'); -const router = express.Router() -const eth = new Ethereum(process.env.ETHEREUM_CHAIN) -const uniswap = new Uniswap(process.env.ETHEREUM_CHAIN) -uniswap.generate_tokens() -setTimeout(uniswap.update_pairs.bind(uniswap), 2000) -const fees = new Fees() +const router = express.Router(); +const eth = new Ethereum(process.env.ETHEREUM_CHAIN); +const uniswap = new Uniswap(process.env.ETHEREUM_CHAIN); +uniswap.generate_tokens(); +setTimeout(uniswap.update_pairs.bind(uniswap), 2000); +const fees = new Fees(); -const swapMoreThanMaxPriceError = 'Price too high' -const swapLessThanMaxPriceError = 'Price too low' +const swapMoreThanMaxPriceError = 'Price too high'; +const swapLessThanMaxPriceError = 'Price too low'; -const estimateGasLimit = () => uniswap.gasLimit +const estimateGasLimit = () => uniswap.gasLimit; const getErrorMessage = (err) => { /* [WIP] Custom error message based-on string match */ - let message = err + let message = err; if (err.includes('failed to meet quorum')) { - message = 'Failed to meet quorum in Uniswap' + message = 'Failed to meet quorum in Uniswap'; } else if (err.includes('Invariant failed: ADDRESSES')) { - message = 'Invariant failed: ADDRESSES' + message = 'Invariant failed: ADDRESSES'; } else if (err.includes('"call revert exception')) { - message = statusMessages.no_pool_available + message = statusMessages.no_pool_available; } else if (err.includes('"trade" is read-only')) { - message = statusMessages.no_pool_available + message = statusMessages.no_pool_available; } - return message -} + return message; +}; router.post('/', async (req, res) => { /* @@ -50,33 +50,33 @@ router.post('/', async (req, res) => { uniswap_router: uniswap.router, connection: true, timestamp: Date.now() - }) -}) + }); +}); router.post('/gas-limit', async (req, res) => { /* POST: /buy-price */ - const gasLimit = estimateGasLimit() + const gasLimit = estimateGasLimit(); try { res.status(200).json({ network: uniswap.network, gasLimit, timestamp: Date.now() - }) + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.get('/start', async (req, res) => { /* @@ -86,23 +86,23 @@ router.get('/start', async (req, res) => { "gasPrice":30 } */ - const initTime = Date.now() - const paramData = getParamData(req.query) - const pairs = JSON.parse(paramData.pairs) - let gasPrice + const initTime = Date.now(); + const paramData = getParamData(req.query); + const pairs = JSON.parse(paramData.pairs); + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } // get token contract address and cache paths for (let pair of pairs) { - pair = pair.split('-') - const baseTokenSymbol = pair[0] - const quoteTokenSymbol = pair[1] - const baseTokenContractInfo = eth.getERC20TokenAddresses(baseTokenSymbol) - const quoteTokenContractInfo = eth.getERC20TokenAddresses(quoteTokenSymbol) + pair = pair.split('-'); + const baseTokenSymbol = pair[0]; + const quoteTokenSymbol = pair[1]; + const baseTokenContractInfo = eth.getERC20TokenAddresses(baseTokenSymbol); + const quoteTokenContractInfo = eth.getERC20TokenAddresses(quoteTokenSymbol); // check for valid token symbols if ( @@ -110,23 +110,25 @@ router.get('/start', async (req, res) => { quoteTokenContractInfo === undefined ) { const undefinedToken = - baseTokenContractInfo === undefined ? baseTokenSymbol : quoteTokenSymbol + baseTokenContractInfo === undefined + ? baseTokenSymbol + : quoteTokenSymbol; res.status(500).json({ error: `Token ${undefinedToken} contract address not found`, message: `Token contract address not found for ${undefinedToken}. Check token list source` - }) - return + }); + return; } await Promise.allSettled([ uniswap.extend_update_pairs([ baseTokenContractInfo.address, quoteTokenContractInfo.address ]) - ]) + ]); } - const gasLimit = estimateGasLimit() - const gasCost = await fees.getGasCost(gasPrice, gasLimit) + const gasLimit = estimateGasLimit(); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); const result = { network: eth.network, @@ -137,9 +139,9 @@ router.get('/start', async (req, res) => { gasPrice, gasLimit, gasCost - } - res.status(200).json(result) -}) + }; + res.status(200).json(result); +}); router.post('/trade', async (req, res) => { /* @@ -154,31 +156,31 @@ router.post('/trade', async (req, res) => { "side":{buy|sell} } */ - const initTime = Date.now() + const initTime = Date.now(); // params: privateKey (required), base (required), quote (required), amount (required), maxPrice (required), gasPrice (required) - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey - const wallet = new ethers.Wallet(privateKey, uniswap.provider) - const amount = paramData.amount + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; + const wallet = new ethers.Wallet(privateKey, uniswap.provider); + const amount = paramData.amount; - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base) - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote) - const baseTokenAddress = baseTokenContractInfo.address - const quoteTokenAddress = quoteTokenContractInfo.address - const side = paramData.side.toUpperCase() + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base); + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote); + const baseTokenAddress = baseTokenContractInfo.address; + const quoteTokenAddress = quoteTokenContractInfo.address; + const side = paramData.side.toUpperCase(); - let limitPrice + let limitPrice; if (paramData.limitPrice) { - limitPrice = parseFloat(paramData.limitPrice) + limitPrice = parseFloat(paramData.limitPrice); } - let gasPrice + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } - const gasLimit = estimateGasLimit() - const gasCost = await fees.getGasCost(gasPrice, gasLimit) + const gasLimit = estimateGasLimit(); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); try { // fetch the optimal pool mix from uniswap @@ -193,11 +195,11 @@ router.post('/trade', async (req, res) => { baseTokenAddress, // tokenIn is base asset quoteTokenAddress, // tokenOut is quote asset amount - ) + ); if (side === 'BUY') { - const price = trade.executionPrice.invert().toSignificant(8) - logger.info(`uniswap.route - Price: ${price.toString()}`) + const price = trade.executionPrice.invert().toSignificant(8); + logger.info(`uniswap.route - Price: ${price.toString()}`); if (!limitPrice || price <= limitPrice) { // pass swaps to exchange-proxy to complete trade const tx = await uniswap.swapExactOut( @@ -205,7 +207,7 @@ router.post('/trade', async (req, res) => { trade, baseTokenAddress, gasPrice - ) + ); // submit response res.status(200).json({ network: uniswap.network, @@ -220,20 +222,20 @@ router.post('/trade', async (req, res) => { gasLimit, gasCost, txHash: tx.hash - }) + }); } else { res.status(200).json({ error: swapMoreThanMaxPriceError, message: `Swap price ${price} exceeds limitPrice ${limitPrice}` - }) + }); logger.info( `uniswap.route - Swap price ${price} exceeds limitPrice ${limitPrice}` - ) + ); } } else { // sell - const price = trade.executionPrice.toSignificant(8) - logger.info(`Price: ${price.toString()}`) + const price = trade.executionPrice.toSignificant(8); + logger.info(`Price: ${price.toString()}`); if (!limitPrice || price >= limitPrice) { // pass swaps to exchange-proxy to complete trade const tx = await uniswap.swapExactIn( @@ -241,7 +243,7 @@ router.post('/trade', async (req, res) => { trade, baseTokenAddress, gasPrice - ) + ); // submit response res.status(200).json({ network: uniswap.network, @@ -256,29 +258,29 @@ router.post('/trade', async (req, res) => { gasLimit, gasCost, txHash: tx.hash - }) + }); } else { res.status(200).json({ error: swapLessThanMaxPriceError, message: `Swap price ${price} lower than limitPrice ${limitPrice}` - }) + }); logger.info( `uniswap.route - Swap price ${price} lower than limitPrice ${limitPrice}` - ) + ); } } } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/price', async (req, res) => { /* @@ -289,24 +291,24 @@ router.post('/price', async (req, res) => { "amount":1 } */ - const initTime = Date.now() + const initTime = Date.now(); // params: base (required), quote (required), amount (required) - const paramData = getParamData(req.body) - const amount = paramData.amount + const paramData = getParamData(req.body); + const amount = paramData.amount; - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base) - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote) - const baseTokenAddress = baseTokenContractInfo.address - const quoteTokenAddress = quoteTokenContractInfo.address - const side = paramData.side.toUpperCase() - let gasPrice + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base); + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote); + const baseTokenAddress = baseTokenContractInfo.address; + const quoteTokenAddress = quoteTokenContractInfo.address; + const side = paramData.side.toUpperCase(); + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } - const gasLimit = estimateGasLimit() - const gasCost = await fees.getGasCost(gasPrice, gasLimit) + const gasLimit = estimateGasLimit(); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); try { // fetch the optimal pool mix from uniswap @@ -321,17 +323,17 @@ router.post('/price', async (req, res) => { baseTokenAddress, // tokenIn is base asset quoteTokenAddress, // tokenOut is quote asset amount - ) + ); if (trade !== null && expectedAmount !== null) { const price = side === 'BUY' ? trade.executionPrice.invert().toSignificant(8) - : trade.executionPrice.toSignificant(8) + : trade.executionPrice.toSignificant(8); - const tradeAmount = parseFloat(amount) - const expectedTradeAmount = parseFloat(expectedAmount.toSignificant(8)) - const tradePrice = parseFloat(price) + const tradeAmount = parseFloat(amount); + const expectedTradeAmount = parseFloat(expectedAmount.toSignificant(8)); + const tradePrice = parseFloat(price); const result = { network: uniswap.network, @@ -346,44 +348,44 @@ router.post('/price', async (req, res) => { gasLimit, gasCost, trade - } + }; debug( `Price ${side} ${baseTokenContractInfo.symbol}-${quoteTokenContractInfo.symbol} | amount:${amount} (rate:${tradePrice}) - gasPrice:${gasPrice} gasLimit:${gasLimit} estimated fee:${gasCost} ETH` - ) - res.status(200).json(result) + ); + res.status(200).json(result); } else { // no pool available res.status(200).json({ info: statusMessages.no_pool_available, message: '' - }) + }); } } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - let errCode = 500 + logger.error(req.originalUrl, { message: err }); + let reason; + let errCode = 500; if (Object.keys(err).includes('isInsufficientReservesError')) { - errCode = 200 - reason = `${statusMessages.insufficient_reserves} in ${side} at Uniswap` + errCode = 200; + reason = `${statusMessages.insufficient_reserves} in ${side} at Uniswap`; } else if (Object.getOwnPropertyNames(err).includes('message')) { - reason = getErrorMessage(err.message) + reason = getErrorMessage(err.message); if (reason === statusMessages.no_pool_available) { - errCode = 200 + errCode = 200; res.status(errCode).json({ info: reason, message: err - }) + }); } } else { err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); } res.status(errCode).json({ error: reason, message: err - }) + }); } -}) +}); -export default router +export default router; diff --git a/src/routes/uniswap_v3.route.js b/src/routes/uniswap_v3.route.js index c184f40..9df8e79 100644 --- a/src/routes/uniswap_v3.route.js +++ b/src/routes/uniswap_v3.route.js @@ -1,48 +1,48 @@ -import { ethers } from 'ethers' -import express from 'express' +import { ethers } from 'ethers'; +import express from 'express'; import { getNonceManager, getParamData, latency, statusMessages -} from '../services/utils' +} from '../services/utils'; -import { logger } from '../services/logger' -import Ethereum from '../services/eth' -import UniswapV3 from '../services/uniswap_v3' -import Fees from '../services/fees' +import { logger } from '../services/logger'; +import Ethereum from '../services/eth'; +import UniswapV3 from '../services/uniswap_v3'; +import Fees from '../services/fees'; -require('dotenv').config() +require('dotenv').config(); -const debug = require('debug')('router') +const debug = require('debug')('router'); -const router = express.Router() -const eth = new Ethereum(process.env.ETHEREUM_CHAIN) -const uniswap = new UniswapV3(process.env.ETHEREUM_CHAIN) +const router = express.Router(); +const eth = new Ethereum(process.env.ETHEREUM_CHAIN); +const uniswap = new UniswapV3(process.env.ETHEREUM_CHAIN); -const fees = new Fees() +const fees = new Fees(); // const swapMoreThanMaxPriceError = 'Price too high' // const swapLessThanMaxPriceError = 'Price too low' -const estimateGasLimit = () => uniswap.gasLimit +const estimateGasLimit = () => uniswap.gasLimit; const getErrorMessage = (err) => { /* [WIP] Custom error message based-on string match */ - let message = err + let message = err; if (err.includes('failed to meet quorum')) { - message = 'Failed to meet quorum in Uniswap' + message = 'Failed to meet quorum in Uniswap'; } else if (err.includes('Invariant failed: ADDRESSES')) { - message = 'Invariant failed: ADDRESSES' + message = 'Invariant failed: ADDRESSES'; } else if (err.includes('"call revert exception')) { - message = statusMessages.no_pool_available + message = statusMessages.no_pool_available; } else if (err.includes('"trade" is read-only')) { - message = statusMessages.no_pool_available + message = statusMessages.no_pool_available; } - return message -} + return message; +}; router.post('/', async (req, res) => { /* @@ -54,33 +54,33 @@ router.post('/', async (req, res) => { uniswap_router: uniswap.router, connection: true, timestamp: Date.now() - }) -}) + }); +}); router.post('/gas-limit', async (req, res) => { /* POST: /gas-limit */ - const gasLimit = estimateGasLimit() + const gasLimit = estimateGasLimit(); try { res.status(200).json({ network: uniswap.network, gasLimit, timestamp: Date.now() - }) + }); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/result', async (req, res) => { /* @@ -89,18 +89,18 @@ router.post('/result', async (req, res) => { "logs":"[...]" } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const logs = JSON.parse(paramData.logs) + const initTime = Date.now(); + const paramData = getParamData(req.body); + const logs = JSON.parse(paramData.logs); const result = { network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), info: uniswap.abiDecoder.decodeLogs(logs) - } - res.status(200).json(result) -}) + }; + res.status(200).json(result); +}); router.post('/trade', async (req, res) => { /* @@ -116,36 +116,36 @@ router.post('/trade', async (req, res) => { "side":{buy|sell} } */ - const initTime = Date.now() + const initTime = Date.now(); // params: privateKey (required), base (required), quote (required), amount (required), maxPrice (required), gasPrice (required) - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; const wallet = await getNonceManager( new ethers.Wallet(privateKey, uniswap.provider) - ) - const amount = paramData.amount + ); + const amount = paramData.amount; - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base) - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote) - const baseTokenAddress = baseTokenContractInfo.address - const quoteTokenAddress = quoteTokenContractInfo.address - const side = paramData.side.toUpperCase() - const tier = paramData.tier.toUpperCase() + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base); + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote); + const baseTokenAddress = baseTokenContractInfo.address; + const quoteTokenAddress = quoteTokenContractInfo.address; + const side = paramData.side.toUpperCase(); + const tier = paramData.tier.toUpperCase(); - let limitPrice + let limitPrice; if (paramData.limitPrice) { - limitPrice = parseFloat(paramData.limitPrice) + limitPrice = parseFloat(paramData.limitPrice); } else { - limitPrice = 0 + limitPrice = 0; } - let gasPrice + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } - const gasLimit = estimateGasLimit() - const gasCost = await fees.getGasCost(gasPrice, gasLimit) + const gasLimit = estimateGasLimit(); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); try { if (side === 'BUY') { @@ -157,7 +157,7 @@ router.post('/trade', async (req, res) => { limitPrice, tier, gasPrice - ) + ); // submit response res.status(200).json({ network: uniswap.network, @@ -172,7 +172,7 @@ router.post('/trade', async (req, res) => { gasLimit, gasCost, txHash: tx.hash - }) + }); } else { // sell const tx = await uniswap.swapExactIn( @@ -183,7 +183,7 @@ router.post('/trade', async (req, res) => { limitPrice, tier, gasPrice - ) + ); // submit response res.status(200).json({ @@ -199,20 +199,20 @@ router.post('/trade', async (req, res) => { gasLimit, gasCost, txHash: tx.hash - }) + }); } } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason + logger.error(req.originalUrl, { message: err }); + let reason; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(500).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/price', async (req, res) => { /* @@ -222,27 +222,27 @@ router.post('/price', async (req, res) => { "base":"DAI" } */ - const initTime = Date.now() + const initTime = Date.now(); // params: base (required), quote (required), amount (required) - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; const wallet = await getNonceManager( new ethers.Wallet(privateKey, uniswap.provider) - ) + ); - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base) - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote) - const baseTokenAddress = baseTokenContractInfo.address - const quoteTokenAddress = quoteTokenContractInfo.address + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.base); + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.quote); + const baseTokenAddress = baseTokenContractInfo.address; + const quoteTokenAddress = quoteTokenContractInfo.address; - let gasPrice + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } - const gasLimit = estimateGasLimit() - const gasCost = await fees.getGasCost(gasPrice, gasLimit) + const gasLimit = estimateGasLimit(); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); try { // fetch pools for all tiers @@ -250,7 +250,7 @@ router.post('/price', async (req, res) => { wallet, baseTokenAddress, quoteTokenAddress - ) + ); const result = { network: uniswap.network, @@ -262,42 +262,42 @@ router.post('/price', async (req, res) => { gasPrice, gasLimit, gasCost - } + }; debug( `Mid Price ${baseTokenContractInfo.symbol}-${ quoteTokenContractInfo.symbol } | (rate:${JSON.stringify( prices )}) - gasPrice:${gasPrice} gasLimit:${gasLimit} estimated fee:${gasCost} ETH` - ) - res.status(200).json(result) + ); + res.status(200).json(result); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - let errCode = 500 + logger.error(req.originalUrl, { message: err }); + let reason; + let errCode = 500; if (Object.keys(err).includes('isInsufficientReservesError')) { - errCode = 200 - reason = `${statusMessages.insufficient_reserves} at Uniswap` + errCode = 200; + reason = `${statusMessages.insufficient_reserves} at Uniswap`; } else if (Object.getOwnPropertyNames(err).includes('message')) { - reason = getErrorMessage(err.message) + reason = getErrorMessage(err.message); if (reason === statusMessages.no_pool_available) { - errCode = 200 + errCode = 200; res.status(errCode).json({ info: reason, message: err - }) + }); } } else { err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); } res.status(errCode).json({ error: reason, message: err - }) + }); } -}) +}); // LP section @@ -308,34 +308,34 @@ router.post('/position', async (req, res) => { "tokenId":"tokenId" } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; const wallet = await getNonceManager( new ethers.Wallet(privateKey, uniswap.provider) - ) - const tokenId = paramData.tokenId + ); + const tokenId = paramData.tokenId; try { // fetch position data - const positionData = await uniswap.getPosition(wallet, tokenId) + const positionData = await uniswap.getPosition(wallet, tokenId); const result = { network: uniswap.network, timestamp: initTime, latency: latency(initTime, Date.now()), position: positionData - } - debug(`Position data: ${positionData} `) - res.status(200).json(result) + }; + debug(`Position data: ${positionData} `); + res.status(200).json(result); } catch (err) { - logger.error(req.originalUrl, { message: err }) + logger.error(req.originalUrl, { message: err }); res.status(500).json({ info: statusMessages.operation_error, position: {} - }) + }); } -}) +}); router.post('/add-position', async (req, res) => { /* @@ -350,29 +350,29 @@ router.post('/add-position', async (req, res) => { "amount1": amount1 } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; const wallet = await getNonceManager( new ethers.Wallet(privateKey, uniswap.provider) - ) + ); - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.token0) - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.token1) - const fee = paramData.fee - const lowerPrice = parseFloat(paramData.lowerPrice) - const upperPrice = parseFloat(paramData.upperPrice) - const amount0 = paramData.amount0 - const amount1 = paramData.amount1 + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.token0); + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.token1); + const fee = paramData.fee; + const lowerPrice = parseFloat(paramData.lowerPrice); + const upperPrice = parseFloat(paramData.upperPrice); + const amount0 = paramData.amount0; + const amount1 = paramData.amount1; - let gasPrice + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } - const gasLimit = estimateGasLimit() - const gasCost = await fees.getGasCost(gasPrice, gasLimit) + const gasLimit = estimateGasLimit(); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); try { // add position to pool @@ -385,7 +385,7 @@ router.post('/add-position', async (req, res) => { fee, lowerPrice, upperPrice - ) + ); const result = { network: uniswap.network, @@ -402,17 +402,17 @@ router.post('/add-position', async (req, res) => { gasPrice, gasLimit, gasCost - } - debug(`New Position: ${newPosition.hash}`) - res.status(200).json(result) + }; + debug(`New Position: ${newPosition.hash}`); + res.status(200).json(result); } catch (err) { - logger.error(req.originalUrl, { message: err }) + logger.error(req.originalUrl, { message: err }); res.status(200).json({ info: statusMessages.operation_error, message: err - }) + }); } -}) +}); router.post('/remove-position', async (req, res) => { /* @@ -421,25 +421,25 @@ router.post('/remove-position', async (req, res) => { "tokenId":"12" } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; const wallet = await getNonceManager( new ethers.Wallet(privateKey, uniswap.provider) - ) - const tokenId = paramData.tokenId + ); + const tokenId = paramData.tokenId; - let gasPrice + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } - const gasLimit = estimateGasLimit() - const gasCost = await fees.getGasCost(gasPrice, gasLimit) + const gasLimit = estimateGasLimit(); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); try { - const removelp = await uniswap.removePosition(wallet, tokenId) + const removelp = await uniswap.removePosition(wallet, tokenId); const result = { network: uniswap.network, @@ -449,22 +449,22 @@ router.post('/remove-position', async (req, res) => { gasPrice, gasLimit, gasCost - } - debug(`Remove lp: ${removelp.hash}`) - res.status(200).json(result) + }; + debug(`Remove lp: ${removelp.hash}`); + res.status(200).json(result); } catch (err) { - logger.error(req.originalUrl, { message: err }) - let reason - const errCode = 500 + logger.error(req.originalUrl, { message: err }); + let reason; + const errCode = 500; err.reason ? (reason = err.reason) - : (reason = statusMessages.operation_error) + : (reason = statusMessages.operation_error); res.status(errCode).json({ error: reason, message: err - }) + }); } -}) +}); router.post('/replace-position', async (req, res) => { /* @@ -480,29 +480,29 @@ router.post('/replace-position', async (req, res) => { "amount1": amount1 } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; const wallet = await getNonceManager( new ethers.Wallet(privateKey, uniswap.provider) - ) - const tokenId = paramData.tokenId - const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.token0) - const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.token1) - const fee = paramData.fee - const lowerPrice = parseFloat(paramData.lowerPrice) - const upperPrice = parseFloat(paramData.upperPrice) - const amount0 = paramData.amount0 - const amount1 = paramData.amount1 - - let gasPrice + ); + const tokenId = paramData.tokenId; + const baseTokenContractInfo = eth.getERC20TokenAddresses(paramData.token0); + const quoteTokenContractInfo = eth.getERC20TokenAddresses(paramData.token1); + const fee = paramData.fee; + const lowerPrice = parseFloat(paramData.lowerPrice); + const upperPrice = parseFloat(paramData.upperPrice); + const amount0 = paramData.amount0; + const amount1 = paramData.amount1; + + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } - const gasLimit = estimateGasLimit() - const gasCost = await fees.getGasCost(gasPrice, gasLimit) + const gasLimit = estimateGasLimit(); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); try { // const position = await uniswap.getPosition(wallet, tokenId) @@ -518,7 +518,7 @@ router.post('/replace-position', async (req, res) => { fee, lowerPrice, upperPrice - ) + ); const result = { network: uniswap.network, @@ -531,17 +531,17 @@ router.post('/replace-position', async (req, res) => { gasPrice, gasLimit, gasCost - } - debug(`Position change ${positionChange.hash}`) - res.status(200).json(result) + }; + debug(`Position change ${positionChange.hash}`); + res.status(200).json(result); } catch (err) { - logger.error(req.originalUrl, { message: err }) + logger.error(req.originalUrl, { message: err }); res.status(200).json({ info: statusMessages.operation_error, message: err - }) + }); } -}) +}); router.post('/collect-fees', async (req, res) => { /* @@ -552,26 +552,26 @@ router.post('/collect-fees', async (req, res) => { "amount1": amount1 } */ - const initTime = Date.now() - const paramData = getParamData(req.body) - const privateKey = paramData.privateKey + const initTime = Date.now(); + const paramData = getParamData(req.body); + const privateKey = paramData.privateKey; const wallet = await getNonceManager( new ethers.Wallet(privateKey, uniswap.provider) - ) - const tokenId = paramData.tokenId + ); + const tokenId = paramData.tokenId; - let gasPrice + let gasPrice; if (paramData.gasPrice) { - gasPrice = parseFloat(paramData.gasPrice) + gasPrice = parseFloat(paramData.gasPrice); } else { - gasPrice = fees.ethGasPrice + gasPrice = fees.ethGasPrice; } - const gasLimit = estimateGasLimit() - const gasCost = await fees.getGasCost(gasPrice, gasLimit) + const gasLimit = estimateGasLimit(); + const gasCost = await fees.getGasCost(gasPrice, gasLimit); try { // withdraw fees - const collect = await uniswap.collectFees(wallet, tokenId) + const collect = await uniswap.collectFees(wallet, tokenId); const result = { network: uniswap.network, @@ -582,16 +582,16 @@ router.post('/collect-fees', async (req, res) => { gasPrice, gasLimit, gasCost - } - debug(`Fees: ${collect.hash}`) - res.status(200).json(result) + }; + debug(`Fees: ${collect.hash}`); + res.status(200).json(result); } catch (err) { - logger.error(req.originalUrl, { message: err }) + logger.error(req.originalUrl, { message: err }); res.status(200).json({ info: statusMessages.operation_error, message: err - }) + }); } -}) +}); -export default router +export default router; diff --git a/src/services/access.js b/src/services/access.js index d917e80..cf374b9 100644 --- a/src/services/access.js +++ b/src/services/access.js @@ -2,23 +2,23 @@ middleware for validating mutual authentication access */ -import { logger } from './logger' -import { statusMessages } from './utils' +import { logger } from './logger'; +import { statusMessages } from './utils'; export const validateAccess = (req, res, next) => { - const cert = req.connection.getPeerCertificate() + const cert = req.connection.getPeerCertificate(); if (req.client.authorized) { - const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress - const method = req.method - const url = req.url - const requestInfo = `Request from IP: ${ip} ${method} ${url}` - console.log(requestInfo) - next() + const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; + const method = req.method; + const url = req.url; + const requestInfo = `Request from IP: ${ip} ${method} ${url}`; + console.log(requestInfo); + next(); } else if (cert.subject) { - logger.error(statusMessages.ssl_cert_invalid) - res.status(403).send({ error: statusMessages.ssl_cert_invalid }) + logger.error(statusMessages.ssl_cert_invalid); + res.status(403).send({ error: statusMessages.ssl_cert_invalid }); } else { - logger.error(statusMessages.ssl_cert_required) - res.status(401).send({ error: statusMessages.ssl_cert_required }) + logger.error(statusMessages.ssl_cert_required); + res.status(401).send({ error: statusMessages.ssl_cert_required }); } -} +}; diff --git a/src/services/balancer.js b/src/services/balancer.js index aa3715c..c846e90 100644 --- a/src/services/balancer.js +++ b/src/services/balancer.js @@ -1,66 +1,67 @@ -import { logger } from './logger' +import { logger } from './logger'; -const debug = require('debug')('router') -require('dotenv').config() // DO NOT REMOVE. needed to configure REACT_APP_SUBGRAPH_URL used by @balancer-labs/sor -const sor = require('@balancer-labs/sor') -const BigNumber = require('bignumber.js') -const ethers = require('ethers') -const proxyArtifact = require('../static/ExchangeProxy.json') +const debug = require('debug')('router'); +require('dotenv').config(); // DO NOT REMOVE. needed to configure REACT_APP_SUBGRAPH_URL used by @balancer-labs/sor +const sor = require('@balancer-labs/sor'); +const BigNumber = require('bignumber.js'); +const ethers = require('ethers'); +const proxyArtifact = require('../static/ExchangeProxy.json'); // constants -const MULTI = '0xeefba1e63905ef1d7acba5a8513c70307c1ce441' -const MULTI_KOVAN = ' 0x2cc8688C5f75E365aaEEb4ea8D6a480405A48D2A' -const MAX_UINT = ethers.constants.MaxUint256 -const GAS_BASE = process.env.BALANCER_GAS_BASE || 200688 -const GAS_PER_SWAP = process.env.BALANCER_GAS_PER_SWAP || 100000 +const MULTI = '0xeefba1e63905ef1d7acba5a8513c70307c1ce441'; +const MULTI_KOVAN = ' 0x2cc8688C5f75E365aaEEb4ea8D6a480405A48D2A'; +const MAX_UINT = ethers.constants.MaxUint256; +const GAS_BASE = process.env.BALANCER_GAS_BASE || 200688; +const GAS_PER_SWAP = process.env.BALANCER_GAS_PER_SWAP || 100000; export default class Balancer { constructor(network = 'kovan') { - const providerUrl = process.env.ETHEREUM_RPC_URL - this.network = process.env.ETHEREUM_CHAIN - this.provider = new ethers.providers.JsonRpcProvider(providerUrl) - this.subgraphUrl = process.env.REACT_APP_SUBGRAPH_URL - this.gasBase = GAS_BASE - this.gasPerSwap = GAS_PER_SWAP - this.maxSwaps = process.env.BALANCER_MAX_SWAPS || 4 - this.exchangeProxy = process.env.EXCHANGE_PROXY - this.cachedPools = [] + const providerUrl = process.env.ETHEREUM_RPC_URL; + this.network = process.env.ETHEREUM_CHAIN; + this.provider = new ethers.providers.JsonRpcProvider(providerUrl); + this.subgraphUrl = process.env.REACT_APP_SUBGRAPH_URL; + this.gasBase = GAS_BASE; + this.gasPerSwap = GAS_PER_SWAP; + this.maxSwaps = process.env.BALANCER_MAX_SWAPS || 4; + this.exchangeProxy = process.env.EXCHANGE_PROXY; + this.cachedPools = []; switch (network) { case 'mainnet': - this.multiCall = MULTI - break + this.multiCall = MULTI; + break; case 'kovan': - this.multiCall = MULTI_KOVAN - break - default: - const err = `Invalid network ${network}` - logger.error(err) - throw Error(err) + this.multiCall = MULTI_KOVAN; + break; + default: { + const err = `Invalid network ${network}`; + logger.error(err); + throw Error(err); + } } } async fetchPool(tokenIn, tokenOut) { - const pools = await sor.getPoolsWithTokens(tokenIn, tokenOut) - this.cachedPools[tokenIn + tokenOut] = pools + const pools = await sor.getPoolsWithTokens(tokenIn, tokenOut); + this.cachedPools[tokenIn + tokenOut] = pools; if (pools.pools.length === 0) { debug('>>> No pools contain the tokens provided.', { message: this.network - }) - return {} + }); + return {}; } debug(`>>> ${pools.pools.length} Pools Retrieved.`, { message: this.network - }) + }); } async getCachedPools(tokenIn, tokenOut) { - const cachePools = this.cachedPools[tokenIn + tokenOut].pools + const cachePools = this.cachedPools[tokenIn + tokenOut].pools; debug(`>>> get cached Pools. ${tokenIn + tokenOut}`, { message: `total pools: ${cachePools.length}` - }) - return cachePools + }); + return cachePools; } async priceSwapIn( @@ -72,10 +73,10 @@ export default class Balancer { // Fetch all the pools that contain the tokens provided try { // Get current on-chain data about the fetched pools - await this.fetchPool(tokenIn, tokenOut) + await this.fetchPool(tokenIn, tokenOut); - let poolData - const cachedPools = await this.getCachedPools(tokenIn, tokenOut) + let poolData; + const cachedPools = await this.getCachedPools(tokenIn, tokenOut); if (this.network === 'mainnet') { poolData = await sor.parsePoolDataOnChain( cachedPools, @@ -83,10 +84,10 @@ export default class Balancer { tokenOut, this.multiCall, this.provider - ) + ); } else { // Kovan multicall throws an ENS error - poolData = await sor.parsePoolData(cachedPools, tokenIn, tokenOut) + poolData = await sor.parsePoolData(cachedPools, tokenIn, tokenOut); } // Parse the pools and pass them to smart order outer to get the swaps needed @@ -96,14 +97,18 @@ export default class Balancer { tokenInAmount, // targetInputAmount: BigNumber new BigNumber(maxSwaps.toString()), // maxBalancers: number 0 // costOutputToken: BigNumber - ) + ); - const swapsFormatted = sor.formatSwapsExactAmountIn(sorSwaps, MAX_UINT, 0) - const expectedAmount = sor.calcTotalOutput(swapsFormatted, poolData) - debug(`Expected Out: ${expectedAmount.toString()} (${tokenOut})`) + const swapsFormatted = sor.formatSwapsExactAmountIn( + sorSwaps, + MAX_UINT, + 0 + ); + const expectedAmount = sor.calcTotalOutput(swapsFormatted, poolData); + debug(`Expected Out: ${expectedAmount.toString()} (${tokenOut})`); // Create correct swap format for new proxy - const swaps = [] + const swaps = []; for (let i = 0; i < swapsFormatted.length; i++) { const swap = { pool: swapsFormatted[i].pool, @@ -112,15 +117,15 @@ export default class Balancer { swapAmount: swapsFormatted[i].tokenInParam, limitReturnAmount: swapsFormatted[i].tokenOutParam, maxPrice: swapsFormatted[i].maxPrice.toString() - } - swaps.push(swap) + }; + swaps.push(swap); } - return { swaps, expectedAmount } + return { swaps, expectedAmount }; } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error in swapExactOut') - return reason + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error in swapExactOut'); + return reason; } } @@ -133,10 +138,10 @@ export default class Balancer { // Fetch all the pools that contain the tokens provided try { // Get current on-chain data about the fetched pools - await this.fetchPool(tokenIn, tokenOut) + await this.fetchPool(tokenIn, tokenOut); - let poolData - const cachedPools = await this.getCachedPools(tokenIn, tokenOut) + let poolData; + const cachedPools = await this.getCachedPools(tokenIn, tokenOut); if (this.network === 'mainnet') { poolData = await sor.parsePoolDataOnChain( cachedPools, @@ -144,10 +149,10 @@ export default class Balancer { tokenOut, this.multiCall, this.provider - ) + ); } else { // Kovan multicall throws an ENS error - poolData = await sor.parsePoolData(cachedPools, tokenIn, tokenOut) + poolData = await sor.parsePoolData(cachedPools, tokenIn, tokenOut); } // Parse the pools and pass them to smart order outer to get the swaps needed @@ -157,17 +162,17 @@ export default class Balancer { tokenOutAmount, // targetInputAmount: BigNumber new BigNumber(maxSwaps.toString()), // maxBalancers: number 0 // costOutputToken: BigNumber - ) + ); const swapsFormatted = sor.formatSwapsExactAmountOut( sorSwaps, MAX_UINT, MAX_UINT - ) - const expectedAmount = sor.calcTotalInput(swapsFormatted, poolData) - debug(`Expected In: ${expectedAmount.toString()} (${tokenIn})`) + ); + const expectedAmount = sor.calcTotalInput(swapsFormatted, poolData); + debug(`Expected In: ${expectedAmount.toString()} (${tokenIn})`); // Create correct swap format for new proxy - const swaps = [] + const swaps = []; for (let i = 0; i < swapsFormatted.length; i++) { const swap = { pool: swapsFormatted[i].pool, @@ -176,15 +181,15 @@ export default class Balancer { swapAmount: swapsFormatted[i].tokenOutParam, limitReturnAmount: swapsFormatted[i].tokenInParam, maxPrice: swapsFormatted[i].maxPrice.toString() - } - swaps.push(swap) + }; + swaps.push(swap); } - return { swaps, expectedAmount } + return { swaps, expectedAmount }; } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error in swapExactOut') - return reason + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error in swapExactOut'); + return reason; } } @@ -197,13 +202,13 @@ export default class Balancer { minAmountOut, gasPrice ) { - debug(`Number of swaps: ${swaps.length}`) + debug(`Number of swaps: ${swaps.length}`); try { const contract = new ethers.Contract( this.exchangeProxy, proxyArtifact.abi, wallet - ) + ); const tx = await contract.batchSwapExactIn( swaps, tokenIn, @@ -214,25 +219,25 @@ export default class Balancer { gasPrice: gasPrice * 1e9, gasLimit: GAS_BASE + swaps.length * GAS_PER_SWAP } - ) - debug(`Tx Hash: ${tx.hash}`) - return tx + ); + debug(`Tx Hash: ${tx.hash}`); + return tx; } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error in swapExactIn') - return reason + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error in swapExactIn'); + return reason; } } async swapExactOut(wallet, swaps, tokenIn, tokenOut, expectedIn, gasPrice) { - debug(`Number of swaps: ${swaps.length}`) + debug(`Number of swaps: ${swaps.length}`); try { const contract = new ethers.Contract( this.exchangeProxy, proxyArtifact.abi, wallet - ) + ); const tx = await contract.batchSwapExactOut( swaps, tokenIn, @@ -242,14 +247,14 @@ export default class Balancer { gasPrice: gasPrice * 1e9, gasLimit: GAS_BASE + swaps.length * GAS_PER_SWAP } - ) - debug(`Tx Hash: ${tx.hash}`) - return tx + ); + debug(`Tx Hash: ${tx.hash}`); + return tx; } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error in swapExactOut') - return reason + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error in swapExactOut'); + return reason; } } } diff --git a/src/services/eth.js b/src/services/eth.js index 68d2ae9..13d292b 100644 --- a/src/services/eth.js +++ b/src/services/eth.js @@ -1,35 +1,37 @@ -import axios from 'axios' -import { logger } from './logger' +import axios from 'axios'; +import { logger } from './logger'; -require('dotenv').config() -const fs = require('fs') -const ethers = require('ethers') -const abi = require('../static/abi') +require('dotenv').config(); +const fs = require('fs'); +const ethers = require('ethers'); +const abi = require('../static/abi'); // constants -const APPROVAL_GAS_LIMIT = process.env.ETH_APPROVAL_GAS_LIMIT || 50000 +const APPROVAL_GAS_LIMIT = process.env.ETH_APPROVAL_GAS_LIMIT || 50000; export default class Ethereum { constructor(network = 'mainnet') { // network defaults to kovan - const providerUrl = process.env.ETHEREUM_RPC_URL - this.provider = new ethers.providers.JsonRpcProvider(providerUrl) - this.erc20TokenListURL = process.env.ETHEREUM_TOKEN_LIST_URL - this.network = network + const providerUrl = process.env.ETHEREUM_RPC_URL; + this.provider = new ethers.providers.JsonRpcProvider(providerUrl); + this.erc20TokenListURL = process.env.ETHEREUM_TOKEN_LIST_URL; + this.network = network; // update token list - this.getERC20TokenList() // erc20TokenList + this.getERC20TokenList(); // erc20TokenList } // get ETH balance async getETHBalance(wallet) { try { - const balance = await wallet.getBalance() - return balance / (1e18).toString() + const balance = await wallet.getBalance(); + return balance / (1e18).toString(); } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error ETH balance lookup') - return reason + logger.error(err); + let reason; + err.reason + ? (reason = err.reason) + : (reason = 'error ETH balance lookup'); + return reason; } } @@ -40,15 +42,15 @@ export default class Ethereum { tokenAddress, abi.ERC20Abi, this.provider - ) + ); try { - const balance = await contract.balanceOf(wallet.address) - return balance / (10 ** decimals).toString() + const balance = await contract.balanceOf(wallet.address); + return balance / (10 ** decimals).toString(); } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error balance lookup') - return reason + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error balance lookup'); + return reason; } } @@ -59,15 +61,15 @@ export default class Ethereum { tokenAddress, abi.ERC20Abi, this.provider - ) + ); try { - const allowance = await contract.allowance(wallet.address, spender) - return allowance / (10 ** decimals).toString() + const allowance = await contract.allowance(wallet.address, spender); + return allowance / (10 ** decimals).toString(); } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error allowance lookup') - return reason + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error allowance lookup'); + return reason; } } @@ -82,18 +84,18 @@ export default class Ethereum { ) { try { // fixate gas limit to prevent overwriting - const approvalGasLimit = APPROVAL_GAS_LIMIT + const approvalGasLimit = APPROVAL_GAS_LIMIT; // instantiate a contract and pass in wallet, which act on behalf of that signer - const contract = new ethers.Contract(tokenAddress, abi.ERC20Abi, wallet) + const contract = new ethers.Contract(tokenAddress, abi.ERC20Abi, wallet); return await contract.approve(spender, amount, { gasPrice: gasPrice * 1e9, gasLimit: approvalGasLimit - }) + }); } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error approval') - return reason + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error approval'); + return reason; } } @@ -102,14 +104,14 @@ export default class Ethereum { try { this.provider.getGasPrice().then((gas) => { // gasPrice is a BigNumber; convert it to a decimal string - const gasPrice = gas.toString() - return gasPrice - }) + const gasPrice = gas.toString(); + return gasPrice; + }); } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error gas lookup') - return reason + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error gas lookup'); + return reason; } } @@ -126,59 +128,59 @@ export default class Ethereum { tokenAddress, abi.KovanWETHAbi, wallet - ) + ); return await contract.deposit({ value: amount, gasPrice: gasPrice * 1e9, gasLimit - }) + }); } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error deposit') - return reason + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error deposit'); + return reason; } } // get ERC20 Token List async getERC20TokenList() { - let tokenListSource + let tokenListSource; try { if (this.network === 'kovan') { - tokenListSource = 'src/static/erc20_tokens_kovan.json' - this.erc20TokenList = JSON.parse(fs.readFileSync(tokenListSource)) + tokenListSource = 'src/static/erc20_tokens_kovan.json'; + this.erc20TokenList = JSON.parse(fs.readFileSync(tokenListSource)); } else if (this.network === 'mainnet') { - tokenListSource = this.erc20TokenListURL + tokenListSource = this.erc20TokenListURL; if (tokenListSource === undefined || tokenListSource === null) { - const errMessage = 'Token List source not found' - logger.error('ERC20 Token List Error', { message: errMessage }) - console.log('eth - Error: ', errMessage) + const errMessage = 'Token List source not found'; + logger.error('ERC20 Token List Error', { message: errMessage }); + console.log('eth - Error: ', errMessage); } if ( this.erc20TokenList === undefined || this.erc20TokenList === null || this.erc20TokenList === {} ) { - const response = await axios.get(tokenListSource) + const response = await axios.get(tokenListSource); if (response.status === 200 && response.data) { - this.erc20TokenList = response.data + this.erc20TokenList = response.data; } } } else { - throw Error(`Invalid network ${this.network}`) + throw Error(`Invalid network ${this.network}`); } console.log( 'get ERC20 Token List', this.network, 'source', tokenListSource - ) + ); } catch (err) { - console.log(err) - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error ERC 20 Token List') - return reason + console.log(err); + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error ERC 20 Token List'); + return reason; } } @@ -186,14 +188,14 @@ export default class Ethereum { getERC20TokenAddresses(tokenSymbol) { const tokenContractAddress = this.erc20TokenList.tokens.filter( (obj) => obj.symbol === tokenSymbol.toUpperCase() - ) - return tokenContractAddress[0] + ); + return tokenContractAddress[0]; } getERC20TokenByAddress(tokenAddress) { const tokenContract = this.erc20TokenList.tokens.filter( (obj) => obj.address.toUpperCase() === tokenAddress.toUpperCase() - ) - return tokenContract[0] + ); + return tokenContract[0]; } } diff --git a/src/services/fees.js b/src/services/fees.js index 4a3ab6e..3f7ab37 100644 --- a/src/services/fees.js +++ b/src/services/fees.js @@ -1,25 +1,25 @@ -import axios from 'axios' -import BigNumber from 'bignumber.js' -import { logger } from './logger' +import axios from 'axios'; +import BigNumber from 'bignumber.js'; +import { logger } from './logger'; -require('dotenv').config() +require('dotenv').config(); // constants -const ethGasStationHost = 'https://ethgasstation.info' -const ethGasStationEnabled = process.env.ENABLE_ETH_GAS_STATION || false -const ethGasStationApiKey = process.env.ETH_GAS_STATION_API_KEY -const ethManualGasPrice = parseInt(process.env.MANUAL_GAS_PRICE) -const ethGasStationURL = `${ethGasStationHost}/api/ethgasAPI.json?api-key=${ethGasStationApiKey}` -const defaultRefreshInterval = 120 -const denom = BigNumber('1e+9') +const ethGasStationHost = 'https://ethgasstation.info'; +const ethGasStationEnabled = process.env.ENABLE_ETH_GAS_STATION || false; +const ethGasStationApiKey = process.env.ETH_GAS_STATION_API_KEY; +const ethManualGasPrice = parseInt(process.env.MANUAL_GAS_PRICE); +const ethGasStationURL = `${ethGasStationHost}/api/ethgasAPI.json?api-key=${ethGasStationApiKey}`; +const defaultRefreshInterval = 120; +const denom = BigNumber('1e+9'); export default class Fees { constructor() { - this.ethGasStationGasLevel = process.env.ETH_GAS_STATION_GAS_LEVEL + this.ethGasStationGasLevel = process.env.ETH_GAS_STATION_GAS_LEVEL; this.ethGasStationRefreshTime = (process.env.ETH_GAS_STATION_REFRESH_TIME || defaultRefreshInterval) * - 1000 - this.getETHGasStationFee(this.ethGasStationGasLevel, 0) + 1000; + this.getETHGasStationFee(this.ethGasStationGasLevel, 0); } // get ETH Gas Station @@ -32,41 +32,43 @@ export default class Fees { ethGasStationEnabled === true || ethGasStationEnabled.toLowerCase() === 'true' ) { - const response = await axios.get(ethGasStationURL) + const response = await axios.get(ethGasStationURL); // divite by 10 to convert it to Gwei) - this.ethGasPrice = response.data[gasLevel] / 10 + this.ethGasPrice = response.data[gasLevel] / 10; console.log( `get ETHGasStation gas price (${gasLevel}): ${ this.ethGasPrice } / interval: ${this.ethGasStationRefreshTime / 1000} sec` - ) + ); } else { - this.ethGasPrice = ethManualGasPrice + this.ethGasPrice = ethManualGasPrice; console.log( `get manual fixed gas price: ${this.ethGasPrice} / interval: ${ this.ethGasStationRefreshTime / 1000 } sec` - ) + ); } } catch (err) { - console.log(err) - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error ETH gas fee lookup') - return reason + console.log(err); + logger.error(err); + let reason; + err.reason + ? (reason = err.reason) + : (reason = 'error ETH gas fee lookup'); + return reason; } if (interval > 0) { // set to '0' for one-time retrieval setTimeout( this.getETHGasStationFee.bind(this), this.ethGasStationRefreshTime - ) // update every x seconds + ); // update every x seconds } } // get gas cost async getGasCost(gasPrice, gasLimit, inGwei = false) { - const cost = gasPrice * gasLimit - return inGwei ? cost : cost / denom + const cost = gasPrice * gasLimit; + return inGwei ? cost : cost / denom; } } diff --git a/src/services/logger.js b/src/services/logger.js index 774e0af..c7c6c56 100644 --- a/src/services/logger.js +++ b/src/services/logger.js @@ -1,26 +1,26 @@ -import { getLocalDate } from './utils' +import { getLocalDate } from './utils'; -require('dotenv').config() -const appRoot = require('app-root-path') -const winston = require('winston') -require('winston-daily-rotate-file') +require('dotenv').config(); +const appRoot = require('app-root-path'); +const winston = require('winston'); +require('winston-daily-rotate-file'); const logFormat = winston.format.combine( winston.format.timestamp(), winston.format.align(), winston.format.printf((info) => { - const localDate = getLocalDate() - return `${localDate} | ${info.level} | ${info.message}` + const localDate = getLocalDate(); + return `${localDate} | ${info.level} | ${info.message}`; }) -) +); const getLogPath = () => { - let logPath = process.env.LOG_PATH + let logPath = process.env.LOG_PATH; if (typeof logPath === 'undefined' || logPath == null || logPath === '') { - logPath = [appRoot.path, 'logs'].join('/') + logPath = [appRoot.path, 'logs'].join('/'); } - return logPath -} + return logPath; +}; const config = { file: { @@ -30,14 +30,16 @@ const config = { handleExceptions: true, handleRejections: true } -} +}; -const allLogsFileTransport = new winston.transports.DailyRotateFile(config.file) +const allLogsFileTransport = new winston.transports.DailyRotateFile( + config.file +); const options = { format: logFormat, transports: [allLogsFileTransport], exitOnError: false -} +}; -export const logger = winston.createLogger(options) +export const logger = winston.createLogger(options); diff --git a/src/services/perpetual_finance.js b/src/services/perpetual_finance.js index 98d0afc..9999aef 100644 --- a/src/services/perpetual_finance.js +++ b/src/services/perpetual_finance.js @@ -1,70 +1,71 @@ -import { logger } from './logger' +import { logger } from './logger'; -const fetch = require('cross-fetch') +const fetch = require('cross-fetch'); -const Ethers = require('ethers') -const AmmArtifact = require('@perp/contract/build/contracts/Amm.json') -const ClearingHouseArtifact = require('@perp/contract/build/contracts/ClearingHouse.json') -const ClearingHouseViewerArtifact = require('@perp/contract/build/contracts/ClearingHouseViewer.json') -const TetherTokenArtifact = require('@perp/contract/build/contracts/TetherToken.json') +const Ethers = require('ethers'); +const AmmArtifact = require('@perp/contract/build/contracts/Amm.json'); +const ClearingHouseArtifact = require('@perp/contract/build/contracts/ClearingHouse.json'); +const ClearingHouseViewerArtifact = require('@perp/contract/build/contracts/ClearingHouseViewer.json'); +const TetherTokenArtifact = require('@perp/contract/build/contracts/TetherToken.json'); -const GAS_LIMIT = 2123456 -const DEFAULT_DECIMALS = 18 -const CONTRACT_ADDRESSES = 'https://metadata.perp.exchange/' -const XDAI_PROVIDER = process.env.XDAI_PROVIDER || 'https://dai.poa.network' -const PNL_OPTION_SPOT_PRICE = 0 -const UPDATE_PERIOD = 60000 // stop updating prices after 30 secs from last request +const GAS_LIMIT = 2123456; +const DEFAULT_DECIMALS = 18; +const CONTRACT_ADDRESSES = 'https://metadata.perp.exchange/'; +const XDAI_PROVIDER = process.env.XDAI_PROVIDER || 'https://dai.poa.network'; +const PNL_OPTION_SPOT_PRICE = 0; +const UPDATE_PERIOD = 60000; // stop updating prices after 30 secs from last request export default class PerpetualFinance { constructor(network = 'mainnet') { - this.providerUrl = XDAI_PROVIDER - this.network = network - this.provider = new Ethers.providers.JsonRpcProvider(this.providerUrl) - this.gasLimit = GAS_LIMIT - this.contractAddressesUrl = CONTRACT_ADDRESSES - this.amm = {} - this.priceCache = {} - this.cacheExpirary = {} - this.pairAmountCache = {} + this.providerUrl = XDAI_PROVIDER; + this.network = network; + this.provider = new Ethers.providers.JsonRpcProvider(this.providerUrl); + this.gasLimit = GAS_LIMIT; + this.contractAddressesUrl = CONTRACT_ADDRESSES; + this.amm = {}; + this.priceCache = {}; + this.cacheExpirary = {}; + this.pairAmountCache = {}; switch (network) { case 'mainnet': - this.contractAddressesUrl += 'production.json' - break + this.contractAddressesUrl += 'production.json'; + break; case 'kovan': - this.contractAddressesUrl += 'staging.json' - break - default: - const err = `Invalid network ${network}` - logger.error(err) - throw Error(err) + this.contractAddressesUrl += 'staging.json'; + break; + default: { + const err = `Invalid network ${network}`; + logger.error(err); + throw Error(err); + } } - this.loadedMetadata = this.load_metadata() + this.loadedMetadata = this.load_metadata(); } async load_metadata() { try { const metadata = await fetch(this.contractAddressesUrl).then((res) => res.json() - ) - const layer2 = Object.keys(metadata.layers.layer2.contracts) + ); + const layer2 = Object.keys(metadata.layers.layer2.contracts); for (const key of layer2) { if (metadata.layers.layer2.contracts[key].name === 'Amm') { - this.amm[key] = metadata.layers.layer2.contracts[key].address + this.amm[key] = metadata.layers.layer2.contracts[key].address; } else { - this[key] = metadata.layers.layer2.contracts[key].address + this[key] = metadata.layers.layer2.contracts[key].address; } } this.layer2AmbAddr = - metadata.layers.layer2.externalContracts.ambBridgeOnXDai - this.xUsdcAddr = metadata.layers.layer2.externalContracts.usdc - this.loadedMetadata = true - return true + metadata.layers.layer2.externalContracts.ambBridgeOnXDai; + this.xUsdcAddr = metadata.layers.layer2.externalContracts.usdc; + this.loadedMetadata = true; + return true; } catch (err) { - return false + return false; } } @@ -72,8 +73,8 @@ export default class PerpetualFinance { if (Object.keys(this.cacheExpirary).length > 0) { for (const pair in this.cacheExpirary) { if (this.cacheExpirary[pair] <= Date.now()) { - delete this.cacheExpirary[pair] - delete this.priceCache[pair] + delete this.cacheExpirary[pair]; + delete this.priceCache[pair]; } } @@ -82,7 +83,7 @@ export default class PerpetualFinance { this.amm[pair], AmmArtifact.abi, this.provider - ) + ); await Promise.allSettled([ amm.getInputPrice(0, { d: Ethers.utils.parseUnits( @@ -97,33 +98,33 @@ export default class PerpetualFinance { ) }) ]).then((values) => { - if (!this.priceCache.hasOwnProperty(pair)) { - this.priceCache[pair] = [] + if (!Object.prototype.hasOwnProperty.call(this.priceCache, pair)) { + this.priceCache[pair] = []; } this.priceCache[pair][0] = this.pairAmountCache[pair] / - Ethers.utils.formatUnits(values[0].value.d) + Ethers.utils.formatUnits(values[0].value.d); this.priceCache[pair][1] = Ethers.utils.formatUnits(values[1].value.d) / - this.pairAmountCache[pair] - }) + this.pairAmountCache[pair]; + }); } } - setTimeout(this.update_price_loop.bind(this), 10000) // update every 10 seconds + setTimeout(this.update_price_loop.bind(this), 10000); // update every 10 seconds } // get XDai balance async getXdaiBalance(wallet) { try { - const xDaiBalance = await wallet.getBalance() - return Ethers.utils.formatEther(xDaiBalance) + const xDaiBalance = await wallet.getBalance(); + return Ethers.utils.formatEther(xDaiBalance); } catch (err) { - logger.error(err) - let reason + logger.error(err); + let reason; err.reason ? (reason = err.reason) - : (reason = 'error xDai balance lookup') - return reason + : (reason = 'error xDai balance lookup'); + return reason; } } @@ -134,15 +135,15 @@ export default class PerpetualFinance { this.xUsdcAddr, TetherTokenArtifact.abi, wallet - ) - const layer2UsdcBalance = await layer2Usdc.balanceOf(wallet.address) - const layer2UsdcDecimals = await layer2Usdc.decimals() - return Ethers.utils.formatUnits(layer2UsdcBalance, layer2UsdcDecimals) + ); + const layer2UsdcBalance = await layer2Usdc.balanceOf(wallet.address); + const layer2UsdcDecimals = await layer2Usdc.decimals(); + return Ethers.utils.formatUnits(layer2UsdcBalance, layer2UsdcDecimals); } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error balance lookup') - return reason + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error balance lookup'); + return reason; } } @@ -153,23 +154,23 @@ export default class PerpetualFinance { this.xUsdcAddr, TetherTokenArtifact.abi, wallet - ) + ); try { const allowanceForClearingHouse = await layer2Usdc.allowance( wallet.address, this.ClearingHouse - ) + ); return Ethers.utils.formatUnits( allowanceForClearingHouse, DEFAULT_DECIMALS - ) + ); } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error allowance lookup') - return reason + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error allowance lookup'); + return reason; } } @@ -181,18 +182,18 @@ export default class PerpetualFinance { this.xUsdcAddr, TetherTokenArtifact.abi, wallet - ) + ); const tx = await layer2Usdc.approve( this.ClearingHouse, Ethers.utils.parseUnits(amount, DEFAULT_DECIMALS) - ) + ); // TO-DO: We may want to supply custom gasLimit value above - return tx.hash + return tx.hash; } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error approval') - return reason + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error approval'); + return reason; } } @@ -201,16 +202,16 @@ export default class PerpetualFinance { try { const quoteAssetAmount = { d: Ethers.utils.parseUnits(margin, DEFAULT_DECIMALS) - } - const leverage = { d: Ethers.utils.parseUnits(levrg, DEFAULT_DECIMALS) } + }; + const leverage = { d: Ethers.utils.parseUnits(levrg, DEFAULT_DECIMALS) }; const minBaseAssetAmount = { d: Ethers.utils.parseUnits(minBaseAmount, DEFAULT_DECIMALS) - } + }; const clearingHouse = new Ethers.Contract( this.ClearingHouse, ClearingHouseArtifact.abi, wallet - ) + ); const tx = await clearingHouse.openPosition( this.amm[pair], side, @@ -218,13 +219,13 @@ export default class PerpetualFinance { leverage, minBaseAssetAmount, { gasLimit: this.gasLimit } - ) - return tx + ); + return tx; } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error opening position') - return reason + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error opening position'); + return reason; } } @@ -233,36 +234,36 @@ export default class PerpetualFinance { try { const minimalQuoteAsset = { d: Ethers.utils.parseUnits(minimalQuote, DEFAULT_DECIMALS) - } + }; const clearingHouse = new Ethers.Contract( this.ClearingHouse, ClearingHouseArtifact.abi, wallet - ) + ); const tx = await clearingHouse.closePosition( this.amm[pair], minimalQuoteAsset, { gasLimit: this.gasLimit } - ) - return tx + ); + return tx; } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error closing position') - return reason + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error closing position'); + return reason; } } // get active position async getPosition(wallet, pair) { try { - const positionValues = {} + const positionValues = {}; const clearingHouse = new Ethers.Contract( this.ClearingHouse, ClearingHouseArtifact.abi, wallet - ) - let premIndex = 0 + ); + let premIndex = 0; await Promise.allSettled([ clearingHouse.getPosition(this.amm[pair], wallet.address), clearingHouse.getLatestCumulativePremiumFraction(this.amm[pair]), @@ -275,47 +276,47 @@ export default class PerpetualFinance { positionValues.openNotional = Ethers.utils.formatUnits( values[0].value.openNotional.d, DEFAULT_DECIMALS - ) + ); positionValues.size = Ethers.utils.formatUnits( values[0].value.size.d, DEFAULT_DECIMALS - ) + ); positionValues.margin = Ethers.utils.formatUnits( values[0].value.margin.d, DEFAULT_DECIMALS - ) + ); positionValues.cumulativePremiumFraction = Ethers.utils.formatUnits( values[0].value.lastUpdatedCumulativePremiumFraction.d, DEFAULT_DECIMALS - ) + ); premIndex = Ethers.utils.formatUnits( values[1].value.d, DEFAULT_DECIMALS - ) + ); positionValues.pnl = Ethers.utils.formatUnits( values[2].value.unrealizedPnl.d, DEFAULT_DECIMALS - ) + ); positionValues.positionNotional = Ethers.utils.formatUnits( values[2].value.positionNotional.d, DEFAULT_DECIMALS - ) - }) + ); + }); positionValues.entryPrice = Math.abs( positionValues.openNotional / positionValues.size - ) + ); positionValues.fundingPayment = (premIndex - positionValues.cumulativePremiumFraction) * - positionValues.size // * -1 - return positionValues + positionValues.size; // * -1 + return positionValues; } catch (err) { - logger.error(err) - let reason + logger.error(err); + let reason; err.reason ? (reason = err.reason) - : (reason = 'error getting active position') - return reason + : (reason = 'error getting active position'); + return reason; } } @@ -326,70 +327,70 @@ export default class PerpetualFinance { this.ClearingHouseViewer, ClearingHouseViewerArtifact.abi, wallet - ) + ); const activeMargin = await clearingHouseViewer.getPersonalBalanceWithFundingPayment( this.xUsdcAddr, wallet.address - ) - return activeMargin / (1e18).toString() + ); + return activeMargin / (1e18).toString(); } catch (err) { - logger.error(err) - let reason + logger.error(err); + let reason; err.reason ? (reason = err.reason) - : (reason = 'error getting active position') - return reason + : (reason = 'error getting active position'); + return reason; } } // get Price async getPrice(side, amount, pair) { try { - let price - this.cacheExpirary[pair] = Date.now() + UPDATE_PERIOD - this.pairAmountCache[pair] = amount - if (!this.priceCache.hasOwnProperty(pair)) { + let price; + this.cacheExpirary[pair] = Date.now() + UPDATE_PERIOD; + this.pairAmountCache[pair] = amount; + if (!Object.prototype.hasOwnProperty.call(this.priceCache, pair)) { const amm = new Ethers.Contract( this.amm[pair], AmmArtifact.abi, this.provider - ) + ); if (side === 'buy') { price = await amm.getInputPrice(0, { d: Ethers.utils.parseUnits(amount, DEFAULT_DECIMALS) - }) - price = amount / Ethers.utils.formatUnits(price.d) + }); + price = amount / Ethers.utils.formatUnits(price.d); } else { price = await amm.getOutputPrice(0, { d: Ethers.utils.parseUnits(amount, DEFAULT_DECIMALS) - }) - price = Ethers.utils.formatUnits(price.d) / amount + }); + price = Ethers.utils.formatUnits(price.d) / amount; } } else if (side === 'buy') { - price = this.priceCache[pair][0] + price = this.priceCache[pair][0]; } else { - price = this.priceCache[pair][1] + price = this.priceCache[pair][1]; } - return price + return price; } catch (err) { - console.log(err) - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error getting Price') - return reason + console.log(err); + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error getting Price'); + return reason; } } // get getFundingRate async getFundingRate(pair) { try { - const funding = {} + const funding = {}; const amm = new Ethers.Contract( this.amm[pair], AmmArtifact.abi, this.provider - ) + ); await Promise.allSettled([ amm.getUnderlyingTwapPrice(3600), amm.getTwapPrice(3600), @@ -397,22 +398,22 @@ export default class PerpetualFinance { ]).then((values) => { funding.indexPrice = parseFloat( Ethers.utils.formatUnits(values[0].value.d) - ) + ); funding.markPrice = parseFloat( Ethers.utils.formatUnits(values[1].value.d) - ) - funding.nextFundingTime = parseInt(values[2].value.toString()) - }) + ); + funding.nextFundingTime = parseInt(values[2].value.toString()); + }); funding.rate = - (funding.markPrice - funding.indexPrice) / 24 / funding.indexPrice - return funding + (funding.markPrice - funding.indexPrice) / 24 / funding.indexPrice; + return funding; } catch (err) { - console.log(err) - logger.error(err)() - let reason - err.reason ? (reason = err.reason) : (reason = 'error getting fee') - return reason + console.log(err); + logger.error(err)(); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error getting fee'); + return reason; } } } diff --git a/src/services/terra.js b/src/services/terra.js index 48d8485..601802e 100644 --- a/src/services/terra.js +++ b/src/services/terra.js @@ -4,13 +4,13 @@ import { MsgSwap, MnemonicKey, isTxError -} from '@terra-money/terra.js' -import BigNumber from 'bignumber.js' -import { logger } from './logger' -import { getHummingbotMemo } from './utils' +} from '@terra-money/terra.js'; +import BigNumber from 'bignumber.js'; +import { logger } from './logger'; +import { getHummingbotMemo } from './utils'; -const debug = require('debug')('router') -require('dotenv').config() +const debug = require('debug')('router'); +require('dotenv').config(); // constants const TERRA_TOKENS = { @@ -19,35 +19,35 @@ const TERRA_TOKENS = { ukrw: { symbol: 'KRT' }, usdr: { symbol: 'SDT' }, umnt: { symbol: 'MNT' } -} -const DENOM_UNIT = BigNumber('1e+6') -const TOBIN_TAX = 0.0025 // a Tobin Tax (set at 0.25%) for spot-converting Terra<>Terra swaps -const MIN_SPREAD = 0.02 // a minimum spread (set at 2%) for Terra<>Luna swaps -const GAS_PRICE = { uluna: 0.16 } -const GAS_ADJUSTMENT = 1.4 +}; +const DENOM_UNIT = BigNumber('1e+6'); +const TOBIN_TAX = 0.0025; // a Tobin Tax (set at 0.25%) for spot-converting Terra<>Terra swaps +const MIN_SPREAD = 0.02; // a minimum spread (set at 2%) for Terra<>Luna swaps +const GAS_PRICE = { uluna: 0.16 }; +const GAS_ADJUSTMENT = 1.4; export default class Terra { constructor() { - this.lcdUrl = process.env.TERRA_LCD_URL - this.network = process.env.TERRA_CHAIN - this.tokens = TERRA_TOKENS - this.denomUnitMultiplier = DENOM_UNIT - this.tobinTax = TOBIN_TAX - this.minSpread = MIN_SPREAD - this.memo = getHummingbotMemo() + this.lcdUrl = process.env.TERRA_LCD_URL; + this.network = process.env.TERRA_CHAIN; + this.tokens = TERRA_TOKENS; + this.denomUnitMultiplier = DENOM_UNIT; + this.tobinTax = TOBIN_TAX; + this.minSpread = MIN_SPREAD; + this.memo = getHummingbotMemo(); try { - this.lcd = this.connect() + this.lcd = this.connect(); this.lcd.market.parameters().catch(() => { - throw new Error('Connection error') - }) + throw new Error('Connection error'); + }); // set gas & fee - this.lcd.config.gasAdjustment = GAS_ADJUSTMENT - this.lcd.config.gasPrices = GAS_PRICE + this.lcd.config.gasAdjustment = GAS_ADJUSTMENT; + this.lcd.config.gasPrices = GAS_PRICE; } catch (err) { - logger.error(err) - throw Error(`Connection failed: ${this.network}`) + logger.error(err); + throw Error(`Connection failed: ${this.network}`); } } @@ -57,145 +57,149 @@ export default class Terra { const lcd = new LCDClient({ URL: this.lcdUrl, chainID: this.network - }) - lcd.config.gasAdjustment = GAS_ADJUSTMENT - lcd.config.gasPrices = GAS_PRICE - return lcd + }); + lcd.config.gasAdjustment = GAS_ADJUSTMENT; + lcd.config.gasPrices = GAS_PRICE; + return lcd; } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error Terra LCD connect') - return reason + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error Terra LCD connect'); + return reason; } } // get Token Denom getTokenDenom(symbol) { try { - let denom + let denom; Object.keys(TERRA_TOKENS).forEach((item) => { if (TERRA_TOKENS[item].symbol === symbol) { - denom = item + denom = item; } - }) - return denom + }); + return denom; } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error Terra Denom lookup') - return reason + logger.error(err); + let reason; + err.reason + ? (reason = err.reason) + : (reason = 'error Terra Denom lookup'); + return reason; } } // get Token Symbol getTokenSymbol(denom) { try { - const { symbol } = TERRA_TOKENS[denom] - return symbol + const { symbol } = TERRA_TOKENS[denom]; + return symbol; } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error Terra Denom lookup') - return reason + logger.error(err); + let reason; + err.reason + ? (reason = err.reason) + : (reason = 'error Terra Denom lookup'); + return reason; } } getTxAttributes(attributes) { - const attrib = {} + const attrib = {}; attributes.forEach((item) => { - attrib[item.key] = item.value - }) - return attrib + attrib[item.key] = item.value; + }); + return attrib; } async getEstimateFee(tx) { try { - const fee = await this.lcd.tx.estimateFee(tx) - return fee + const fee = await this.lcd.tx.estimateFee(tx); + return fee; } catch (err) { - logger.error(err) - let reason + logger.error(err); + let reason; err.reason ? (reason = err.reason) - : (reason = 'error Terra estimate fee lookup') - return reason + : (reason = 'error Terra estimate fee lookup'); + return reason; } } async getExchangeRate(denom) { try { - const exchangeRates = await this.lcd.oracle.exchangeRates() - return exchangeRates.get(denom) + const exchangeRates = await this.lcd.oracle.exchangeRates(); + return exchangeRates.get(denom); } catch (err) { - logger.error(err) - let reason + logger.error(err); + let reason; err.reason ? (reason = err.reason) - : (reason = 'error Terra exchange rate lookup') - return reason + : (reason = 'error Terra exchange rate lookup'); + return reason; } } async getTxFee() { try { - const lunaFee = GAS_PRICE.uluna * GAS_ADJUSTMENT - const feeList = { uluna: lunaFee } + const lunaFee = GAS_PRICE.uluna * GAS_ADJUSTMENT; + const feeList = { uluna: lunaFee }; await this.lcd.oracle.exchangeRates().then((rates) => { Object.keys(rates._coins).forEach((key) => { - feeList[key] = rates._coins[key].amount * lunaFee - }) - }) - debug('lunaFee', lunaFee, feeList) + feeList[key] = rates._coins[key].amount * lunaFee; + }); + }); + debug('lunaFee', lunaFee, feeList); - return feeList + return feeList; } catch (err) { - logger.error(err) - let reason + logger.error(err); + let reason; err.reason ? (reason = err.reason) - : (reason = 'error Terra exchange rate lookup') - return reason + : (reason = 'error Terra exchange rate lookup'); + return reason; } } // get Terra Swap Rate async getSwapRate(baseToken, quoteToken, amount, tradeType) { try { - let exchangeRate - let offerCoin - let offerDenom - let swapDenom - let cost - let costAmount - let offer - const swaps = {} + let exchangeRate; + let offerCoin; + let offerDenom; + let swapDenom; + let cost; + let costAmount; + let offer; + const swaps = {}; if (tradeType.toLowerCase() === 'sell') { // sell base - offerDenom = this.getTokenDenom(baseToken) - swapDenom = this.getTokenDenom(quoteToken) + offerDenom = this.getTokenDenom(baseToken); + swapDenom = this.getTokenDenom(quoteToken); - offerCoin = new Coin(offerDenom, amount * DENOM_UNIT) + offerCoin = new Coin(offerDenom, amount * DENOM_UNIT); await this.lcd.market .swapRate(offerCoin, swapDenom) .then((swapCoin) => { - offer = { amount } + offer = { amount }; exchangeRate = { amount: swapCoin.amount / DENOM_UNIT / amount, token: quoteToken - } - costAmount = amount * exchangeRate.amount + }; + costAmount = amount * exchangeRate.amount; cost = { amount: costAmount, token: quoteToken - } - }) + }; + }); } else { // buy base - offerDenom = this.getTokenDenom(quoteToken) - swapDenom = this.getTokenDenom(baseToken) + offerDenom = this.getTokenDenom(quoteToken); + swapDenom = this.getTokenDenom(baseToken); - offerCoin = new Coin(offerDenom, 1 * DENOM_UNIT) + offerCoin = new Coin(offerDenom, 1 * DENOM_UNIT); await this.lcd.market .swapRate(offerCoin, swapDenom) .then((swapCoin) => { @@ -203,36 +207,36 @@ export default class Terra { amount: ((amount / parseInt(swapCoin.amount)) * DENOM_UNIT) / amount, // adjusted amount token: quoteToken - } - costAmount = amount * exchangeRate.amount + }; + costAmount = amount * exchangeRate.amount; cost = { amount: costAmount, token: quoteToken - } - offer = { amount: cost.amount } - }) + }; + offer = { amount: cost.amount }; + }); } - let txFee + let txFee; await this.getTxFee().then((fee) => { // fee in quote txFee = { amount: parseFloat(fee[this.getTokenDenom(quoteToken)]), token: quoteToken - } - }) - - swaps.offer = offer - swaps.price = exchangeRate - swaps.cost = cost - swaps.txFee = txFee - debug('swaps', swaps) - return swaps + }; + }); + + swaps.offer = offer; + swaps.price = exchangeRate; + swaps.cost = cost; + swaps.txFee = txFee; + debug('swaps', swaps); + return swaps; } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = 'error swap rate lookup') - return reason + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = 'error swap rate lookup'); + return reason; } } @@ -246,40 +250,40 @@ export default class Terra { gasAdjustment, secret ) { - let swapResult + let swapResult; try { // connect to lcd - const lcd = this.connect() + const lcd = this.connect(); const mk = new MnemonicKey({ mnemonic: secret - }) - let wallet + }); + let wallet; try { - wallet = lcd.wallet(mk) + wallet = lcd.wallet(mk); } catch (err) { - logger.error(err) - throw Error('Wallet access error') + logger.error(err); + throw Error('Wallet access error'); } - const address = wallet.key.accAddress + const address = wallet.key.accAddress; // get the current swap rate - const baseDenom = this.getTokenDenom(baseToken) - const quoteDenom = this.getTokenDenom(quoteToken) + const baseDenom = this.getTokenDenom(baseToken); + const quoteDenom = this.getTokenDenom(quoteToken); - let offerDenom - let swapDenom - let swaps - let txAttributes - const tokenSwap = {} + let offerDenom; + let swapDenom; + let swaps; + let txAttributes; + const tokenSwap = {}; if (tradeType.toLowerCase() === 'sell') { - offerDenom = baseDenom - swapDenom = quoteDenom + offerDenom = baseDenom; + swapDenom = quoteDenom; } else { - offerDenom = quoteDenom - swapDenom = baseDenom + offerDenom = quoteDenom; + swapDenom = baseDenom; } await this.getSwapRate( @@ -289,16 +293,16 @@ export default class Terra { tradeType, secret ).then((rate) => { - swaps = rate - }) + swaps = rate; + }); - const offerAmount = parseInt(swaps.offer.amount * DENOM_UNIT) - const offerCoin = new Coin(offerDenom, offerAmount) + const offerAmount = parseInt(swaps.offer.amount * DENOM_UNIT); + const offerCoin = new Coin(offerDenom, offerAmount); // Create and Sign Transaction - const msgSwap = new MsgSwap(address, offerCoin, swapDenom) + const msgSwap = new MsgSwap(address, offerCoin, swapDenom); - let txOptions + let txOptions; if (gasPrice !== null && gasPrice !== null) { // ignore gasAdjustment when gasPrice is not set txOptions = { @@ -306,57 +310,57 @@ export default class Terra { gasPrices: { uluna: parseFloat(gasPrice) }, gasAdjustment, memo: this.memo - } + }; } else { txOptions = { msgs: [msgSwap], memo: this.memo - } + }; } await wallet .createAndSignTx(txOptions) .then((tx) => lcd.tx.broadcast(tx)) .then((txResult) => { - swapResult = txResult + swapResult = txResult; - const swapSuccess = !isTxError(txResult) + const swapSuccess = !isTxError(txResult); if (swapSuccess) { - tokenSwap.txSuccess = swapSuccess + tokenSwap.txSuccess = swapSuccess; } else { - tokenSwap.txSuccess = !swapSuccess + tokenSwap.txSuccess = !swapSuccess; throw new Error( `encountered an error while running the transaction: ${txResult.code} ${txResult.codespace}` - ) + ); } - const txHash = txResult.txhash - const { events } = JSON.parse(txResult.raw_log)[0] - const swap = events.find((obj) => obj.type === 'swap') - txAttributes = this.getTxAttributes(swap.attributes) - const offer = Coin.fromString(txAttributes.offer) - const ask = Coin.fromString(txAttributes.swap_coin) - const fee = Coin.fromString(txAttributes.swap_fee) + const txHash = txResult.txhash; + const { events } = JSON.parse(txResult.raw_log)[0]; + const swap = events.find((obj) => obj.type === 'swap'); + txAttributes = this.getTxAttributes(swap.attributes); + const offer = Coin.fromString(txAttributes.offer); + const ask = Coin.fromString(txAttributes.swap_coin); + const fee = Coin.fromString(txAttributes.swap_fee); tokenSwap.expectedIn = { amount: parseFloat(offer.amount) / DENOM_UNIT, token: TERRA_TOKENS[offer.denom].symbol - } + }; tokenSwap.expectedOut = { amount: parseFloat(ask.amount) / DENOM_UNIT, token: TERRA_TOKENS[ask.denom].symbol - } + }; tokenSwap.fee = { amount: parseFloat(fee.amount) / DENOM_UNIT, token: TERRA_TOKENS[fee.denom].symbol - } - tokenSwap.txHash = txHash - }) - return tokenSwap + }; + tokenSwap.txHash = txHash; + }); + return tokenSwap; } catch (err) { - logger.error(err) - let reason - err.reason ? (reason = err.reason) : (reason = swapResult) - return { txSuccess: false, message: reason } + logger.error(err); + let reason; + err.reason ? (reason = err.reason) : (reason = swapResult); + return { txSuccess: false, message: reason }; } } } diff --git a/src/services/uniswap.js b/src/services/uniswap.js index 076dbb7..e41ee81 100644 --- a/src/services/uniswap.js +++ b/src/services/uniswap.js @@ -1,65 +1,66 @@ -import { logger } from './logger' +import { logger } from './logger'; -const debug = require('debug')('router') -const math = require('mathjs') -const uni = require('@uniswap/sdk') -const ethers = require('ethers') -const proxyArtifact = require('../static/uniswap_v2_router_abi.json') -const routeTokens = require('../static/uniswap_route_tokens.json') +const debug = require('debug')('router'); +const math = require('mathjs'); +const uni = require('@uniswap/sdk'); +const ethers = require('ethers'); +const proxyArtifact = require('../static/uniswap_v2_router_abi.json'); +const routeTokens = require('../static/uniswap_route_tokens.json'); // constants -const ROUTER = process.env.UNISWAP_ROUTER -const GAS_LIMIT = process.env.UNISWAP_GAS_LIMIT || 150688 -const TTL = process.env.UNISWAP_TTL || 300 -const UPDATE_PERIOD = process.env.UNISWAP_UPDATE_PERIOD || 300000 // stop updating pair after 5 minutes from last request +const ROUTER = process.env.UNISWAP_ROUTER; +const GAS_LIMIT = process.env.UNISWAP_GAS_LIMIT || 150688; +const TTL = process.env.UNISWAP_TTL || 300; +const UPDATE_PERIOD = process.env.UNISWAP_UPDATE_PERIOD || 300000; // stop updating pair after 5 minutes from last request export default class Uniswap { constructor(network = 'mainnet') { - this.providerUrl = process.env.ETHEREUM_RPC_URL - this.network = process.env.ETHEREUM_CHAIN - this.provider = new ethers.providers.JsonRpcProvider(this.providerUrl) - this.router = ROUTER - this.slippage = math.fraction(process.env.UNISWAP_ALLOWED_SLIPPAGE) + this.providerUrl = process.env.ETHEREUM_RPC_URL; + this.network = process.env.ETHEREUM_CHAIN; + this.provider = new ethers.providers.JsonRpcProvider(this.providerUrl); + this.router = ROUTER; + this.slippage = math.fraction(process.env.UNISWAP_ALLOWED_SLIPPAGE); this.allowedSlippage = new uni.Percent( this.slippage.n, this.slippage.d * 100 - ) - this.pairsCacheTime = process.env.UNISWAP_PAIRS_CACHE_TIME - this.gasLimit = GAS_LIMIT - this.expireTokenPairUpdate = UPDATE_PERIOD + ); + this.pairsCacheTime = process.env.UNISWAP_PAIRS_CACHE_TIME; + this.gasLimit = GAS_LIMIT; + this.expireTokenPairUpdate = UPDATE_PERIOD; this.zeroReserveCheckInterval = - process.env.UNISWAP_NO_RESERVE_CHECK_INTERVAL - this.zeroReservePairs = {} // No reserve pairs - this.tokenList = {} - this.pairs = [] - this.tokenSwapList = {} - this.cachedRoutes = {} + process.env.UNISWAP_NO_RESERVE_CHECK_INTERVAL; + this.zeroReservePairs = {}; // No reserve pairs + this.tokenList = {}; + this.pairs = []; + this.tokenSwapList = {}; + this.cachedRoutes = {}; switch (network) { case 'mainnet': - this.chainID = uni.ChainId.MAINNET - break + this.chainID = uni.ChainId.MAINNET; + break; case 'kovan': - this.chainID = uni.ChainId.KOVAN - break - default: - const err = `Invalid network ${network}` - logger.error(err) - throw Error(err) + this.chainID = uni.ChainId.KOVAN; + break; + default: { + const err = `Invalid network ${network}`; + logger.error(err); + throw Error(err); + } } } async fetch_route(tIn, tOut) { - let route - let pair + let route; + let pair; try { - pair = await uni.Fetcher.fetchPairData(tIn, tOut) - route = new uni.Route([pair], tIn, tOut) + pair = await uni.Fetcher.fetchPairData(tIn, tOut); + route = new uni.Route([pair], tIn, tOut); } catch (err) { - logger.error(err) + logger.error(err); } - return route + return route; } generate_tokens() { @@ -70,19 +71,19 @@ export default class Uniswap { token.decimals, token.symbol, token.name - ) + ); } } async extend_update_pairs(tokens = []) { for (const token of tokens) { - if (!this.tokenList.hasOwnProperty(token)) { + if (!Object.prototype.hasOwnProperty.call(this.tokenList, token)) { this.tokenList[token] = await uni.Fetcher.fetchTokenData( this.chainID, token - ) + ); } - this.tokenSwapList[token] = Date.now() + this.expireTokenPairUpdate + this.tokenSwapList[token] = Date.now() + this.expireTokenPairUpdate; } } @@ -91,7 +92,7 @@ export default class Uniswap { if (Object.keys(this.zeroReservePairs).length > 0) { for (const pair in this.zeroReservePairs) { if (this.zeroReservePairs[pair] <= Date.now()) { - delete this.zeroReservePairs[pair] + delete this.zeroReservePairs[pair]; // delete this.tokenList[token]; } } @@ -101,19 +102,19 @@ export default class Uniswap { if (Object.keys(this.tokenSwapList).length > 0) { for (const token in this.tokenSwapList) { if (this.tokenSwapList[token] <= Date.now()) { - delete this.tokenSwapList[token] + delete this.tokenSwapList[token]; // delete this.tokenList[token]; } } - const tokens = Object.keys(this.tokenList) - let firstToken - let secondToken - let position - const length = tokens.length - const pairs = [] - const pairAddressRequests = [] - const pairAddressResponses = [] + const tokens = Object.keys(this.tokenList); + let firstToken; + let secondToken; + let position; + const length = tokens.length; + const pairs = []; + const pairAddressRequests = []; + const pairAddressResponses = []; for (firstToken = 0; firstToken < length; firstToken++) { for ( secondToken = firstToken + 1; @@ -123,18 +124,23 @@ export default class Uniswap { try { const pairString = `${this.tokenList[tokens[firstToken]].address}-${ this.tokenList[tokens[secondToken]].address - }` - if (!this.zeroReservePairs.hasOwnProperty(pairString)) { - pairs.push(pairString) + }`; + if ( + !Object.prototype.hasOwnProperty.call( + this.zeroReservePairs, + pairString + ) + ) { + pairs.push(pairString); pairAddressRequests.push( uni.Fetcher.fetchPairData( this.tokenList[tokens[firstToken]], this.tokenList[tokens[secondToken]] ) - ) + ); } } catch (err) { - logger.error(err) + logger.error(err); } } } @@ -142,82 +148,82 @@ export default class Uniswap { await Promise.allSettled(pairAddressRequests).then((values) => { for (position = 0; position < pairAddressRequests.length; position++) { if (values[position].status === 'fulfilled') { - pairAddressResponses.push(values[position].value) + pairAddressResponses.push(values[position].value); } else { this.zeroReservePairs[pairs[position]] = - Date.now() + this.zeroReserveCheckInterval + Date.now() + this.zeroReserveCheckInterval; } } - }) - this.pairs = pairAddressResponses + }); + this.pairs = pairAddressResponses; } - setTimeout(this.update_pairs.bind(this), 1000) + setTimeout(this.update_pairs.bind(this), 1000); } async priceSwapIn(tokenIn, tokenOut, tokenInAmount) { - await this.extend_update_pairs([tokenIn, tokenOut]) - const tIn = this.tokenList[tokenIn] - const tOut = this.tokenList[tokenOut] + await this.extend_update_pairs([tokenIn, tokenOut]); + const tIn = this.tokenList[tokenIn]; + const tOut = this.tokenList[tokenOut]; const tokenAmountIn = new uni.TokenAmount( tIn, ethers.utils.parseUnits(tokenInAmount, tIn.decimals) - ) + ); if (this.pairs.length === 0) { - const route = await this.fetch_route(tIn, tOut) - const trade = uni.Trade.exactIn(route, tokenAmountIn) + const route = await this.fetch_route(tIn, tOut); + const trade = uni.Trade.exactIn(route, tokenAmountIn); if (trade !== undefined) { - const expectedAmount = trade.minimumAmountOut(this.allowedSlippage) - this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade - return { trade, expectedAmount } + const expectedAmount = trade.minimumAmountOut(this.allowedSlippage); + this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade; + return { trade, expectedAmount }; } - return "Can't find route to swap, kindly update " + return "Can't find route to swap, kindly update "; } let trade = uni.Trade.bestTradeExactIn( this.pairs, tokenAmountIn, this.tokenList[tokenOut], { maxHops: 5 } - )[0] + )[0]; if (trade === undefined) { - trade = this.cachedRoutes[tIn.symbol + tOut.Symbol] + trade = this.cachedRoutes[tIn.symbol + tOut.Symbol]; } else { - this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade + this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade; } - const expectedAmount = trade.minimumAmountOut(this.allowedSlippage) - return { trade, expectedAmount } + const expectedAmount = trade.minimumAmountOut(this.allowedSlippage); + return { trade, expectedAmount }; } async priceSwapOut(tokenIn, tokenOut, tokenOutAmount) { - await this.extend_update_pairs([tokenIn, tokenOut]) - const tOut = this.tokenList[tokenOut] - const tIn = this.tokenList[tokenIn] + await this.extend_update_pairs([tokenIn, tokenOut]); + const tOut = this.tokenList[tokenOut]; + const tIn = this.tokenList[tokenIn]; const tokenAmountOut = new uni.TokenAmount( tOut, ethers.utils.parseUnits(tokenOutAmount, tOut.decimals) - ) + ); if (this.pairs.length === 0) { - const route = await this.fetch_route(tIn, tOut) - const trade = uni.Trade.exactOut(route, tokenAmountOut) + const route = await this.fetch_route(tIn, tOut); + const trade = uni.Trade.exactOut(route, tokenAmountOut); if (trade !== undefined) { - const expectedAmount = trade.maximumAmountIn(this.allowedSlippage) - this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade - return { trade, expectedAmount } + const expectedAmount = trade.maximumAmountIn(this.allowedSlippage); + this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade; + return { trade, expectedAmount }; } - return + return; } let trade = uni.Trade.bestTradeExactOut( this.pairs, this.tokenList[tokenIn], tokenAmountOut, { maxHops: 5 } - )[0] + )[0]; if (trade === undefined) { - trade = this.cachedRoutes[tIn.symbol + tOut.Symbol] + trade = this.cachedRoutes[tIn.symbol + tOut.Symbol]; } else { - this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade + this.cachedRoutes[tIn.symbol + tOut.Symbol] = trade; } - const expectedAmount = trade.maximumAmountIn(this.allowedSlippage) - return { trade, expectedAmount } + const expectedAmount = trade.maximumAmountIn(this.allowedSlippage); + return { trade, expectedAmount }; } async swapExactIn(wallet, trade, tokenAddress, gasPrice) { @@ -225,17 +231,21 @@ export default class Uniswap { ttl: TTL, recipient: wallet.address, allowedSlippage: this.allowedSlippage - }) + }); - const contract = new ethers.Contract(this.router, proxyArtifact.abi, wallet) + const contract = new ethers.Contract( + this.router, + proxyArtifact.abi, + wallet + ); const tx = await contract[result.methodName](...result.args, { gasPrice: gasPrice * 1e9, gasLimit: GAS_LIMIT, value: result.value - }) + }); - debug(`Tx Hash: ${tx.hash}`) - return tx + debug(`Tx Hash: ${tx.hash}`); + return tx; } async swapExactOut(wallet, trade, tokenAddress, gasPrice) { @@ -243,16 +253,20 @@ export default class Uniswap { ttl: TTL, recipient: wallet.address, allowedSlippage: this.allowedSlippage - }) + }); - const contract = new ethers.Contract(this.router, proxyArtifact.abi, wallet) + const contract = new ethers.Contract( + this.router, + proxyArtifact.abi, + wallet + ); const tx = await contract[result.methodName](...result.args, { gasPrice: gasPrice * 1e9, gasLimit: GAS_LIMIT, value: result.value - }) + }); - debug(`Tx Hash: ${tx.hash}`) - return tx + debug(`Tx Hash: ${tx.hash}`); + return tx; } } diff --git a/src/services/uniswap_v3.js b/src/services/uniswap_v3.js index fecf868..88fe990 100644 --- a/src/services/uniswap_v3.js +++ b/src/services/uniswap_v3.js @@ -1,113 +1,114 @@ -import { logger } from './logger' +import { logger } from './logger'; import { encodePriceSqrt, getTickFromPrice -} from '../static/uniswap-v3/helper_functions' +} from '../static/uniswap-v3/helper_functions'; -const debug = require('debug')('router') -const math = require('mathjs') -const uni = require('@uniswap/sdk') -const ethers = require('ethers') -const coreArtifact = require('@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json') -const nftArtifact = require('@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json') -const routerArtifact = require('@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json') -const poolArtifact = require('@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json') +const debug = require('debug')('router'); +const math = require('mathjs'); +const uni = require('@uniswap/sdk'); +const ethers = require('ethers'); +const coreArtifact = require('@uniswap/v3-core/artifacts/contracts/UniswapV3Factory.sol/UniswapV3Factory.json'); +const nftArtifact = require('@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'); +const routerArtifact = require('@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json'); +const poolArtifact = require('@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json'); // const routeTokens = require('../static/uniswap_route_tokens.json') -const abiDecoder = require('abi-decoder') +const abiDecoder = require('abi-decoder'); // constants -const FeeAmount = { LOW: 500, MEDIUM: 3000, HIGH: 10000 } -const GAS_LIMIT = process.env.UNISWAP_GAS_LIMIT || 5506880 -const TTL = process.env.UNISWAP_TTL || 300 -const UPDATE_PERIOD = process.env.UNISWAP_UPDATE_PERIOD || 300000 // stop updating pair after 5 minutes from last request -const MaxUint128 = ethers.BigNumber.from(2).pow(128).sub(1) +const FeeAmount = { LOW: 500, MEDIUM: 3000, HIGH: 10000 }; +const GAS_LIMIT = process.env.UNISWAP_GAS_LIMIT || 5506880; +const TTL = process.env.UNISWAP_TTL || 300; +const UPDATE_PERIOD = process.env.UNISWAP_UPDATE_PERIOD || 300000; // stop updating pair after 5 minutes from last request +const MaxUint128 = ethers.BigNumber.from(2).pow(128).sub(1); -abiDecoder.addABI(nftArtifact.abi) -abiDecoder.addABI(routerArtifact.abi) +abiDecoder.addABI(nftArtifact.abi); +abiDecoder.addABI(routerArtifact.abi); export default class UniswapV3 { constructor(network = 'mainnet') { - this.providerUrl = process.env.ETHEREUM_RPC_URL - this.network = process.env.ETHEREUM_CHAIN - this.provider = new ethers.providers.JsonRpcProvider(this.providerUrl) - this.router = process.env.UNISWAP_V3_ROUTER - this.nftManager = process.env.UNISWAP_V3_NFT_MANAGER - this.core = process.env.UNISWAP_V3_CORE - this.slippage = process.env.UNISWAP_ALLOWED_SLIPPAGE - this.pairsCacheTime = process.env.UNISWAP_PAIRS_CACHE_TIME - this.gasLimit = GAS_LIMIT - this.expireTokenPairUpdate = UPDATE_PERIOD + this.providerUrl = process.env.ETHEREUM_RPC_URL; + this.network = process.env.ETHEREUM_CHAIN; + this.provider = new ethers.providers.JsonRpcProvider(this.providerUrl); + this.router = process.env.UNISWAP_V3_ROUTER; + this.nftManager = process.env.UNISWAP_V3_NFT_MANAGER; + this.core = process.env.UNISWAP_V3_CORE; + this.slippage = process.env.UNISWAP_ALLOWED_SLIPPAGE; + this.pairsCacheTime = process.env.UNISWAP_PAIRS_CACHE_TIME; + this.gasLimit = GAS_LIMIT; + this.expireTokenPairUpdate = UPDATE_PERIOD; this.zeroReserveCheckInterval = - process.env.UNISWAP_NO_RESERVE_CHECK_INTERVAL - this.zeroReservePairs = {} // No reserve pairs - this.tokenList = {} - this.pairs = [] - this.tokenSwapList = {} - this.cachedRoutes = {} - this.abiDecoder = abiDecoder + process.env.UNISWAP_NO_RESERVE_CHECK_INTERVAL; + this.zeroReservePairs = {}; // No reserve pairs + this.tokenList = {}; + this.pairs = []; + this.tokenSwapList = {}; + this.cachedRoutes = {}; + this.abiDecoder = abiDecoder; switch (network) { case 'mainnet': - this.chainID = uni.ChainId.MAINNET - break + this.chainID = uni.ChainId.MAINNET; + break; case 'kovan': - this.chainID = uni.ChainId.KOVAN - break - default: - const err = `Invalid network ${network}` - logger.error(err) + this.chainID = uni.ChainId.KOVAN; + break; + default: { + const err = `Invalid network ${network}`; + logger.error(err); + } } } get_contract(contract, wallet) { if (contract === 'core') { - return new ethers.Contract(this.core, coreArtifact.abi, wallet) + return new ethers.Contract(this.core, coreArtifact.abi, wallet); } if (contract === 'router') { - return new ethers.Contract(this.router, routerArtifact.abi, wallet) + return new ethers.Contract(this.router, routerArtifact.abi, wallet); } - return new ethers.Contract(this.nftManager, nftArtifact.abi, wallet) + return new ethers.Contract(this.nftManager, nftArtifact.abi, wallet); } async currentPrice(wallet, tokenIn, tokenOut) { - let pool - let poolContract - const poolPrices = [] - const poolLiquidity = [] - const keys = ['LOW', 'MEDIUM', 'HIGH'] - const coreContract = this.get_contract('core', wallet) + let pool; + let poolContract; + const poolPrices = []; + const poolLiquidity = []; + const keys = ['LOW', 'MEDIUM', 'HIGH']; + const coreContract = this.get_contract('core', wallet); const poolAddressRequests = [ coreContract.getPool(tokenIn, tokenOut, FeeAmount.LOW), coreContract.getPool(tokenIn, tokenOut, FeeAmount.MEDIUM), coreContract.getPool(tokenIn, tokenOut, FeeAmount.HIGH) - ] + ]; await Promise.allSettled(poolAddressRequests).then((values) => { for (pool = 0; pool < 3; pool++) { if (values[pool].value === ethers.constants.AddressZero) { - poolPrices[pool] = 0 + poolPrices[pool] = 0; } else { poolContract = new ethers.Contract( values[pool].value, poolArtifact.abi, wallet - ) - poolPrices[pool] = poolContract.observe([1, 0]) + ); + poolPrices[pool] = poolContract.observe([1, 0]); } } - }) + }); await Promise.allSettled(poolPrices).then((values) => { for (pool = 0; pool < 3; pool++) { - poolPrices[pool] = poolLiquidity[pool] = 0 + poolPrices[pool] = poolLiquidity[pool] = 0; if (values[pool].value) { for (const tick of values[pool].value.tickCumulatives) { - poolPrices[pool] = tick.toNumber() - poolPrices[pool] + poolPrices[pool] = tick.toNumber() - poolPrices[pool]; } - poolPrices[pool] = math.pow(1.0001, poolPrices[pool]) + poolPrices[pool] = math.pow(1.0001, poolPrices[pool]); } } - }) - return Object.assign(...keys.map((k, i) => ({ [k]: poolPrices[i] }))) + }); + return Object.assign(...keys.map((k, i) => ({ [k]: poolPrices[i] }))); } async swapExactIn( @@ -120,16 +121,16 @@ export default class UniswapV3 { _gasPrice ) { // sell, In => base, Out => quote - const minPercentOut = 1 - this.slippage / 100 + const minPercentOut = 1 - this.slippage / 100; const amountOutMinimum = Math.floor( baseAmount * limitPrice * minPercentOut * quoteTokenContractInfo.decimals - ) / quoteTokenContractInfo.decimals + ) / quoteTokenContractInfo.decimals; // const priceFraction = math.fraction(limitPrice) - const contract = this.get_contract('router', wallet) + const contract = this.get_contract('router', wallet); const tx = await contract.exactInputSingle( { tokenIn: baseTokenContractInfo.address, @@ -150,11 +151,11 @@ export default class UniswapV3 { { gasLimit: GAS_LIMIT } - ) + ); - debug(`Tx Hash: ${tx.hash}`) - tx.expectedAmount = amountOutMinimum - return tx + debug(`Tx Hash: ${tx.hash}`); + tx.expectedAmount = amountOutMinimum; + return tx; } async swapExactOut( @@ -167,13 +168,13 @@ export default class UniswapV3 { _gasPrice ) { // buy, In => quote, Out => base - const maxPercentIn = 1 + this.slippage / 100 + const maxPercentIn = 1 + this.slippage / 100; const amountInMaximum = Math.ceil( baseAmount * limitPrice * maxPercentIn * quoteTokenContractInfo.decimals - ) / quoteTokenContractInfo.decimals + ) / quoteTokenContractInfo.decimals; // const priceFraction = math.fraction(limitPrice) - const contract = this.get_contract('router', wallet) + const contract = this.get_contract('router', wallet); const tx = await contract.exactOutputSingle( { tokenIn: quoteTokenContractInfo.address, @@ -194,18 +195,18 @@ export default class UniswapV3 { { gasLimit: GAS_LIMIT } - ) + ); - debug(`Tx Hash: ${tx.hash}`) - tx.expectedAmount = amountInMaximum - return tx + debug(`Tx Hash: ${tx.hash}`); + tx.expectedAmount = amountInMaximum; + return tx; } // LP section async getPosition(wallet, tokenId) { - const contract = this.get_contract('nft', wallet) - const position = await contract.positions(tokenId) + const contract = this.get_contract('nft', wallet); + const position = await contract.positions(tokenId); return { nonce: position[0].toString(), operator: position[1], @@ -219,7 +220,7 @@ export default class UniswapV3 { feeGrowthInside1LastX128: position[9].toString(), tokensOwed0: position[10].toString(), tokensOwed1: position[11].toString() - } + }; } getRemoveLiquidityData(wallet, contract, tokenId, liquidity) { @@ -234,7 +235,7 @@ export default class UniswapV3 { deadline: Date.now() + TTL } ] - ) + ); const collectFeesData = contract.interface.encodeFunctionData('collect', [ { tokenId, @@ -242,10 +243,10 @@ export default class UniswapV3 { amount0Max: MaxUint128, amount1Max: MaxUint128 } - ]) - const burnData = contract.interface.encodeFunctionData('burn', [tokenId]) + ]); + const burnData = contract.interface.encodeFunctionData('burn', [tokenId]); - return [decreaseLiquidityData, collectFeesData, burnData] + return [decreaseLiquidityData, collectFeesData, burnData]; } getAddLiquidityData( @@ -274,9 +275,9 @@ export default class UniswapV3 { deadline: Date.now() + TTL, fee: FeeAmount[fee] } - ]) + ]); - return mintData + return mintData; } async addPosition( @@ -289,14 +290,14 @@ export default class UniswapV3 { lowerPrice, upperPrice ) { - const nftContract = this.get_contract('nft', wallet) - const coreContract = this.get_contract('core', wallet) + const nftContract = this.get_contract('nft', wallet); + const coreContract = this.get_contract('core', wallet); const pool = await coreContract.getPool( token0.address, token1.address, FeeAmount[fee] - ) - const midPrice = math.fraction((lowerPrice + upperPrice) / 2) // Use mid price to initialize uninitialized pool + ); + const midPrice = math.fraction((lowerPrice + upperPrice) / 2); // Use mid price to initialize uninitialized pool const initPoolData = nftContract.interface.encodeFunctionData( 'createAndInitializePoolIfNecessary', @@ -306,7 +307,7 @@ export default class UniswapV3 { FeeAmount[fee], encodePriceSqrt(midPrice.n, midPrice.d) ] - ) + ); const mintData = this.getAddLiquidityData( wallet, @@ -318,30 +319,30 @@ export default class UniswapV3 { fee, lowerPrice, upperPrice - ) + ); - const calls = [mintData] + const calls = [mintData]; if (pool === ethers.constants.AddressZero) { const tx = await nftContract.multicall([initPoolData, mintData], { gasLimit: GAS_LIMIT - }) - return tx + }); + return tx; } - const tx = await nftContract.multicall(calls, { gasLimit: GAS_LIMIT }) - return tx + const tx = await nftContract.multicall(calls, { gasLimit: GAS_LIMIT }); + return tx; } async removePosition(wallet, tokenId) { // Reduce position and burn - const positionData = await this.getPosition(wallet, tokenId) - const contract = this.get_contract('nft', wallet) + const positionData = await this.getPosition(wallet, tokenId); + const contract = this.get_contract('nft', wallet); const data = this.getRemoveLiquidityData( wallet, contract, tokenId, positionData.liquidity - ) - return contract.multicall(data, { gasLimit: GAS_LIMIT }) + ); + return contract.multicall(data, { gasLimit: GAS_LIMIT }); } async replacePosition( @@ -355,14 +356,14 @@ export default class UniswapV3 { lowerPrice, upperPrice ) { - const contract = this.get_contract('nft', wallet) - const positionData = await this.getPosition(wallet, tokenId) + const contract = this.get_contract('nft', wallet); + const positionData = await this.getPosition(wallet, tokenId); const removeData = this.getRemoveLiquidityData( wallet, contract, tokenId, positionData.liquidity - ) + ); const mintData = this.getAddLiquidityData( wallet, contract, @@ -373,15 +374,15 @@ export default class UniswapV3 { fee, lowerPrice, upperPrice - ) + ); return contract.multicall(removeData.concat(mintData), { gasLimit: GAS_LIMIT - }) + }); } async collectFees(wallet, tokenId) { - const contract = this.get_contract('nft', wallet) + const contract = this.get_contract('nft', wallet); return contract.collect( { tokenId, @@ -390,6 +391,6 @@ export default class UniswapV3 { amount1Max: MaxUint128 }, { gasLimit: GAS_LIMIT } - ) + ); } } diff --git a/src/services/utils.js b/src/services/utils.js index bb7124c..c161b45 100644 --- a/src/services/utils.js +++ b/src/services/utils.js @@ -1,9 +1,9 @@ /* Hummingbot Utils */ -const lodash = require('lodash') -const moment = require('moment') -const { NonceManager } = require('@ethersproject/experimental') +const lodash = require('lodash'); +const moment = require('moment'); +const { NonceManager } = require('@ethersproject/experimental'); export const statusMessages = { ssl_cert_required: 'SSL Certificate required', @@ -13,21 +13,21 @@ export const statusMessages = { invalid_token_symbol: 'Invalid Token Symbol', insufficient_reserves: 'Insufficient Liquidity Reserves', page_not_found: 'Page not found. Invalid path' -} +}; export const latency = (startTime, endTime) => - parseFloat((endTime - startTime) / 1000) + parseFloat((endTime - startTime) / 1000); export const isValidParams = (params) => { - const values = Object.values(params) + const values = Object.values(params); // DO NOT use forEach, it returns callback without breaking the loop for (let i = 0; i < values.length; i++) { if (typeof values[i] === 'undefined') { - throw new Error('Invalid input params') + throw new Error('Invalid input params'); } } - return true -} + return true; +}; export const isValidData = (data, format) => { if ( @@ -35,58 +35,58 @@ export const isValidData = (data, format) => { Object.keys(data).length !== 0 && lodash.isEqual(Object.keys(data).sort(), format.sort()) ) { - return true + return true; } - return false -} + return false; +}; export const getParamData = (data, format = null) => { - const dataObject = {} + const dataObject = {}; if (format !== null) { if (isValidData(data, format)) { format.forEach((key, _index) => { - dataObject[key] = data[key] - }) + dataObject[key] = data[key]; + }); } } else { Object.keys(data).forEach((key, _index) => { - dataObject[key] = data[key] - }) + dataObject[key] = data[key]; + }); } - return dataObject -} + return dataObject; +}; export const splitParamData = (param, separator = ',') => { - const dataArray = param.split(separator) - return dataArray -} + const dataArray = param.split(separator); + return dataArray; +}; export const getSymbols = (tradingPair) => { - const symbols = tradingPair.split('-') + const symbols = tradingPair.split('-'); const baseQuotePair = { base: symbols[0].toUpperCase(), quote: symbols[1].toUpperCase() - } - return baseQuotePair -} + }; + return baseQuotePair; +}; export const reportConnectionError = (res, error) => { res.json({ error: error.errno, code: error.code - }) -} + }); +}; -export const strToDecimal = (str) => parseInt(str) / 100 +export const strToDecimal = (str) => parseInt(str) / 100; export const getHummingbotMemo = () => { - const prefix = 'hbot' - const clientId = process.env.HUMMINGBOT_INSTANCE_ID + const prefix = 'hbot'; + const clientId = process.env.HUMMINGBOT_INSTANCE_ID; if (typeof clientId !== 'undefined' && clientId != null && clientId !== '') { - return [prefix, clientId].join('-') + return [prefix, clientId].join('-'); } - return prefix -} + return prefix; +}; export const loadConfig = () => { const config = { @@ -115,13 +115,13 @@ export const loadConfig = () => { uniswap_router: process.env.UNISWAP_ROUTER, terra_lcd_url: process.env.TERRA_LCD_URL, terra_chain: process.env.TERRA_CHAIN - } - return config -} + }; + return config; +}; export const getLocalDate = () => { - const gmtOffset = process.env.GMT_OFFSET - let newDate = moment().format('YYYY-MM-DD hh:mm:ss').trim() + const gmtOffset = process.env.GMT_OFFSET; + let newDate = moment().format('YYYY-MM-DD hh:mm:ss').trim(); if ( typeof gmtOffset !== 'undefined' && gmtOffset !== null && @@ -130,22 +130,22 @@ export const getLocalDate = () => { newDate = moment() .utcOffset(gmtOffset, false) .format('YYYY-MM-DD hh:mm:ss') - .trim() + .trim(); } - return newDate -} + return newDate; +}; -export const nonceManagerCache = {} +export const nonceManagerCache = {}; export const getNonceManager = async (signer) => { - let key = await signer.getAddress() + let key = await signer.getAddress(); if (signer.provider) { - key += (await signer.provider.getNetwork()).chainId + key += (await signer.provider.getNetwork()).chainId; } - let nonceManager = nonceManagerCache[key] + let nonceManager = nonceManagerCache[key]; if (typeof nonceManager === 'undefined') { - nonceManager = new NonceManager(signer) - nonceManagerCache[key] = nonceManager + nonceManager = new NonceManager(signer); + nonceManagerCache[key] = nonceManager; } - return nonceManager -} + return nonceManager; +}; diff --git a/src/static/abi.js b/src/static/abi.js index ec06099..439080b 100644 --- a/src/static/abi.js +++ b/src/static/abi.js @@ -221,7 +221,7 @@ const ERC20Abi = [ name: 'Transfer', type: 'event' } -] +]; const KovanWETHAbi = [ { @@ -375,12 +375,12 @@ const KovanWETHAbi = [ name: 'Withdrawal', type: 'event' } -] +]; -const KovanFaucetAddress = '0xb48Cc42C45d262534e46d5965a9Ac496F1B7a830' +const KovanFaucetAddress = '0xb48Cc42C45d262534e46d5965a9Ac496F1B7a830'; module.exports = { ERC20Abi, KovanWETHAbi, KovanFaucetAddress -} +}; diff --git a/src/static/uniswap-v3/helper_functions.js b/src/static/uniswap-v3/helper_functions.js index 6015333..7cc3ae1 100644 --- a/src/static/uniswap-v3/helper_functions.js +++ b/src/static/uniswap-v3/helper_functions.js @@ -1,24 +1,24 @@ -import bn from 'bignumber.js' -import JSBI from 'jsbi' -import { BigNumber, mulShift, Q32, ZERO, ONE, MaxUint256 } from 'ethers' +import bn from 'bignumber.js'; +import JSBI from 'jsbi'; +import { BigNumber, mulShift, Q32, ZERO, ONE, MaxUint256 } from 'ethers'; -const math = require('mathjs') +const math = require('mathjs'); -const TICK_SPACINGS = { LOW: 10, MEDIUM: 60, HIGH: 2000 } +const TICK_SPACINGS = { LOW: 10, MEDIUM: 60, HIGH: 2000 }; -bn.config({ EXPONENTIAL_AT: 999999, DECIMAL_PLACES: 40 }) +bn.config({ EXPONENTIAL_AT: 999999, DECIMAL_PLACES: 40 }); export function expandTo18Decimals(n) { - return BigNumber.from(n).mul(BigNumber.from(10).pow(18)) + return BigNumber.from(n).mul(BigNumber.from(10).pow(18)); } export function toHex(bigintIsh) { - const bigInt = JSBI.BigInt(bigintIsh) - let hex = bigInt.toString(16) + const bigInt = JSBI.BigInt(bigintIsh); + let hex = bigInt.toString(16); if (hex.length % 2 !== 0) { - hex = `0${hex}` + hex = `0${hex}`; } - return `0x${hex}` + return `0x${hex}`; } // returns the sqrt price as a 64x96 @@ -30,7 +30,7 @@ export function encodePriceSqrt(reserve1, reserve0) { .multipliedBy(new bn(2).pow(96)) .integerValue(3) .toString() - ) + ); } export function getLiquidity(amount0, amount1) { @@ -39,7 +39,7 @@ export function getLiquidity(amount0, amount1) { .multipliedBy(amount1.toString()) .sqrt() .toString() - ) + ); /* let tokenPrice0, tokenPrice1, tokenFraction; tokenFraction = math.fraction(amount1/amount0) tokenPrice0 = encodePriceSqrt(tokenFraction.n, tokenFraction.d) @@ -47,106 +47,106 @@ export function getLiquidity(amount0, amount1) { return tokenPrice0.mul(tokenPrice1) */ } -const TWO = JSBI.BigInt(2) +const TWO = JSBI.BigInt(2); const POWERS_OF_2 = [128, 64, 32, 16, 8, 4, 2, 1].map((pow) => [ pow, JSBI.exponentiate(TWO, JSBI.BigInt(pow)) -]) +]); export function mostSignificantBit(x) { - let y = x - let msb = 0 + let y = x; + let msb = 0; for (const [power, min] of POWERS_OF_2) { if (JSBI.greaterThanOrEqual(y, min)) { - y = JSBI.signedRightShift(y, JSBI.BigInt(power)) - msb += power + y = JSBI.signedRightShift(y, JSBI.BigInt(power)); + msb += power; } } - return msb + return msb; } export function getSqrtRatioAtTick(tick) { - const absTick = tick < 0 ? tick * -1 : tick + const absTick = tick < 0 ? tick * -1 : tick; let ratio = (absTick & 0x1) !== 0 ? JSBI.BigInt('0xfffcb933bd6fad37aa2d162d1a594001') - : JSBI.BigInt('0x100000000000000000000000000000000') + : JSBI.BigInt('0x100000000000000000000000000000000'); if ((absTick & 0x2) !== 0) - ratio = mulShift(ratio, '0xfff97272373d413259a46990580e213a') + ratio = mulShift(ratio, '0xfff97272373d413259a46990580e213a'); if ((absTick & 0x4) !== 0) - ratio = mulShift(ratio, '0xfff2e50f5f656932ef12357cf3c7fdcc') + ratio = mulShift(ratio, '0xfff2e50f5f656932ef12357cf3c7fdcc'); if ((absTick & 0x8) !== 0) - ratio = mulShift(ratio, '0xffe5caca7e10e4e61c3624eaa0941cd0') + ratio = mulShift(ratio, '0xffe5caca7e10e4e61c3624eaa0941cd0'); if ((absTick & 0x10) !== 0) - ratio = mulShift(ratio, '0xffcb9843d60f6159c9db58835c926644') + ratio = mulShift(ratio, '0xffcb9843d60f6159c9db58835c926644'); if ((absTick & 0x20) !== 0) - ratio = mulShift(ratio, '0xff973b41fa98c081472e6896dfb254c0') + ratio = mulShift(ratio, '0xff973b41fa98c081472e6896dfb254c0'); if ((absTick & 0x40) !== 0) - ratio = mulShift(ratio, '0xff2ea16466c96a3843ec78b326b52861') + ratio = mulShift(ratio, '0xff2ea16466c96a3843ec78b326b52861'); if ((absTick & 0x80) !== 0) - ratio = mulShift(ratio, '0xfe5dee046a99a2a811c461f1969c3053') + ratio = mulShift(ratio, '0xfe5dee046a99a2a811c461f1969c3053'); if ((absTick & 0x100) !== 0) - ratio = mulShift(ratio, '0xfcbe86c7900a88aedcffc83b479aa3a4') + ratio = mulShift(ratio, '0xfcbe86c7900a88aedcffc83b479aa3a4'); if ((absTick & 0x200) !== 0) - ratio = mulShift(ratio, '0xf987a7253ac413176f2b074cf7815e54') + ratio = mulShift(ratio, '0xf987a7253ac413176f2b074cf7815e54'); if ((absTick & 0x400) !== 0) - ratio = mulShift(ratio, '0xf3392b0822b70005940c7a398e4b70f3') + ratio = mulShift(ratio, '0xf3392b0822b70005940c7a398e4b70f3'); if ((absTick & 0x800) !== 0) - ratio = mulShift(ratio, '0xe7159475a2c29b7443b29c7fa6e889d9') + ratio = mulShift(ratio, '0xe7159475a2c29b7443b29c7fa6e889d9'); if ((absTick & 0x1000) !== 0) - ratio = mulShift(ratio, '0xd097f3bdfd2022b8845ad8f792aa5825') + ratio = mulShift(ratio, '0xd097f3bdfd2022b8845ad8f792aa5825'); if ((absTick & 0x2000) !== 0) - ratio = mulShift(ratio, '0xa9f746462d870fdf8a65dc1f90e061e5') + ratio = mulShift(ratio, '0xa9f746462d870fdf8a65dc1f90e061e5'); if ((absTick & 0x4000) !== 0) - ratio = mulShift(ratio, '0x70d869a156d2a1b890bb3df62baf32f7') + ratio = mulShift(ratio, '0x70d869a156d2a1b890bb3df62baf32f7'); if ((absTick & 0x8000) !== 0) - ratio = mulShift(ratio, '0x31be135f97d08fd981231505542fcfa6') + ratio = mulShift(ratio, '0x31be135f97d08fd981231505542fcfa6'); if ((absTick & 0x10000) !== 0) - ratio = mulShift(ratio, '0x9aa508b5b7a84e1c677de54f3e99bc9') + ratio = mulShift(ratio, '0x9aa508b5b7a84e1c677de54f3e99bc9'); if ((absTick & 0x20000) !== 0) - ratio = mulShift(ratio, '0x5d6af8dedb81196699c329225ee604') + ratio = mulShift(ratio, '0x5d6af8dedb81196699c329225ee604'); if ((absTick & 0x40000) !== 0) - ratio = mulShift(ratio, '0x2216e584f5fa1ea926041bedfe98') + ratio = mulShift(ratio, '0x2216e584f5fa1ea926041bedfe98'); if ((absTick & 0x80000) !== 0) - ratio = mulShift(ratio, '0x48a170391f7dc42444e8fa2') + ratio = mulShift(ratio, '0x48a170391f7dc42444e8fa2'); - if (tick > 0) ratio = JSBI.divide(MaxUint256, ratio) + if (tick > 0) ratio = JSBI.divide(MaxUint256, ratio); // back to Q96 return JSBI.greaterThan(JSBI.remainder(ratio, Q32), ZERO) ? JSBI.add(JSBI.divide(ratio, Q32), ONE) - : JSBI.divide(ratio, Q32) + : JSBI.divide(ratio, Q32); } export function getTickAtSqrtRatio(sqrtRatioX96) { - const sqrtRatioX128 = JSBI.leftShift(sqrtRatioX96, JSBI.BigInt(32)) + const sqrtRatioX128 = JSBI.leftShift(sqrtRatioX96, JSBI.BigInt(32)); - const msb = mostSignificantBit(sqrtRatioX128) + const msb = mostSignificantBit(sqrtRatioX128); - let r + let r; if (JSBI.greaterThanOrEqual(JSBI.BigInt(msb), JSBI.BigInt(128))) { - r = JSBI.signedRightShift(sqrtRatioX128, JSBI.BigInt(msb - 127)) + r = JSBI.signedRightShift(sqrtRatioX128, JSBI.BigInt(msb - 127)); } else { - r = JSBI.leftShift(sqrtRatioX128, JSBI.BigInt(127 - msb)) + r = JSBI.leftShift(sqrtRatioX128, JSBI.BigInt(127 - msb)); } let log_2 = JSBI.leftShift( JSBI.subtract(JSBI.BigInt(msb), JSBI.BigInt(128)), JSBI.BigInt(64) - ) + ); for (let i = 0; i < 14; i++) { - r = JSBI.signedRightShift(JSBI.multiply(r, r), JSBI.BigInt(127)) - const f = JSBI.signedRightShift(r, JSBI.BigInt(128)) - log_2 = JSBI.bitwiseOr(log_2, JSBI.leftShift(f, JSBI.BigInt(63 - i))) - r = JSBI.signedRightShift(r, f) + r = JSBI.signedRightShift(JSBI.multiply(r, r), JSBI.BigInt(127)); + const f = JSBI.signedRightShift(r, JSBI.BigInt(128)); + log_2 = JSBI.bitwiseOr(log_2, JSBI.leftShift(f, JSBI.BigInt(63 - i))); + r = JSBI.signedRightShift(r, f); } const log_sqrt10001 = JSBI.multiply( log_2, JSBI.BigInt('255738958999603826347141') - ) + ); const tickLow = JSBI.toNumber( JSBI.signedRightShift( @@ -156,7 +156,7 @@ export function getTickAtSqrtRatio(sqrtRatioX96) { ), JSBI.BigInt(128) ) - ) + ); const tickHigh = JSBI.toNumber( JSBI.signedRightShift( JSBI.add( @@ -165,42 +165,42 @@ export function getTickAtSqrtRatio(sqrtRatioX96) { ), JSBI.BigInt(128) ) - ) + ); if (tickLow === tickHigh) { - return tickLow + return tickLow; } return JSBI.lessThanOrEqual(getSqrtRatioAtTick(tickHigh), sqrtRatioX96) ? tickHigh - : tickLow + : tickLow; } export function getMinTick(tier) { - return Math.ceil(-887272 / TICK_SPACINGS[tier]) * TICK_SPACINGS[tier] + return Math.ceil(-887272 / TICK_SPACINGS[tier]) * TICK_SPACINGS[tier]; } export function getMaxTick(tier) { - return Math.floor(887272 / TICK_SPACINGS[tier]) * TICK_SPACINGS[tier] + return Math.floor(887272 / TICK_SPACINGS[tier]) * TICK_SPACINGS[tier]; } export function getTickFromPrice(price, tier, side) { - let tick = 0 + let tick = 0; if (side === 'UPPER') { tick = math.ceil(math.log(price, 1.0001) / TICK_SPACINGS[tier]) * - TICK_SPACINGS[tier] + TICK_SPACINGS[tier]; } else { tick = math.floor(math.log(price, 1.0001) / TICK_SPACINGS[tier]) * - TICK_SPACINGS[tier] + TICK_SPACINGS[tier]; } if (tick >= getMaxTick(tier)) { - return getMaxTick(tier) + return getMaxTick(tier); } if (tick <= getMinTick(tier)) { - return getMinTick(tier) + return getMinTick(tier); } - return tick + return tick; } diff --git a/yarn.lock b/yarn.lock index 5435848..5190a68 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,7 +9,7 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.12.13": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== @@ -271,7 +271,7 @@ regenerator-runtime "^0.13.4" v8flags "^3.1.1" -"@babel/parser@^7.12.13", "@babel/parser@^7.14.2", "@babel/parser@^7.14.3": +"@babel/parser@^7.12.13", "@babel/parser@^7.14.2", "@babel/parser@^7.14.3", "@babel/parser@^7.7.0": version "7.14.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.4.tgz#a5c560d6db6cd8e6ed342368dea8039232cbab18" integrity sha512-ArliyUsWDUqEGfWcmzpGUzNfLxTdTp6WU4IuP6QFSp9gGfWS6boxFCkJSJ/L4+RG8z/FnIU3WxCk6hPL9SSWeA== @@ -876,7 +876,7 @@ "@babel/parser" "^7.12.13" "@babel/types" "^7.12.13" -"@babel/traverse@^7.13.0", "@babel/traverse@^7.13.15", "@babel/traverse@^7.14.0", "@babel/traverse@^7.14.2": +"@babel/traverse@^7.13.0", "@babel/traverse@^7.13.15", "@babel/traverse@^7.14.0", "@babel/traverse@^7.14.2", "@babel/traverse@^7.7.0": version "7.14.2" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.2.tgz#9201a8d912723a831c2679c7ebbf2fe1416d765b" integrity sha512-TsdRgvBFHMyHOOzcP9S6QU0QQtjxlRpEYOy3mcCO5RgmC305ki42aSAmfZEMSSYBla2oZ9BMqYlncBaKmD/7iA== @@ -890,7 +890,7 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.16", "@babel/types@^7.14.0", "@babel/types@^7.14.2", "@babel/types@^7.14.4", "@babel/types@^7.4.4": +"@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.13.12", "@babel/types@^7.13.16", "@babel/types@^7.14.0", "@babel/types@^7.14.2", "@babel/types@^7.14.4", "@babel/types@^7.4.4", "@babel/types@^7.7.0": version "7.14.4" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.4.tgz#bfd6980108168593b38b3eb48a24aa026b919bc0" integrity sha512-lCj4aIs0xUefJFQnwwQv2Bxg7Omd6bgquZ6LGC+gGMh6/s5qDVfjuCMlDmYQ15SLsWHd9n+X3E75lKIhl5Lkiw== @@ -1594,6 +1594,18 @@ axios@^0.21.1: dependencies: follow-redirects "^1.10.0" +babel-eslint@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" + integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + eslint-visitor-keys "^1.0.0" + resolve "^1.12.0" + babel-plugin-dynamic-import-node@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" @@ -2015,11 +2027,6 @@ configstore@^5.0.1: write-file-atomic "^3.0.0" xdg-basedir "^4.0.0" -confusing-browser-globals@^1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz#30d1e7f3d1b882b25ec4933d1d1adac353d20a59" - integrity sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA== - content-disposition@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" @@ -2359,24 +2366,15 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-config-airbnb-base@^14.2.1: - version "14.2.1" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz#8a2eb38455dc5a312550193b319cdaeef042cd1e" - integrity sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA== - dependencies: - confusing-browser-globals "^1.0.10" - object.assign "^4.1.2" - object.entries "^1.1.2" - eslint-config-prettier@^8.3.0: version "8.3.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew== -eslint-config-standard@^14.1.1: - version "14.1.1" - resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea" - integrity sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg== +eslint-config-standard@^16.0.3: + version "16.0.3" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz#6c8761e544e96c531ff92642eeb87842b8488516" + integrity sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg== eslint-import-resolver-node@^0.3.4: version "0.3.4" @@ -2402,7 +2400,7 @@ eslint-plugin-es@^3.0.0: eslint-utils "^2.0.0" regexpp "^3.0.0" -eslint-plugin-import@^2.23.3: +eslint-plugin-import@^2.23.4: version "2.23.4" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz#8dceb1ed6b73e46e50ec9a5bb2411b645e7d3d97" integrity sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ== @@ -2442,10 +2440,10 @@ eslint-plugin-prettier@^3.4.0: dependencies: prettier-linter-helpers "^1.0.0" -eslint-plugin-promise@^4.2.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz#61485df2a359e03149fdafc0a68b0e030ad2ac45" - integrity sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ== +eslint-plugin-promise@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-5.1.0.tgz#fb2188fb734e4557993733b41aa1a688f46c6f24" + integrity sha512-NGmI6BH5L12pl7ScQHbg7tvtk4wPxxj8yPHH47NvSmMtFneC077PSeY3huFj06ZWZvtbfxSPt3RuOQD5XcR4ng== eslint-plugin-standard@^4.0.1: version "4.1.0" @@ -2467,7 +2465,7 @@ eslint-utils@^2.0.0, eslint-utils@^2.1.0: dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== @@ -3822,15 +3820,6 @@ object.assign@^4.1.0, object.assign@^4.1.2: has-symbols "^1.0.1" object-keys "^1.1.1" -object.entries@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.4.tgz#43ccf9a50bc5fd5b649d45ab1a579f24e088cafd" - integrity sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.2" - object.getownpropertydescriptors@^2.0.3: version "2.1.2" resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz#1bd63aeacf0d5d2d2f31b5e393b03a7c601a23f7" @@ -4305,7 +4294,7 @@ resolve-from@^4.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.10.0, resolve@^1.10.1, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.20.0: +resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.20.0: version "1.20.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== From e41020ba434faf3f767a8e12a6d026fda83318be Mon Sep 17 00:00:00 2001 From: james-hummingbot Date: Fri, 4 Jun 2021 10:21:50 +0200 Subject: [PATCH 6/7] Apply prettier to test files --- .prettierignore | 1 - package.json | 2 +- ...eway-Ethereum-Base.postman_collection.json | 2441 ++++++++--------- .../Gateway-Terra.postman_collection.json | 635 +++-- test/postman/PERPFI.postman_collection.json | 836 +++--- .../Uniswap_V3_postman_collection.json | 960 +++---- test/postman/terra.postman_environment.json | 56 +- .../v2/Gateway.postman_collection.json | 1875 ++++++------- .../v2/Gateway.postman_environment.json | 66 +- 9 files changed, 3249 insertions(+), 3623 deletions(-) diff --git a/.prettierignore b/.prettierignore index b4d36e3..426ed2f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,3 @@ -test certs *.md *.yml \ No newline at end of file diff --git a/package.json b/package.json index 55933c6..bedb73a 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "start": "babel-node src/index.js", "dev": "nodemon --exec babel-node src/index.js", "debug": "DEBUG=*router nodemon --exec babel-node src/index.js", - "lint": "node_modules/.bin/eslint src --format table", + "lint": "node_modules/.bin/eslint src test --format table", "prettier": "node_modules/.bin/prettier . --write", "test": "echo \"Error: no test specified\" && exit 1" }, diff --git a/test/postman/Gateway-Ethereum-Base.postman_collection.json b/test/postman/Gateway-Ethereum-Base.postman_collection.json index 20622ac..1910611 100644 --- a/test/postman/Gateway-Ethereum-Base.postman_collection.json +++ b/test/postman/Gateway-Ethereum-Base.postman_collection.json @@ -1,1264 +1,1179 @@ { - "info": { - "_postman_id": "e39af94e-6095-479e-8ba0-66930b12e364", - "name": "Gateway-Ethereum-Base", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "ethereum", - "item": [ - { - "name": "eth/balances", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "tokenAddressList", - "value": "{ \"{{WETH}}\": 18, \"{{DAI}}\": 18}", - "type": "text" - }, - { - "key": "connector", - "value": "balancer", - "type": "text" - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/balances", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "balances" - ] - } - }, - "response": [] - }, - { - "name": "eth/allowances", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "tokenAddressList", - "value": "{ \"{{BAT}}\": 18, \"{{DAI}}\": 18 }", - "type": "text" - }, - { - "key": "connector", - "value": "balancer", - "type": "text" - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - } - ], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/eth/allowances", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "allowances" - ] - } - }, - "response": [] - }, - { - "name": "eth/approve", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "tokenAddress", - "value": "{{WETH}}", - "type": "text" - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "gasPrice", - "value": "23", - "type": "text" - }, - { - "key": "decimals", - "value": "18", - "type": "text" - }, - { - "key": "connector", - "value": "balancer", - "type": "text" - }, - { - "key": "amount", - "value": "999999", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/approve", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "approve" - ] - } - }, - "response": [] - }, - { - "name": "eth/get-weth", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "gasPrice", - "value": "31", - "type": "text" - }, - { - "key": "amount", - "value": "0.03", - "type": "text" - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "tokenAddress", - "value": "{{WETH}}", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/get-weth", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "get-weth" - ] - } - }, - "response": [] - }, - { - "name": "eth/get-receipt", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "txHash", - "value": "{{txHash}}", - "type": "text" - } - ], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/eth/get-receipt", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "get-receipt" - ] - } - }, - "response": [] - } - ], - "protocolProfileBehavior": {} - }, - { - "name": "balancer", - "item": [ - { - "name": "balancer", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/balancer", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "balancer" - ] - } - }, - "response": [] - }, - { - "name": "balancer/gas-limit", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "maxSwaps", - "value": "3", - "type": "text" - } - ], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/balancer/gas-limit", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "balancer", - "gas-limit" - ] - } - }, - "response": [] - }, - { - "name": "balancer/buy-price/", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "{{BAT}}", - "type": "text" - }, - { - "key": "quote", - "value": "{{DAI}}", - "type": "text" - }, - { - "key": "amount", - "value": "10", - "type": "text" - }, - { - "key": "maxSwaps", - "value": "4", - "type": "text" - }, - { - "key": "base_decimals", - "value": "18", - "type": "text" - }, - { - "key": "quote_decimals", - "value": "18", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/balancer/buy-price", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "balancer", - "buy-price" - ] - } - }, - "response": [ - { - "name": "{network}/quote", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "http://localhost:5000/{{network}}/quote/trading_pair/{{celo-cusd}}/amount/1", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "5000", - "path": [ - "{{network}}", - "quote", - "trading_pair", - "{{celo-cusd}}", - "amount", - "1" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Security-Policy", - "value": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" - }, - { - "key": "X-DNS-Prefetch-Control", - "value": "off" - }, - { - "key": "Expect-CT", - "value": "max-age=0" - }, - { - "key": "X-Frame-Options", - "value": "SAMEORIGIN" - }, - { - "key": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains" - }, - { - "key": "X-Download-Options", - "value": "noopen" - }, - { - "key": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "key": "X-Permitted-Cross-Domain-Policies", - "value": "none" - }, - { - "key": "Referrer-Policy", - "value": "no-referrer" - }, - { - "key": "X-XSS-Protection", - "value": "0" - }, - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Content-Length", - "value": "97" - }, - { - "key": "ETag", - "value": "W/\"61-Wemp9YmP9g/CsUFMa7Y5zK6SoLQ\"" - }, - { - "key": "Date", - "value": "Wed, 23 Sep 2020 18:07:26 GMT" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"timestamp\": 1600884444051,\n \"latency\": 2.542,\n \"trading_pair\": \"CELO-CUSD\",\n \"price\": 2.5435604641582747\n}" - } - ] - }, - { - "name": "balancer/sell-price/", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "{{BAT}}", - "type": "text" - }, - { - "key": "quote", - "value": "{{DAI}}", - "type": "text" - }, - { - "key": "amount", - "value": "10", - "type": "text" - }, - { - "key": "maxSwaps", - "value": "4", - "type": "text" - }, - { - "key": "base_decimals", - "value": "18", - "type": "text" - }, - { - "key": "quote_decimals", - "value": "18", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/balancer/sell-price", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "balancer", - "sell-price" - ] - } - }, - "response": [ - { - "name": "{network}/quote", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "http://localhost:5000/{{network}}/quote/trading_pair/{{celo-cusd}}/amount/1", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "5000", - "path": [ - "{{network}}", - "quote", - "trading_pair", - "{{celo-cusd}}", - "amount", - "1" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Security-Policy", - "value": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" - }, - { - "key": "X-DNS-Prefetch-Control", - "value": "off" - }, - { - "key": "Expect-CT", - "value": "max-age=0" - }, - { - "key": "X-Frame-Options", - "value": "SAMEORIGIN" - }, - { - "key": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains" - }, - { - "key": "X-Download-Options", - "value": "noopen" - }, - { - "key": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "key": "X-Permitted-Cross-Domain-Policies", - "value": "none" - }, - { - "key": "Referrer-Policy", - "value": "no-referrer" - }, - { - "key": "X-XSS-Protection", - "value": "0" - }, - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Content-Length", - "value": "97" - }, - { - "key": "ETag", - "value": "W/\"61-Wemp9YmP9g/CsUFMa7Y5zK6SoLQ\"" - }, - { - "key": "Date", - "value": "Wed, 23 Sep 2020 18:07:26 GMT" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"timestamp\": 1600884444051,\n \"latency\": 2.542,\n \"trading_pair\": \"CELO-CUSD\",\n \"price\": 2.5435604641582747\n}" - } - ] - }, - { - "name": "balancer/buy", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "{{BAT}}", - "type": "text" - }, - { - "key": "quote", - "value": "{{DAI}}", - "type": "text" - }, - { - "key": "amount", - "value": "1", - "type": "text" - }, - { - "key": "maxSwaps", - "value": "4", - "type": "text" - }, - { - "key": "maxPrice", - "value": "0.19767217120251", - "type": "text" - }, - { - "key": "gasPrice", - "value": "37", - "type": "text" - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "base_decimals", - "value": "18", - "type": "text" - }, - { - "key": "quote_decimals", - "value": "18", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/balancer/buy", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "balancer", - "buy" - ] - } - }, - "response": [ - { - "name": "{network}/quote", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "http://localhost:5000/{{network}}/quote/trading_pair/{{celo-cusd}}/amount/1", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "5000", - "path": [ - "{{network}}", - "quote", - "trading_pair", - "{{celo-cusd}}", - "amount", - "1" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Security-Policy", - "value": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" - }, - { - "key": "X-DNS-Prefetch-Control", - "value": "off" - }, - { - "key": "Expect-CT", - "value": "max-age=0" - }, - { - "key": "X-Frame-Options", - "value": "SAMEORIGIN" - }, - { - "key": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains" - }, - { - "key": "X-Download-Options", - "value": "noopen" - }, - { - "key": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "key": "X-Permitted-Cross-Domain-Policies", - "value": "none" - }, - { - "key": "Referrer-Policy", - "value": "no-referrer" - }, - { - "key": "X-XSS-Protection", - "value": "0" - }, - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Content-Length", - "value": "97" - }, - { - "key": "ETag", - "value": "W/\"61-Wemp9YmP9g/CsUFMa7Y5zK6SoLQ\"" - }, - { - "key": "Date", - "value": "Wed, 23 Sep 2020 18:07:26 GMT" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"timestamp\": 1600884444051,\n \"latency\": 2.542,\n \"trading_pair\": \"CELO-CUSD\",\n \"price\": 2.5435604641582747\n}" - } - ] - }, - { - "name": "balancer/sell", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "{{BAT}}", - "type": "text" - }, - { - "key": "quote", - "value": "{{DAI}}", - "type": "text" - }, - { - "key": "amount", - "value": "0.1", - "type": "text" - }, - { - "key": "maxSwaps", - "value": "4", - "type": "text" - }, - { - "key": "maxPrice", - "value": "0.2685681573104575", - "type": "text" - }, - { - "key": "gasPrice", - "value": "37", - "type": "text" - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "base_decimals", - "value": "18", - "type": "text" - }, - { - "key": "quote_decimals", - "value": "18", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/balancer/sell", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "balancer", - "sell" - ] - } - }, - "response": [ - { - "name": "{network}/quote", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "http://localhost:5000/{{network}}/quote/trading_pair/{{celo-cusd}}/amount/1", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "5000", - "path": [ - "{{network}}", - "quote", - "trading_pair", - "{{celo-cusd}}", - "amount", - "1" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Security-Policy", - "value": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" - }, - { - "key": "X-DNS-Prefetch-Control", - "value": "off" - }, - { - "key": "Expect-CT", - "value": "max-age=0" - }, - { - "key": "X-Frame-Options", - "value": "SAMEORIGIN" - }, - { - "key": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains" - }, - { - "key": "X-Download-Options", - "value": "noopen" - }, - { - "key": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "key": "X-Permitted-Cross-Domain-Policies", - "value": "none" - }, - { - "key": "Referrer-Policy", - "value": "no-referrer" - }, - { - "key": "X-XSS-Protection", - "value": "0" - }, - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Content-Length", - "value": "97" - }, - { - "key": "ETag", - "value": "W/\"61-Wemp9YmP9g/CsUFMa7Y5zK6SoLQ\"" - }, - { - "key": "Date", - "value": "Wed, 23 Sep 2020 18:07:26 GMT" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"timestamp\": 1600884444051,\n \"latency\": 2.542,\n \"trading_pair\": \"CELO-CUSD\",\n \"price\": 2.5435604641582747\n}" - } - ] - } - ], - "protocolProfileBehavior": {} - }, - { - "name": "uniswap", - "item": [ - { - "name": "uniswap", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/uniswap", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "uniswap" - ] - } - }, - "response": [] - }, - { - "name": "uniswap/gas-limit", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/uniswap/gas-limit", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "uniswap", - "gas-limit" - ] - } - }, - "response": [] - }, - { - "name": "uniswap/buy-price/", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "{{BAT}}", - "type": "text" - }, - { - "key": "quote", - "value": "{{DAI}}", - "type": "text" - }, - { - "key": "amount", - "value": "10", - "type": "text" - }, - { - "key": "base_decimals", - "value": "18", - "type": "text" - }, - { - "key": "quote_decimals", - "value": "18", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/uniswap/buy-price", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "uniswap", - "buy-price" - ] - } - }, - "response": [ - { - "name": "{network}/quote", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "http://localhost:5000/{{network}}/quote/trading_pair/{{celo-cusd}}/amount/1", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "5000", - "path": [ - "{{network}}", - "quote", - "trading_pair", - "{{celo-cusd}}", - "amount", - "1" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Security-Policy", - "value": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" - }, - { - "key": "X-DNS-Prefetch-Control", - "value": "off" - }, - { - "key": "Expect-CT", - "value": "max-age=0" - }, - { - "key": "X-Frame-Options", - "value": "SAMEORIGIN" - }, - { - "key": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains" - }, - { - "key": "X-Download-Options", - "value": "noopen" - }, - { - "key": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "key": "X-Permitted-Cross-Domain-Policies", - "value": "none" - }, - { - "key": "Referrer-Policy", - "value": "no-referrer" - }, - { - "key": "X-XSS-Protection", - "value": "0" - }, - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Content-Length", - "value": "97" - }, - { - "key": "ETag", - "value": "W/\"61-Wemp9YmP9g/CsUFMa7Y5zK6SoLQ\"" - }, - { - "key": "Date", - "value": "Wed, 23 Sep 2020 18:07:26 GMT" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"timestamp\": 1600884444051,\n \"latency\": 2.542,\n \"trading_pair\": \"CELO-CUSD\",\n \"price\": 2.5435604641582747\n}" - } - ] - }, - { - "name": "uniswap/sell-price/", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "{{BAT}}", - "type": "text" - }, - { - "key": "quote", - "value": "{{DAI}}", - "type": "text" - }, - { - "key": "amount", - "value": "10", - "type": "text" - }, - { - "key": "base_decimals", - "value": "18", - "type": "text" - }, - { - "key": "quote_decimals", - "value": "18", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/uniswap/sell-price", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "uniswap", - "sell-price" - ] - } - }, - "response": [ - { - "name": "{network}/quote", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "http://localhost:5000/{{network}}/quote/trading_pair/{{celo-cusd}}/amount/1", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "5000", - "path": [ - "{{network}}", - "quote", - "trading_pair", - "{{celo-cusd}}", - "amount", - "1" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Security-Policy", - "value": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" - }, - { - "key": "X-DNS-Prefetch-Control", - "value": "off" - }, - { - "key": "Expect-CT", - "value": "max-age=0" - }, - { - "key": "X-Frame-Options", - "value": "SAMEORIGIN" - }, - { - "key": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains" - }, - { - "key": "X-Download-Options", - "value": "noopen" - }, - { - "key": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "key": "X-Permitted-Cross-Domain-Policies", - "value": "none" - }, - { - "key": "Referrer-Policy", - "value": "no-referrer" - }, - { - "key": "X-XSS-Protection", - "value": "0" - }, - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Content-Length", - "value": "97" - }, - { - "key": "ETag", - "value": "W/\"61-Wemp9YmP9g/CsUFMa7Y5zK6SoLQ\"" - }, - { - "key": "Date", - "value": "Wed, 23 Sep 2020 18:07:26 GMT" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"timestamp\": 1600884444051,\n \"latency\": 2.542,\n \"trading_pair\": \"CELO-CUSD\",\n \"price\": 2.5435604641582747\n}" - } - ] - } - ], - "protocolProfileBehavior": {} - } - ], - "protocolProfileBehavior": {} -} \ No newline at end of file + "info": { + "_postman_id": "e39af94e-6095-479e-8ba0-66930b12e364", + "name": "Gateway-Ethereum-Base", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "ethereum", + "item": [ + { + "name": "eth/balances", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "tokenAddressList", + "value": "{ \"{{WETH}}\": 18, \"{{DAI}}\": 18}", + "type": "text" + }, + { + "key": "connector", + "value": "balancer", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/balances", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "balances"] + } + }, + "response": [] + }, + { + "name": "eth/allowances", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "tokenAddressList", + "value": "{ \"{{BAT}}\": 18, \"{{DAI}}\": 18 }", + "type": "text" + }, + { + "key": "connector", + "value": "balancer", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + } + ], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/eth/allowances", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "allowances"] + } + }, + "response": [] + }, + { + "name": "eth/approve", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "tokenAddress", + "value": "{{WETH}}", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "gasPrice", + "value": "23", + "type": "text" + }, + { + "key": "decimals", + "value": "18", + "type": "text" + }, + { + "key": "connector", + "value": "balancer", + "type": "text" + }, + { + "key": "amount", + "value": "999999", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/approve", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "approve"] + } + }, + "response": [] + }, + { + "name": "eth/get-weth", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "gasPrice", + "value": "31", + "type": "text" + }, + { + "key": "amount", + "value": "0.03", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "tokenAddress", + "value": "{{WETH}}", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/get-weth", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "get-weth"] + } + }, + "response": [] + }, + { + "name": "eth/get-receipt", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "txHash", + "value": "{{txHash}}", + "type": "text" + } + ], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/eth/get-receipt", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "get-receipt"] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "balancer", + "item": [ + { + "name": "balancer", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/balancer", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["balancer"] + } + }, + "response": [] + }, + { + "name": "balancer/gas-limit", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "maxSwaps", + "value": "3", + "type": "text" + } + ], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/balancer/gas-limit", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["balancer", "gas-limit"] + } + }, + "response": [] + }, + { + "name": "balancer/buy-price/", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "{{BAT}}", + "type": "text" + }, + { + "key": "quote", + "value": "{{DAI}}", + "type": "text" + }, + { + "key": "amount", + "value": "10", + "type": "text" + }, + { + "key": "maxSwaps", + "value": "4", + "type": "text" + }, + { + "key": "base_decimals", + "value": "18", + "type": "text" + }, + { + "key": "quote_decimals", + "value": "18", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/balancer/buy-price", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["balancer", "buy-price"] + } + }, + "response": [ + { + "name": "{network}/quote", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:5000/{{network}}/quote/trading_pair/{{celo-cusd}}/amount/1", + "protocol": "http", + "host": ["localhost"], + "port": "5000", + "path": [ + "{{network}}", + "quote", + "trading_pair", + "{{celo-cusd}}", + "amount", + "1" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Security-Policy", + "value": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" + }, + { + "key": "X-DNS-Prefetch-Control", + "value": "off" + }, + { + "key": "Expect-CT", + "value": "max-age=0" + }, + { + "key": "X-Frame-Options", + "value": "SAMEORIGIN" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15552000; includeSubDomains" + }, + { + "key": "X-Download-Options", + "value": "noopen" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-Permitted-Cross-Domain-Policies", + "value": "none" + }, + { + "key": "Referrer-Policy", + "value": "no-referrer" + }, + { + "key": "X-XSS-Protection", + "value": "0" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "97" + }, + { + "key": "ETag", + "value": "W/\"61-Wemp9YmP9g/CsUFMa7Y5zK6SoLQ\"" + }, + { + "key": "Date", + "value": "Wed, 23 Sep 2020 18:07:26 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"timestamp\": 1600884444051,\n \"latency\": 2.542,\n \"trading_pair\": \"CELO-CUSD\",\n \"price\": 2.5435604641582747\n}" + } + ] + }, + { + "name": "balancer/sell-price/", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "{{BAT}}", + "type": "text" + }, + { + "key": "quote", + "value": "{{DAI}}", + "type": "text" + }, + { + "key": "amount", + "value": "10", + "type": "text" + }, + { + "key": "maxSwaps", + "value": "4", + "type": "text" + }, + { + "key": "base_decimals", + "value": "18", + "type": "text" + }, + { + "key": "quote_decimals", + "value": "18", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/balancer/sell-price", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["balancer", "sell-price"] + } + }, + "response": [ + { + "name": "{network}/quote", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:5000/{{network}}/quote/trading_pair/{{celo-cusd}}/amount/1", + "protocol": "http", + "host": ["localhost"], + "port": "5000", + "path": [ + "{{network}}", + "quote", + "trading_pair", + "{{celo-cusd}}", + "amount", + "1" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Security-Policy", + "value": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" + }, + { + "key": "X-DNS-Prefetch-Control", + "value": "off" + }, + { + "key": "Expect-CT", + "value": "max-age=0" + }, + { + "key": "X-Frame-Options", + "value": "SAMEORIGIN" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15552000; includeSubDomains" + }, + { + "key": "X-Download-Options", + "value": "noopen" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-Permitted-Cross-Domain-Policies", + "value": "none" + }, + { + "key": "Referrer-Policy", + "value": "no-referrer" + }, + { + "key": "X-XSS-Protection", + "value": "0" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "97" + }, + { + "key": "ETag", + "value": "W/\"61-Wemp9YmP9g/CsUFMa7Y5zK6SoLQ\"" + }, + { + "key": "Date", + "value": "Wed, 23 Sep 2020 18:07:26 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"timestamp\": 1600884444051,\n \"latency\": 2.542,\n \"trading_pair\": \"CELO-CUSD\",\n \"price\": 2.5435604641582747\n}" + } + ] + }, + { + "name": "balancer/buy", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "{{BAT}}", + "type": "text" + }, + { + "key": "quote", + "value": "{{DAI}}", + "type": "text" + }, + { + "key": "amount", + "value": "1", + "type": "text" + }, + { + "key": "maxSwaps", + "value": "4", + "type": "text" + }, + { + "key": "maxPrice", + "value": "0.19767217120251", + "type": "text" + }, + { + "key": "gasPrice", + "value": "37", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "base_decimals", + "value": "18", + "type": "text" + }, + { + "key": "quote_decimals", + "value": "18", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/balancer/buy", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["balancer", "buy"] + } + }, + "response": [ + { + "name": "{network}/quote", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:5000/{{network}}/quote/trading_pair/{{celo-cusd}}/amount/1", + "protocol": "http", + "host": ["localhost"], + "port": "5000", + "path": [ + "{{network}}", + "quote", + "trading_pair", + "{{celo-cusd}}", + "amount", + "1" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Security-Policy", + "value": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" + }, + { + "key": "X-DNS-Prefetch-Control", + "value": "off" + }, + { + "key": "Expect-CT", + "value": "max-age=0" + }, + { + "key": "X-Frame-Options", + "value": "SAMEORIGIN" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15552000; includeSubDomains" + }, + { + "key": "X-Download-Options", + "value": "noopen" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-Permitted-Cross-Domain-Policies", + "value": "none" + }, + { + "key": "Referrer-Policy", + "value": "no-referrer" + }, + { + "key": "X-XSS-Protection", + "value": "0" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "97" + }, + { + "key": "ETag", + "value": "W/\"61-Wemp9YmP9g/CsUFMa7Y5zK6SoLQ\"" + }, + { + "key": "Date", + "value": "Wed, 23 Sep 2020 18:07:26 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"timestamp\": 1600884444051,\n \"latency\": 2.542,\n \"trading_pair\": \"CELO-CUSD\",\n \"price\": 2.5435604641582747\n}" + } + ] + }, + { + "name": "balancer/sell", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "{{BAT}}", + "type": "text" + }, + { + "key": "quote", + "value": "{{DAI}}", + "type": "text" + }, + { + "key": "amount", + "value": "0.1", + "type": "text" + }, + { + "key": "maxSwaps", + "value": "4", + "type": "text" + }, + { + "key": "maxPrice", + "value": "0.2685681573104575", + "type": "text" + }, + { + "key": "gasPrice", + "value": "37", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "base_decimals", + "value": "18", + "type": "text" + }, + { + "key": "quote_decimals", + "value": "18", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/balancer/sell", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["balancer", "sell"] + } + }, + "response": [ + { + "name": "{network}/quote", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:5000/{{network}}/quote/trading_pair/{{celo-cusd}}/amount/1", + "protocol": "http", + "host": ["localhost"], + "port": "5000", + "path": [ + "{{network}}", + "quote", + "trading_pair", + "{{celo-cusd}}", + "amount", + "1" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Security-Policy", + "value": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" + }, + { + "key": "X-DNS-Prefetch-Control", + "value": "off" + }, + { + "key": "Expect-CT", + "value": "max-age=0" + }, + { + "key": "X-Frame-Options", + "value": "SAMEORIGIN" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15552000; includeSubDomains" + }, + { + "key": "X-Download-Options", + "value": "noopen" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-Permitted-Cross-Domain-Policies", + "value": "none" + }, + { + "key": "Referrer-Policy", + "value": "no-referrer" + }, + { + "key": "X-XSS-Protection", + "value": "0" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "97" + }, + { + "key": "ETag", + "value": "W/\"61-Wemp9YmP9g/CsUFMa7Y5zK6SoLQ\"" + }, + { + "key": "Date", + "value": "Wed, 23 Sep 2020 18:07:26 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"timestamp\": 1600884444051,\n \"latency\": 2.542,\n \"trading_pair\": \"CELO-CUSD\",\n \"price\": 2.5435604641582747\n}" + } + ] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "uniswap", + "item": [ + { + "name": "uniswap", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/uniswap", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["uniswap"] + } + }, + "response": [] + }, + { + "name": "uniswap/gas-limit", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/uniswap/gas-limit", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["uniswap", "gas-limit"] + } + }, + "response": [] + }, + { + "name": "uniswap/buy-price/", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "{{BAT}}", + "type": "text" + }, + { + "key": "quote", + "value": "{{DAI}}", + "type": "text" + }, + { + "key": "amount", + "value": "10", + "type": "text" + }, + { + "key": "base_decimals", + "value": "18", + "type": "text" + }, + { + "key": "quote_decimals", + "value": "18", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/uniswap/buy-price", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["uniswap", "buy-price"] + } + }, + "response": [ + { + "name": "{network}/quote", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:5000/{{network}}/quote/trading_pair/{{celo-cusd}}/amount/1", + "protocol": "http", + "host": ["localhost"], + "port": "5000", + "path": [ + "{{network}}", + "quote", + "trading_pair", + "{{celo-cusd}}", + "amount", + "1" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Security-Policy", + "value": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" + }, + { + "key": "X-DNS-Prefetch-Control", + "value": "off" + }, + { + "key": "Expect-CT", + "value": "max-age=0" + }, + { + "key": "X-Frame-Options", + "value": "SAMEORIGIN" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15552000; includeSubDomains" + }, + { + "key": "X-Download-Options", + "value": "noopen" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-Permitted-Cross-Domain-Policies", + "value": "none" + }, + { + "key": "Referrer-Policy", + "value": "no-referrer" + }, + { + "key": "X-XSS-Protection", + "value": "0" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "97" + }, + { + "key": "ETag", + "value": "W/\"61-Wemp9YmP9g/CsUFMa7Y5zK6SoLQ\"" + }, + { + "key": "Date", + "value": "Wed, 23 Sep 2020 18:07:26 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"timestamp\": 1600884444051,\n \"latency\": 2.542,\n \"trading_pair\": \"CELO-CUSD\",\n \"price\": 2.5435604641582747\n}" + } + ] + }, + { + "name": "uniswap/sell-price/", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "{{BAT}}", + "type": "text" + }, + { + "key": "quote", + "value": "{{DAI}}", + "type": "text" + }, + { + "key": "amount", + "value": "10", + "type": "text" + }, + { + "key": "base_decimals", + "value": "18", + "type": "text" + }, + { + "key": "quote_decimals", + "value": "18", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/uniswap/sell-price", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["uniswap", "sell-price"] + } + }, + "response": [ + { + "name": "{network}/quote", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:5000/{{network}}/quote/trading_pair/{{celo-cusd}}/amount/1", + "protocol": "http", + "host": ["localhost"], + "port": "5000", + "path": [ + "{{network}}", + "quote", + "trading_pair", + "{{celo-cusd}}", + "amount", + "1" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Security-Policy", + "value": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" + }, + { + "key": "X-DNS-Prefetch-Control", + "value": "off" + }, + { + "key": "Expect-CT", + "value": "max-age=0" + }, + { + "key": "X-Frame-Options", + "value": "SAMEORIGIN" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15552000; includeSubDomains" + }, + { + "key": "X-Download-Options", + "value": "noopen" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-Permitted-Cross-Domain-Policies", + "value": "none" + }, + { + "key": "Referrer-Policy", + "value": "no-referrer" + }, + { + "key": "X-XSS-Protection", + "value": "0" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "97" + }, + { + "key": "ETag", + "value": "W/\"61-Wemp9YmP9g/CsUFMa7Y5zK6SoLQ\"" + }, + { + "key": "Date", + "value": "Wed, 23 Sep 2020 18:07:26 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"timestamp\": 1600884444051,\n \"latency\": 2.542,\n \"trading_pair\": \"CELO-CUSD\",\n \"price\": 2.5435604641582747\n}" + } + ] + } + ], + "protocolProfileBehavior": {} + } + ], + "protocolProfileBehavior": {} +} diff --git a/test/postman/Gateway-Terra.postman_collection.json b/test/postman/Gateway-Terra.postman_collection.json index 40866b8..ce18b1d 100644 --- a/test/postman/Gateway-Terra.postman_collection.json +++ b/test/postman/Gateway-Terra.postman_collection.json @@ -1,328 +1,309 @@ { - "info": { - "_postman_id": "3cca9e73-0e1f-4e4f-8973-87c985a43219", - "name": "Gateway-Terra", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "terra", - "item": [ - { - "name": "terra/balances", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "address", - "value": "{{address}}", - "type": "text" - } - ], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/terra/balances", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "terra", - "balances" - ] - } - }, - "response": [] - }, - { - "name": "terra/price", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "SDT", - "type": "text" - }, - { - "key": "quote", - "value": "KRT", - "type": "text" - }, - { - "key": "trade_type", - "value": "buy", - "type": "text" - }, - { - "key": "amount", - "value": "3", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/terra/price", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "terra", - "price" - ] - } - }, - "response": [ - { - "name": "{network}/quote", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "http://localhost:5000/{{network}}/quote/trading_pair/{{celo-cusd}}/amount/1", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "5000", - "path": [ - "{{network}}", - "quote", - "trading_pair", - "{{celo-cusd}}", - "amount", - "1" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Security-Policy", - "value": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" - }, - { - "key": "X-DNS-Prefetch-Control", - "value": "off" - }, - { - "key": "Expect-CT", - "value": "max-age=0" - }, - { - "key": "X-Frame-Options", - "value": "SAMEORIGIN" - }, - { - "key": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains" - }, - { - "key": "X-Download-Options", - "value": "noopen" - }, - { - "key": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "key": "X-Permitted-Cross-Domain-Policies", - "value": "none" - }, - { - "key": "Referrer-Policy", - "value": "no-referrer" - }, - { - "key": "X-XSS-Protection", - "value": "0" - }, - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Content-Length", - "value": "97" - }, - { - "key": "ETag", - "value": "W/\"61-Wemp9YmP9g/CsUFMa7Y5zK6SoLQ\"" - }, - { - "key": "Date", - "value": "Wed, 23 Sep 2020 18:07:26 GMT" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"timestamp\": 1600884444051,\n \"latency\": 2.542,\n \"trading_pair\": \"CELO-CUSD\",\n \"price\": 2.5435604641582747\n}" - } - ] - }, - { - "name": "terra/trade", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "SDT", - "type": "text" - }, - { - "key": "quote", - "value": "KRT", - "type": "text" - }, - { - "key": "trade_type", - "value": "buy", - "type": "text" - }, - { - "key": "amount", - "value": "3", - "type": "text" - }, - { - "key": "secret", - "value": "{{secret}}", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/terra/trade", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "terra", - "trade" - ] - } - }, - "response": [ - { - "name": "{network}/quote", - "originalRequest": { - "method": "GET", - "header": [], - "url": { - "raw": "http://localhost:5000/{{network}}/quote/trading_pair/{{celo-cusd}}/amount/1", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "5000", - "path": [ - "{{network}}", - "quote", - "trading_pair", - "{{celo-cusd}}", - "amount", - "1" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Security-Policy", - "value": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" - }, - { - "key": "X-DNS-Prefetch-Control", - "value": "off" - }, - { - "key": "Expect-CT", - "value": "max-age=0" - }, - { - "key": "X-Frame-Options", - "value": "SAMEORIGIN" - }, - { - "key": "Strict-Transport-Security", - "value": "max-age=15552000; includeSubDomains" - }, - { - "key": "X-Download-Options", - "value": "noopen" - }, - { - "key": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "key": "X-Permitted-Cross-Domain-Policies", - "value": "none" - }, - { - "key": "Referrer-Policy", - "value": "no-referrer" - }, - { - "key": "X-XSS-Protection", - "value": "0" - }, - { - "key": "Content-Type", - "value": "application/json; charset=utf-8" - }, - { - "key": "Content-Length", - "value": "97" - }, - { - "key": "ETag", - "value": "W/\"61-Wemp9YmP9g/CsUFMa7Y5zK6SoLQ\"" - }, - { - "key": "Date", - "value": "Wed, 23 Sep 2020 18:07:26 GMT" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"timestamp\": 1600884444051,\n \"latency\": 2.542,\n \"trading_pair\": \"CELO-CUSD\",\n \"price\": 2.5435604641582747\n}" - } - ] - } - ], - "protocolProfileBehavior": {} - } - ], - "protocolProfileBehavior": {} -} \ No newline at end of file + "info": { + "_postman_id": "3cca9e73-0e1f-4e4f-8973-87c985a43219", + "name": "Gateway-Terra", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "terra", + "item": [ + { + "name": "terra/balances", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "address", + "value": "{{address}}", + "type": "text" + } + ], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/terra/balances", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["terra", "balances"] + } + }, + "response": [] + }, + { + "name": "terra/price", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "SDT", + "type": "text" + }, + { + "key": "quote", + "value": "KRT", + "type": "text" + }, + { + "key": "trade_type", + "value": "buy", + "type": "text" + }, + { + "key": "amount", + "value": "3", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/terra/price", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["terra", "price"] + } + }, + "response": [ + { + "name": "{network}/quote", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:5000/{{network}}/quote/trading_pair/{{celo-cusd}}/amount/1", + "protocol": "http", + "host": ["localhost"], + "port": "5000", + "path": [ + "{{network}}", + "quote", + "trading_pair", + "{{celo-cusd}}", + "amount", + "1" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Security-Policy", + "value": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" + }, + { + "key": "X-DNS-Prefetch-Control", + "value": "off" + }, + { + "key": "Expect-CT", + "value": "max-age=0" + }, + { + "key": "X-Frame-Options", + "value": "SAMEORIGIN" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15552000; includeSubDomains" + }, + { + "key": "X-Download-Options", + "value": "noopen" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-Permitted-Cross-Domain-Policies", + "value": "none" + }, + { + "key": "Referrer-Policy", + "value": "no-referrer" + }, + { + "key": "X-XSS-Protection", + "value": "0" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "97" + }, + { + "key": "ETag", + "value": "W/\"61-Wemp9YmP9g/CsUFMa7Y5zK6SoLQ\"" + }, + { + "key": "Date", + "value": "Wed, 23 Sep 2020 18:07:26 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"timestamp\": 1600884444051,\n \"latency\": 2.542,\n \"trading_pair\": \"CELO-CUSD\",\n \"price\": 2.5435604641582747\n}" + } + ] + }, + { + "name": "terra/trade", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "SDT", + "type": "text" + }, + { + "key": "quote", + "value": "KRT", + "type": "text" + }, + { + "key": "trade_type", + "value": "buy", + "type": "text" + }, + { + "key": "amount", + "value": "3", + "type": "text" + }, + { + "key": "secret", + "value": "{{secret}}", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/terra/trade", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["terra", "trade"] + } + }, + "response": [ + { + "name": "{network}/quote", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:5000/{{network}}/quote/trading_pair/{{celo-cusd}}/amount/1", + "protocol": "http", + "host": ["localhost"], + "port": "5000", + "path": [ + "{{network}}", + "quote", + "trading_pair", + "{{celo-cusd}}", + "amount", + "1" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Security-Policy", + "value": "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" + }, + { + "key": "X-DNS-Prefetch-Control", + "value": "off" + }, + { + "key": "Expect-CT", + "value": "max-age=0" + }, + { + "key": "X-Frame-Options", + "value": "SAMEORIGIN" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=15552000; includeSubDomains" + }, + { + "key": "X-Download-Options", + "value": "noopen" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-Permitted-Cross-Domain-Policies", + "value": "none" + }, + { + "key": "Referrer-Policy", + "value": "no-referrer" + }, + { + "key": "X-XSS-Protection", + "value": "0" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "97" + }, + { + "key": "ETag", + "value": "W/\"61-Wemp9YmP9g/CsUFMa7Y5zK6SoLQ\"" + }, + { + "key": "Date", + "value": "Wed, 23 Sep 2020 18:07:26 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"timestamp\": 1600884444051,\n \"latency\": 2.542,\n \"trading_pair\": \"CELO-CUSD\",\n \"price\": 2.5435604641582747\n}" + } + ] + } + ], + "protocolProfileBehavior": {} + } + ], + "protocolProfileBehavior": {} +} diff --git a/test/postman/PERPFI.postman_collection.json b/test/postman/PERPFI.postman_collection.json index 513a083..5445efa 100644 --- a/test/postman/PERPFI.postman_collection.json +++ b/test/postman/PERPFI.postman_collection.json @@ -1,454 +1,384 @@ { - "info": { - "_postman_id": "08bf4528-5e70-42cd-bf71-b97f81088b9c", - "name": "PERPFI", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "default", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "https://localhost:{{port}}/perpfi/", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "perpfi", - "" - ] - } - }, - "response": [] - }, - { - "name": "perpfi/load-metadata", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "https://localhost:{{port}}/perpfi/load-metadata", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "perpfi", - "load-metadata" - ] - } - }, - "response": [] - }, - { - "name": "perpfi/pairs", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "https://localhost:{{port}}/perpfi/pairs", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "perpfi", - "pairs" - ] - } - }, - "response": [] - }, - { - "name": "perpfi/balances", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/perpfi/balances", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "perpfi", - "balances" - ] - } - }, - "response": [] - }, - { - "name": "perpfi/allowances", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/perpfi/allowances", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "perpfi", - "allowances" - ] - } - }, - "response": [] - }, - { - "name": "perpfi/approve", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "amount", - "value": "10", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/perpfi/approve", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "perpfi", - "approve" - ] - } - }, - "response": [] - }, - { - "name": "perpfi/open", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "margin", - "value": "15", - "type": "text" - }, - { - "key": "leverage", - "value": "2", - "type": "text" - }, - { - "key": "side", - "value": "{{SHORT}}", - "type": "text" - }, - { - "key": "pair", - "value": "SNXUSDC", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/perpfi/open", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "perpfi", - "open" - ] - } - }, - "response": [] - }, - { - "name": "perpfi/close", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "pair", - "value": "SNXUSDC", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/perpfi/close", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "perpfi", - "close" - ] - } - }, - "response": [] - }, - { - "name": "perpfi/receipt", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "txHash", - "value": "0xd29120d947319c880f68a44b897c733c07ec313d670a7df55e523b501d7a03a2", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/perpfi/receipt", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "perpfi", - "receipt" - ] - } - }, - "response": [] - }, - { - "name": "perpfi/position", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "pair", - "value": "SNXUSDC", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/perpfi/position", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "perpfi", - "position" - ] - } - }, - "response": [] - }, - { - "name": "perpfi/margin", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/perpfi/margin", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "perpfi", - "margin" - ] - } - }, - "response": [] - }, - { - "name": "perpfi/pnl", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "pair", - "value": "SNXUSDC", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/perpfi/pnl", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "perpfi", - "pnl" - ] - } - }, - "response": [] - }, - { - "name": "perpfi/funding", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "amount", - "value": "1", - "type": "text" - }, - { - "key": "pair", - "value": "SNXUSDC", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/perpfi/funding", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "perpfi", - "funding" - ] - } - }, - "response": [] - }, - { - "name": "perpfi/price", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "side", - "value": "buy", - "type": "text" - }, - { - "key": "pair", - "value": "SNXUSDC", - "type": "text" - }, - { - "key": "amount", - "value": "1", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/perpfi/price", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "perpfi", - "price" - ] - } - }, - "response": [] - } - ] -} \ No newline at end of file + "info": { + "_postman_id": "08bf4528-5e70-42cd-bf71-b97f81088b9c", + "name": "PERPFI", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "default", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://localhost:{{port}}/perpfi/", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["perpfi", ""] + } + }, + "response": [] + }, + { + "name": "perpfi/load-metadata", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://localhost:{{port}}/perpfi/load-metadata", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["perpfi", "load-metadata"] + } + }, + "response": [] + }, + { + "name": "perpfi/pairs", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://localhost:{{port}}/perpfi/pairs", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["perpfi", "pairs"] + } + }, + "response": [] + }, + { + "name": "perpfi/balances", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/perpfi/balances", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["perpfi", "balances"] + } + }, + "response": [] + }, + { + "name": "perpfi/allowances", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/perpfi/allowances", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["perpfi", "allowances"] + } + }, + "response": [] + }, + { + "name": "perpfi/approve", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "amount", + "value": "10", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/perpfi/approve", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["perpfi", "approve"] + } + }, + "response": [] + }, + { + "name": "perpfi/open", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "margin", + "value": "15", + "type": "text" + }, + { + "key": "leverage", + "value": "2", + "type": "text" + }, + { + "key": "side", + "value": "{{SHORT}}", + "type": "text" + }, + { + "key": "pair", + "value": "SNXUSDC", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/perpfi/open", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["perpfi", "open"] + } + }, + "response": [] + }, + { + "name": "perpfi/close", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "pair", + "value": "SNXUSDC", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/perpfi/close", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["perpfi", "close"] + } + }, + "response": [] + }, + { + "name": "perpfi/receipt", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "txHash", + "value": "0xd29120d947319c880f68a44b897c733c07ec313d670a7df55e523b501d7a03a2", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/perpfi/receipt", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["perpfi", "receipt"] + } + }, + "response": [] + }, + { + "name": "perpfi/position", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "pair", + "value": "SNXUSDC", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/perpfi/position", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["perpfi", "position"] + } + }, + "response": [] + }, + { + "name": "perpfi/margin", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/perpfi/margin", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["perpfi", "margin"] + } + }, + "response": [] + }, + { + "name": "perpfi/pnl", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "pair", + "value": "SNXUSDC", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/perpfi/pnl", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["perpfi", "pnl"] + } + }, + "response": [] + }, + { + "name": "perpfi/funding", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "amount", + "value": "1", + "type": "text" + }, + { + "key": "pair", + "value": "SNXUSDC", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/perpfi/funding", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["perpfi", "funding"] + } + }, + "response": [] + }, + { + "name": "perpfi/price", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "side", + "value": "buy", + "type": "text" + }, + { + "key": "pair", + "value": "SNXUSDC", + "type": "text" + }, + { + "key": "amount", + "value": "1", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/perpfi/price", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["perpfi", "price"] + } + }, + "response": [] + } + ] +} diff --git a/test/postman/Uniswap_V3_postman_collection.json b/test/postman/Uniswap_V3_postman_collection.json index 877abbd..9cccb68 100644 --- a/test/postman/Uniswap_V3_postman_collection.json +++ b/test/postman/Uniswap_V3_postman_collection.json @@ -1,518 +1,444 @@ { - "info": { - "_postman_id": "5de36bfa-027e-46e3-810d-219e42c75314", - "name": "Uniswap V3", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "uniswap v3 endpoints", - "item": [ - { - "name": "eth/uniswap/v3", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/eth/uniswap/v3", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "uniswap", - "v3" - ] - } - }, - "response": [] - }, - { - "name": "eth/uniswap/v3/gas-limit", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/eth/uniswap/v3/gas-limit", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "uniswap", - "v3", - "gas-limit" - ] - } - }, - "response": [] - }, - { - "name": "eth/uniswap/v3/result", - "request": { - "method": "GET", - "header": [], - "url": { - "raw": "https://localhost:{{port}}/eth/uniswap/v3/result?logs=§ion=lp", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "uniswap", - "v3", - "result" - ], - "query": [ - { - "key": "logs", - "value": "" - }, - { - "key": "section", - "value": "lp" - } - ] - } - }, - "response": [] - }, - { - "name": "eth/uniswap/v3/price", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "COIN1", - "type": "text" - }, - { - "key": "quote", - "value": "COIN2", - "type": "text" - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/uniswap/v3/price", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "uniswap", - "v3", - "price" - ] - } - }, - "response": [] - }, - { - "name": "eth/uniswap/v3/trade", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "COIN1", - "type": "text" - }, - { - "key": "quote", - "value": "COIN2", - "type": "text" - }, - { - "key": "amount", - "value": "0.000009", - "type": "text" - }, - { - "key": "limitPrice", - "value": "0.000000000025", - "type": "text" - }, - { - "key": "gasPrice", - "value": "37", - "type": "text", - "disabled": true - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "side", - "value": "buy", - "type": "text" - }, - { - "key": "tier", - "value": "HIGH", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/uniswap/v3/trade", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "uniswap", - "v3", - "trade" - ] - } - }, - "response": [] - }, - { - "name": "eth/uniswap/v3/position", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "tokenId", - "value": "66", - "type": "text" - }, - { - "key": "gasPrice", - "value": "37", - "type": "text", - "disabled": true - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/uniswap/v3/position", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "uniswap", - "v3", - "position" - ] - } - }, - "response": [] - }, - { - "name": "eth/uniswap/v3/add-position", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "gasPrice", - "value": "37", - "type": "text", - "disabled": true - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "token0", - "value": "DAI", - "type": "text" - }, - { - "key": "token1", - "value": "USDC", - "type": "text" - }, - { - "key": "fee", - "value": "LOW", - "type": "text" - }, - { - "key": "lowerPrice", - "value": "1561", - "type": "text" - }, - { - "key": "upperPrice", - "value": "1570", - "type": "text" - }, - { - "key": "amount0", - "value": "2", - "type": "text" - }, - { - "key": "amount1", - "value": "2", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/uniswap/v3/add-position", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "uniswap", - "v3", - "add-position" - ] - } - }, - "response": [] - }, - { - "name": "eth/uniswap/v3/replace-position", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "gasPrice", - "value": "37", - "type": "text", - "disabled": true - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "token0", - "value": "COIN1", - "type": "text" - }, - { - "key": "token1", - "value": "COIN2", - "type": "text" - }, - { - "key": "fee", - "value": "MEDIUM", - "type": "text" - }, - { - "key": "lowerPrice", - "value": "6", - "type": "text" - }, - { - "key": "upperPrice", - "value": "20", - "type": "text" - }, - { - "key": "amount0", - "value": "2", - "type": "text" - }, - { - "key": "amount1", - "value": "2", - "type": "text" - }, - { - "key": "tokenId", - "value": "69", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/uniswap/v3/replace-position", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "uniswap", - "v3", - "replace-position" - ] - } - }, - "response": [] - }, - { - "name": "eth/uniswap/v3/collect-fees", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "gasPrice", - "value": "37", - "type": "text", - "disabled": true - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "tokenId", - "value": "44", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/uniswap/v3//collect-fees", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "uniswap", - "v3", - "", - "collect-fees" - ] - } - }, - "response": [] - }, - { - "name": "eth/uniswap/v3/remove-position", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "gasPrice", - "value": "37", - "type": "text", - "disabled": true - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "tokenId", - "value": "66", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/uniswap/v3/remove-position", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "uniswap", - "v3", - "remove-position" - ] - } - }, - "response": [] - } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "type": "text/javascript", - "exec": [ - "" - ] - } - } - ] - } - ] -} \ No newline at end of file + "info": { + "_postman_id": "5de36bfa-027e-46e3-810d-219e42c75314", + "name": "Uniswap V3", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "uniswap v3 endpoints", + "item": [ + { + "name": "eth/uniswap/v3", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/eth/uniswap/v3", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "uniswap", "v3"] + } + }, + "response": [] + }, + { + "name": "eth/uniswap/v3/gas-limit", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/eth/uniswap/v3/gas-limit", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "uniswap", "v3", "gas-limit"] + } + }, + "response": [] + }, + { + "name": "eth/uniswap/v3/result", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "https://localhost:{{port}}/eth/uniswap/v3/result?logs=§ion=lp", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "uniswap", "v3", "result"], + "query": [ + { + "key": "logs", + "value": "" + }, + { + "key": "section", + "value": "lp" + } + ] + } + }, + "response": [] + }, + { + "name": "eth/uniswap/v3/price", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "COIN1", + "type": "text" + }, + { + "key": "quote", + "value": "COIN2", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/uniswap/v3/price", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "uniswap", "v3", "price"] + } + }, + "response": [] + }, + { + "name": "eth/uniswap/v3/trade", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "COIN1", + "type": "text" + }, + { + "key": "quote", + "value": "COIN2", + "type": "text" + }, + { + "key": "amount", + "value": "0.000009", + "type": "text" + }, + { + "key": "limitPrice", + "value": "0.000000000025", + "type": "text" + }, + { + "key": "gasPrice", + "value": "37", + "type": "text", + "disabled": true + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "side", + "value": "buy", + "type": "text" + }, + { + "key": "tier", + "value": "HIGH", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/uniswap/v3/trade", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "uniswap", "v3", "trade"] + } + }, + "response": [] + }, + { + "name": "eth/uniswap/v3/position", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "tokenId", + "value": "66", + "type": "text" + }, + { + "key": "gasPrice", + "value": "37", + "type": "text", + "disabled": true + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/uniswap/v3/position", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "uniswap", "v3", "position"] + } + }, + "response": [] + }, + { + "name": "eth/uniswap/v3/add-position", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "gasPrice", + "value": "37", + "type": "text", + "disabled": true + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "token0", + "value": "DAI", + "type": "text" + }, + { + "key": "token1", + "value": "USDC", + "type": "text" + }, + { + "key": "fee", + "value": "LOW", + "type": "text" + }, + { + "key": "lowerPrice", + "value": "1561", + "type": "text" + }, + { + "key": "upperPrice", + "value": "1570", + "type": "text" + }, + { + "key": "amount0", + "value": "2", + "type": "text" + }, + { + "key": "amount1", + "value": "2", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/uniswap/v3/add-position", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "uniswap", "v3", "add-position"] + } + }, + "response": [] + }, + { + "name": "eth/uniswap/v3/replace-position", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "gasPrice", + "value": "37", + "type": "text", + "disabled": true + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "token0", + "value": "COIN1", + "type": "text" + }, + { + "key": "token1", + "value": "COIN2", + "type": "text" + }, + { + "key": "fee", + "value": "MEDIUM", + "type": "text" + }, + { + "key": "lowerPrice", + "value": "6", + "type": "text" + }, + { + "key": "upperPrice", + "value": "20", + "type": "text" + }, + { + "key": "amount0", + "value": "2", + "type": "text" + }, + { + "key": "amount1", + "value": "2", + "type": "text" + }, + { + "key": "tokenId", + "value": "69", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/uniswap/v3/replace-position", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "uniswap", "v3", "replace-position"] + } + }, + "response": [] + }, + { + "name": "eth/uniswap/v3/collect-fees", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "gasPrice", + "value": "37", + "type": "text", + "disabled": true + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "tokenId", + "value": "44", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/uniswap/v3//collect-fees", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "uniswap", "v3", "", "collect-fees"] + } + }, + "response": [] + }, + { + "name": "eth/uniswap/v3/remove-position", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "gasPrice", + "value": "37", + "type": "text", + "disabled": true + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "tokenId", + "value": "66", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/uniswap/v3/remove-position", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "uniswap", "v3", "remove-position"] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [""] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [""] + } + } + ] + } + ] +} diff --git a/test/postman/terra.postman_environment.json b/test/postman/terra.postman_environment.json index 735927a..eb95c30 100644 --- a/test/postman/terra.postman_environment.json +++ b/test/postman/terra.postman_environment.json @@ -1,29 +1,29 @@ { - "id": "aebe7d1f-0e85-4441-8679-2ddc38d74350", - "name": "terra", - "values": [ - { - "key": "protocol", - "value": "terra", - "enabled": true - }, - { - "key": "port", - "value": "5000", - "enabled": true - }, - { - "key": "address", - "value": "myaddresss", - "enabled": true - }, - { - "key": "secret", - "value": "mysupersecret", - "enabled": true - } - ], - "_postman_variable_scope": "environment", - "_postman_exported_at": "2020-11-13T06:00:14.142Z", - "_postman_exported_using": "Postman/7.35.0" -} \ No newline at end of file + "id": "aebe7d1f-0e85-4441-8679-2ddc38d74350", + "name": "terra", + "values": [ + { + "key": "protocol", + "value": "terra", + "enabled": true + }, + { + "key": "port", + "value": "5000", + "enabled": true + }, + { + "key": "address", + "value": "myaddresss", + "enabled": true + }, + { + "key": "secret", + "value": "mysupersecret", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2020-11-13T06:00:14.142Z", + "_postman_exported_using": "Postman/7.35.0" +} diff --git a/test/postman/v2/Gateway.postman_collection.json b/test/postman/v2/Gateway.postman_collection.json index 949efe0..a84fe12 100644 --- a/test/postman/v2/Gateway.postman_collection.json +++ b/test/postman/v2/Gateway.postman_collection.json @@ -1,1001 +1,876 @@ { - "info": { - "_postman_id": "e39af94e-6095-479e-8ba0-66930b12e364", - "name": "Gateway", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "v2", - "item": [ - { - "name": "ethereum", - "item": [ - { - "name": "eth", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/eth", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth" - ] - } - }, - "response": [] - }, - { - "name": "eth/balances", - "event": [ - { - "listen": "test", - "script": { - "exec": [ - "" - ], - "type": "text/javascript" - } - } - ], - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "tokenList", - "value": "[\"BAT\",\"USDC\",\"DAI\",\"WETH\",\"ZRX\"]", - "type": "text" - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/balances", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "balances" - ] - } - }, - "response": [] - }, - { - "name": "eth/allowances", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "tokenList", - "value": "[\"BAT\",\"USDC\",\"DAI\",\"WETH\",\"ZRX\"]", - "type": "text" - }, - { - "key": "connector", - "value": "balancer", - "type": "text" - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - } - ], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/eth/allowances", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "allowances" - ] - } - }, - "response": [] - }, - { - "name": "eth/approve", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "token", - "value": "ZRX", - "type": "text" - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "gasPrice", - "value": "23", - "type": "text" - }, - { - "key": "connector", - "value": "balancer", - "type": "text" - }, - { - "key": "amount", - "value": "999", - "type": "text", - "disabled": true - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/approve", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "approve" - ] - } - }, - "response": [] - }, - { - "name": "eth/get-weth", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "gasPrice", - "value": "31", - "type": "text" - }, - { - "key": "amount", - "value": "0.03", - "type": "text" - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "tokenAddress", - "value": "{{WETH}}", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/get-weth", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "get-weth" - ] - } - }, - "response": [] - }, - { - "name": "eth/poll", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "txHash", - "value": "{{txHash}}", - "type": "text" - } - ], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/eth/poll", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "poll" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "balancer", - "item": [ - { - "name": "eth/balancer", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/eth/balancer", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "balancer" - ] - } - }, - "response": [] - }, - { - "name": "eth/balancer/gas-limit", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/eth/balancer/gas-limit", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "balancer", - "gas-limit" - ] - } - }, - "response": [] - }, - { - "name": "eth/balancer/start", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "BAT", - "type": "text" - }, - { - "key": "quote", - "value": "dai", - "type": "text" - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "approvalAmount", - "value": "1", - "type": "text", - "disabled": true - }, - { - "key": "gasPrice", - "value": "50", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/balancer/start", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "balancer", - "start" - ] - } - }, - "response": [] - }, - { - "name": "eth/balancer/price", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "BAT", - "type": "text" - }, - { - "key": "quote", - "value": "dai", - "type": "text" - }, - { - "key": "amount", - "value": "10", - "type": "text" - }, - { - "key": "side", - "value": "buy", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/balancer/price", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "balancer", - "price" - ] - } - }, - "response": [] - }, - { - "name": "eth/balancer/trade", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "BAT", - "type": "text" - }, - { - "key": "quote", - "value": "USDC", - "type": "text" - }, - { - "key": "amount", - "value": "1", - "type": "text" - }, - { - "key": "limitPrice", - "value": "0.19767217120251", - "type": "text" - }, - { - "key": "gasPrice", - "value": "37", - "type": "text" - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "side", - "value": "sell", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/balancer/trade", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "balancer", - "trade" - ] - } - }, - "response": [] - } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "type": "text/javascript", - "exec": [ - "" - ] - } - } - ] - }, - { - "name": "uniswap", - "item": [ - { - "name": "eth/uniswap", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/eth/uniswap", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "uniswap" - ] - } - }, - "response": [] - }, - { - "name": "eth/uniswap/gas-limit", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/eth/uniswap/gas-limit", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "uniswap", - "gas-limit" - ] - } - }, - "response": [] - }, - { - "name": "eth/uniswap/start", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "WETH", - "type": "text" - }, - { - "key": "quote", - "value": "USDC", - "type": "text" - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "approvalAmount", - "value": "1", - "type": "text", - "disabled": true - }, - { - "key": "gasPrice", - "value": "50", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/uniswap/start", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "uniswap", - "start" - ] - } - }, - "response": [] - }, - { - "name": "eth/uniswap/price", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "WETH", - "type": "text" - }, - { - "key": "quote", - "value": "DAI", - "type": "text" - }, - { - "key": "amount", - "value": "1", - "type": "text" - }, - { - "key": "side", - "value": "buy", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/uniswap/price", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "uniswap", - "price" - ] - } - }, - "response": [] - }, - { - "name": "eth/uniswap/trade", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "BAT", - "type": "text" - }, - { - "key": "quote", - "value": "DAI", - "type": "text" - }, - { - "key": "amount", - "value": "1", - "type": "text" - }, - { - "key": "limitPrice", - "value": "0.19767217120251", - "type": "text" - }, - { - "key": "gasPrice", - "value": "37", - "type": "text" - }, - { - "key": "privateKey", - "value": "{{privateKey}}", - "type": "text" - }, - { - "key": "side", - "value": "sell", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/eth/uniswap/trade", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "eth", - "uniswap", - "trade" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "terra", - "item": [ - { - "name": "terra", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "address", - "value": "{{address}}", - "type": "text" - } - ], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/terra", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "terra" - ] - } - }, - "response": [] - }, - { - "name": "terra/balances", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "address", - "value": "{{terraWalletAddress}}", - "type": "text" - } - ], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/terra/balances", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "terra", - "balances" - ] - } - }, - "response": [] - }, - { - "name": "terra/start", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "LUNA", - "type": "text" - }, - { - "key": "quote", - "value": "UST", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/terra/start", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "terra", - "start" - ] - } - }, - "response": [] - }, - { - "name": "terra/price", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "UST", - "type": "text" - }, - { - "key": "quote", - "value": "KRT", - "type": "text" - }, - { - "key": "side", - "value": "buy", - "type": "text" - }, - { - "key": "amount", - "value": "1", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/terra/price", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "terra", - "price" - ] - } - }, - "response": [] - }, - { - "name": "terra/trade", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [ - { - "key": "base", - "value": "UST", - "type": "text" - }, - { - "key": "quote", - "value": "KRT", - "type": "text" - }, - { - "key": "side", - "value": "buy", - "type": "text" - }, - { - "key": "amount", - "value": "10", - "type": "text" - }, - { - "key": "privateKey", - "value": "{{terraSeeds}}", - "type": "text" - } - ] - }, - "url": { - "raw": "https://localhost:{{port}}/terra/trade", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "terra", - "trade" - ] - } - }, - "response": [] - } - ] - } - ] - }, - { - "name": "/api", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/api", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "api" - ] - } - }, - "response": [] - }, - { - "name": "/", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "urlencoded", - "urlencoded": [], - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://localhost:{{port}}/", - "protocol": "https", - "host": [ - "localhost" - ], - "port": "{{port}}", - "path": [ - "" - ] - } - }, - "response": [] - } - ] -} \ No newline at end of file + "info": { + "_postman_id": "e39af94e-6095-479e-8ba0-66930b12e364", + "name": "Gateway", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "v2", + "item": [ + { + "name": "ethereum", + "item": [ + { + "name": "eth", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/eth", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth"] + } + }, + "response": [] + }, + { + "name": "eth/balances", + "event": [ + { + "listen": "test", + "script": { + "exec": [""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "tokenList", + "value": "[\"BAT\",\"USDC\",\"DAI\",\"WETH\",\"ZRX\"]", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/balances", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "balances"] + } + }, + "response": [] + }, + { + "name": "eth/allowances", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "tokenList", + "value": "[\"BAT\",\"USDC\",\"DAI\",\"WETH\",\"ZRX\"]", + "type": "text" + }, + { + "key": "connector", + "value": "balancer", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + } + ], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/eth/allowances", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "allowances"] + } + }, + "response": [] + }, + { + "name": "eth/approve", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "token", + "value": "ZRX", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "gasPrice", + "value": "23", + "type": "text" + }, + { + "key": "connector", + "value": "balancer", + "type": "text" + }, + { + "key": "amount", + "value": "999", + "type": "text", + "disabled": true + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/approve", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "approve"] + } + }, + "response": [] + }, + { + "name": "eth/get-weth", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "gasPrice", + "value": "31", + "type": "text" + }, + { + "key": "amount", + "value": "0.03", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "tokenAddress", + "value": "{{WETH}}", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/get-weth", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "get-weth"] + } + }, + "response": [] + }, + { + "name": "eth/poll", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "txHash", + "value": "{{txHash}}", + "type": "text" + } + ], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/eth/poll", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "poll"] + } + }, + "response": [] + } + ] + }, + { + "name": "balancer", + "item": [ + { + "name": "eth/balancer", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/eth/balancer", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "balancer"] + } + }, + "response": [] + }, + { + "name": "eth/balancer/gas-limit", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/eth/balancer/gas-limit", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "balancer", "gas-limit"] + } + }, + "response": [] + }, + { + "name": "eth/balancer/start", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "BAT", + "type": "text" + }, + { + "key": "quote", + "value": "dai", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "approvalAmount", + "value": "1", + "type": "text", + "disabled": true + }, + { + "key": "gasPrice", + "value": "50", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/balancer/start", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "balancer", "start"] + } + }, + "response": [] + }, + { + "name": "eth/balancer/price", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "BAT", + "type": "text" + }, + { + "key": "quote", + "value": "dai", + "type": "text" + }, + { + "key": "amount", + "value": "10", + "type": "text" + }, + { + "key": "side", + "value": "buy", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/balancer/price", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "balancer", "price"] + } + }, + "response": [] + }, + { + "name": "eth/balancer/trade", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "BAT", + "type": "text" + }, + { + "key": "quote", + "value": "USDC", + "type": "text" + }, + { + "key": "amount", + "value": "1", + "type": "text" + }, + { + "key": "limitPrice", + "value": "0.19767217120251", + "type": "text" + }, + { + "key": "gasPrice", + "value": "37", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "side", + "value": "sell", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/balancer/trade", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "balancer", "trade"] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [""] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [""] + } + } + ] + }, + { + "name": "uniswap", + "item": [ + { + "name": "eth/uniswap", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/eth/uniswap", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "uniswap"] + } + }, + "response": [] + }, + { + "name": "eth/uniswap/gas-limit", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/eth/uniswap/gas-limit", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "uniswap", "gas-limit"] + } + }, + "response": [] + }, + { + "name": "eth/uniswap/start", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "WETH", + "type": "text" + }, + { + "key": "quote", + "value": "USDC", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "approvalAmount", + "value": "1", + "type": "text", + "disabled": true + }, + { + "key": "gasPrice", + "value": "50", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/uniswap/start", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "uniswap", "start"] + } + }, + "response": [] + }, + { + "name": "eth/uniswap/price", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "WETH", + "type": "text" + }, + { + "key": "quote", + "value": "DAI", + "type": "text" + }, + { + "key": "amount", + "value": "1", + "type": "text" + }, + { + "key": "side", + "value": "buy", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/uniswap/price", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "uniswap", "price"] + } + }, + "response": [] + }, + { + "name": "eth/uniswap/trade", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "BAT", + "type": "text" + }, + { + "key": "quote", + "value": "DAI", + "type": "text" + }, + { + "key": "amount", + "value": "1", + "type": "text" + }, + { + "key": "limitPrice", + "value": "0.19767217120251", + "type": "text" + }, + { + "key": "gasPrice", + "value": "37", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{privateKey}}", + "type": "text" + }, + { + "key": "side", + "value": "sell", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/eth/uniswap/trade", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["eth", "uniswap", "trade"] + } + }, + "response": [] + } + ] + }, + { + "name": "terra", + "item": [ + { + "name": "terra", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "address", + "value": "{{address}}", + "type": "text" + } + ], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/terra", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["terra"] + } + }, + "response": [] + }, + { + "name": "terra/balances", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "address", + "value": "{{terraWalletAddress}}", + "type": "text" + } + ], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/terra/balances", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["terra", "balances"] + } + }, + "response": [] + }, + { + "name": "terra/start", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "LUNA", + "type": "text" + }, + { + "key": "quote", + "value": "UST", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/terra/start", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["terra", "start"] + } + }, + "response": [] + }, + { + "name": "terra/price", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "UST", + "type": "text" + }, + { + "key": "quote", + "value": "KRT", + "type": "text" + }, + { + "key": "side", + "value": "buy", + "type": "text" + }, + { + "key": "amount", + "value": "1", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/terra/price", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["terra", "price"] + } + }, + "response": [] + }, + { + "name": "terra/trade", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [ + { + "key": "base", + "value": "UST", + "type": "text" + }, + { + "key": "quote", + "value": "KRT", + "type": "text" + }, + { + "key": "side", + "value": "buy", + "type": "text" + }, + { + "key": "amount", + "value": "10", + "type": "text" + }, + { + "key": "privateKey", + "value": "{{terraSeeds}}", + "type": "text" + } + ] + }, + "url": { + "raw": "https://localhost:{{port}}/terra/trade", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["terra", "trade"] + } + }, + "response": [] + } + ] + } + ] + }, + { + "name": "/api", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/api", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": ["api"] + } + }, + "response": [] + }, + { + "name": "/", + "protocolProfileBehavior": { + "disableBodyPruning": true + }, + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "urlencoded", + "urlencoded": [], + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://localhost:{{port}}/", + "protocol": "https", + "host": ["localhost"], + "port": "{{port}}", + "path": [""] + } + }, + "response": [] + } + ] +} diff --git a/test/postman/v2/Gateway.postman_environment.json b/test/postman/v2/Gateway.postman_environment.json index 834026f..5733995 100644 --- a/test/postman/v2/Gateway.postman_environment.json +++ b/test/postman/v2/Gateway.postman_environment.json @@ -1,34 +1,34 @@ { - "id": "4436d04a-e8eb-451b-b7ef-851b171508e8", - "name": "Gateway", - "values": [ - { - "key": "port", - "value": "5000", - "enabled": true - }, - { - "key": "privateKey", - "value": "myprivatekey", - "enabled": true - }, - { - "key": "txHash", - "value": "transactionhash", - "enabled": true - }, - { - "key": "terraWalletAddress", - "value": "terrawalletaddress", - "enabled": true - }, - { - "key": "terraSeeds", - "value": "terraseeds", - "enabled": true - } - ], - "_postman_variable_scope": "environment", - "_postman_exported_at": "2021-01-30T13:04:21.323Z", - "_postman_exported_using": "Postman/8.0.3" -} \ No newline at end of file + "id": "4436d04a-e8eb-451b-b7ef-851b171508e8", + "name": "Gateway", + "values": [ + { + "key": "port", + "value": "5000", + "enabled": true + }, + { + "key": "privateKey", + "value": "myprivatekey", + "enabled": true + }, + { + "key": "txHash", + "value": "transactionhash", + "enabled": true + }, + { + "key": "terraWalletAddress", + "value": "terrawalletaddress", + "enabled": true + }, + { + "key": "terraSeeds", + "value": "terraseeds", + "enabled": true + } + ], + "_postman_variable_scope": "environment", + "_postman_exported_at": "2021-01-30T13:04:21.323Z", + "_postman_exported_using": "Postman/8.0.3" +} From 53aea39a93ae24614d9e1d0531194fe9370ab884 Mon Sep 17 00:00:00 2001 From: james-hummingbot Date: Mon, 7 Jun 2021 13:43:49 +0200 Subject: [PATCH 7/7] Fix things, double check in postman --- package-lock.json | 12 +- package.json | 1 - src/app.js | 5 +- src/index.js | 33 ++-- src/routes/balancer.route.js | 36 ++--- src/routes/celo.route.js | 42 ++--- src/routes/eth.route.js | 26 +-- src/routes/perpetual_finance.route.js | 42 ++--- src/routes/terra.route.js | 30 ++-- src/routes/uniswap.route.js | 35 ++-- src/routes/uniswap_v3.route.js | 88 +++++------ src/services/access.js | 2 +- src/services/balancer.js | 16 +- src/services/eth.js | 30 ++-- src/services/fees.js | 2 +- src/services/perpetual_finance.js | 28 ++-- src/services/terra.js | 42 ++--- src/services/uniswap.js | 42 +++-- src/services/uniswap_v3.js | 85 +++++++--- src/services/utils.js | 13 +- src/static/uniswap-v3/helper_functions.js | 184 ++-------------------- yarn.lock | 12 +- 22 files changed, 348 insertions(+), 458 deletions(-) diff --git a/package-lock.json b/package-lock.json index fcef706..f058691 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5172,9 +5172,9 @@ "dev": true }, "node-releases": { - "version": "1.1.72", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz", - "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==", + "version": "1.1.73", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", + "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", "dev": true }, "nodemon": { @@ -6675,9 +6675,9 @@ }, "dependencies": { "ajv": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.5.0.tgz", - "integrity": "sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz", + "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", diff --git a/package.json b/package.json index b3b8b9d..ae45f0c 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "express-ipfilter": "^1.1.2", "helmet": "^4.6.0", "http-status-codes": "^2.1.3", - "jsbi": "^3.1.4", "lodash": "^4.17.20", "mathjs": "^9.3.0", "moment": "^2.29.1", diff --git a/src/app.js b/src/app.js index 170a1e4..eeb44b1 100644 --- a/src/app.js +++ b/src/app.js @@ -1,14 +1,15 @@ import bodyParser from 'body-parser'; import express from 'express'; import helmet from 'helmet'; -import { IpFilter } from 'express-ipfilter'; import { statusMessages } from './services/utils'; import { validateAccess } from './services/access'; +import { IpFilter } from 'express-ipfilter'; import { logger } from './services/logger'; // Routes import apiRoutes from './routes/index.route'; import balancerRoutes from './routes/balancer.route'; +// import celoRoutes from './routes/celo.route' import ethRoutes from './routes/eth.route'; import terraRoutes from './routes/terra.route'; import uniswapRoutes from './routes/uniswap.route'; @@ -58,7 +59,7 @@ app.use((req, res, _next) => { logger.error(message); res.status(404).send({ error: 'Page not found', - message + message: message }); }); diff --git a/src/index.js b/src/index.js index 23b7908..cdd5675 100644 --- a/src/index.js +++ b/src/index.js @@ -8,12 +8,15 @@ import fs from 'fs'; import app from './app'; import { logger } from './services/logger'; -const env = process.env.NODE_ENV; -const port = process.env.PORT; -const certPassphrase = process.env.CERT_PASSPHRASE; -const ethereumChain = process.env.ETHEREUM_CHAIN; -const terraChain = process.env.TERRA_CHAIN; -let certPath = process.env.CERT_PATH; +const globalConfig = + require('./services/configuration_manager').configManagerInstance.readAllConfigs(); + +const env = globalConfig.CORE.NODE_ENV; +const port = globalConfig.CORE.PORT; +const certPassphrase = globalConfig.CERT_PASSPHRASE; +const ethereumChain = globalConfig.ETHEREUM_CHAIN; +const terraChain = globalConfig.TERRA_CHAIN; +let certPath = globalConfig.CERT_PATH; if ((typeof certPath === 'undefined' && certPath == null) || certPath === '') { // assuming it is local development using test script to generate certs @@ -48,16 +51,16 @@ const onError = (error) => { throw error; } - const bind = typeof port === 'string' ? `Pipe ${port}` : `Port ${port}`; + const bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port; // handle specific listen errors with friendly messages switch (error.code) { case 'EACCES': - console.error(`${bind} requires elevated privileges`); + console.error(bind + ' requires elevated privileges'); process.exit(1); break; case 'EADDRINUSE': - console.error(`${bind} is already in use`); + console.error(bind + ' is already in use'); process.exit(1); break; default: @@ -68,9 +71,9 @@ const onError = (error) => { // event listener for "listening" event. const onListening = () => { const addr = server.address(); - const bind = typeof addr === 'string' ? `pipe ${addr}` : `port ${addr.port}`; - console.log(`listening on ${bind}`); - logger.debug(`listening on ${bind}`); + const bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port; + console.log('listening on ' + bind); + logger.debug('listening on ' + bind); }; // listen on provided port, on all network interfaces. @@ -80,9 +83,9 @@ server.on('listening', onListening); const serverConfig = { app: 'gateway-api', - port, - ethereumChain, - terraChain + port: port, + ethereumChain: ethereumChain, + terraChain: terraChain }; logger.info(JSON.stringify(serverConfig)); diff --git a/src/routes/balancer.route.js b/src/routes/balancer.route.js index fefddac..f59e7e3 100644 --- a/src/routes/balancer.route.js +++ b/src/routes/balancer.route.js @@ -58,7 +58,7 @@ router.post('/gas-limit', async (req, res) => { res.status(200).json({ network: balancer.network, - gasLimit, + gasLimit: gasLimit, timestamp: Date.now() }); } catch (err) { @@ -135,10 +135,10 @@ router.get('/start', async (req, res) => { timestamp: initTime, latency: latency(initTime, Date.now()), success: true, - pairs, - gasPrice, - gasLimit, - gasCost + pairs: pairs, + gasPrice: gasPrice, + gasLimit: gasLimit, + gasCost: gasCost }; console.log('Initializing balancer'); res.status(200).json(result); @@ -210,13 +210,13 @@ router.post('/price', async (req, res) => { base: baseTokenContractInfo, quote: quoteTokenContractInfo, amount: tradeAmount, - side, + side: side, expectedAmount: expectedTradeAmount, price: tradePrice, - gasPrice, - gasLimit, - gasCost, - swaps + gasPrice: gasPrice, + gasLimit: gasLimit, + gasCost: gasCost, + swaps: swaps }; debug( `Price ${side} ${baseTokenContractInfo.symbol}-${quoteTokenContractInfo.symbol} | amount:${amount} (rate:${tradePrice}) - gasPrice:${gasPrice} gasLimit:${gasLimit} estimated fee:${gasCost} ETH` @@ -329,10 +329,10 @@ router.post('/trade', async (req, res) => { quote: quoteTokenContractInfo, amount: parseFloat(paramData.amount), expectedIn: expectedAmount / quoteDenomMultiplier, - price, - gasPrice, - gasLimit, - gasCost, + price: price, + gasPrice: gasPrice, + gasLimit: gasLimit, + gasCost: gasCost, txHash: tx.hash }); } else { @@ -370,10 +370,10 @@ router.post('/trade', async (req, res) => { quote: quoteTokenContractInfo, amount: parseFloat(paramData.amount), expectedOut: expectedAmount / quoteDenomMultiplier, - price, - gasPrice, - gasLimit, - gasCost, + price: price, + gasPrice: gasPrice, + gasLimit: gasLimit, + gasCost: gasCost, txHash: tx.hash }); } else { diff --git a/src/routes/celo.route.js b/src/routes/celo.route.js index 933ff92..fa0c61f 100644 --- a/src/routes/celo.route.js +++ b/src/routes/celo.route.js @@ -1,5 +1,6 @@ -const express = require('express'); +'use strict'; +const express = require('express'); const router = express.Router(); const BigNumber = require('bignumber.js'); const debug = require('debug')('router'); @@ -10,7 +11,6 @@ const celocli = 'celocli'; const DENOM_UNIT_MULTIPLIER = BigNumber('1e+18'); const hbUtils = require('../services/utils'); - const separator = '=>'; router.use((req, res, next) => { @@ -29,8 +29,8 @@ router.get('/status', (req, res) => { const nodeSync = spawn(celocli, ['node:synced']); - const err_message = []; - const out_message = []; + let err_message = [], + out_message = []; nodeSync.stdout.on('data', (out) => { out_message.push(out.toString().trim()); @@ -74,8 +74,8 @@ router.get('/price', (req, res) => { const nodeSync = spawn(celocli, ['exchange:show', '--amount', amount]); - const err_message = []; - const out_message = []; + let err_message = [], + out_message = []; nodeSync.stdout.on('data', (out) => { out_message.push(out.toString().trim()); @@ -86,17 +86,17 @@ router.get('/price', (req, res) => { }); nodeSync.on('close', (code) => { - const exchange_rates = {}; + let exchange_rates = {}; let price; if (code === 0) { // extract exchange rate from cli output out_message.forEach((item, _index) => { if (item.includes(separator)) { - const exchangeInfo = item.split(separator); - const base = exchangeInfo[0].trim().split(' '); - const quote = exchangeInfo[1].trim().split(' '); - const market = [base[1].toUpperCase(), quote[1].toUpperCase()].join( + let exchangeInfo = item.split(separator); + let base = exchangeInfo[0].trim().split(' '); + let quote = exchangeInfo[1].trim().split(' '); + let market = [base[1].toUpperCase(), quote[1].toUpperCase()].join( '-' ); exchange_rates[market] = quote[0] / DENOM_UNIT_MULTIPLIER; @@ -107,7 +107,7 @@ router.get('/price', (req, res) => { price = exchange_rates[tradingPair]; const result = Object.assign(paramData, { - price, + price: price, timestamp: initTime, latency: hbUtils.latency(initTime, Date.now()) }); @@ -128,9 +128,9 @@ router.get('/balance', (req, res) => { const balance = spawn(celocli, ['account:balance', address]); - const err_message = []; - const out_message = []; - const walletBalances = {}; + let err_message = [], + out_message = []; + let walletBalances = {}; balance.stdout.on('data', (out) => { out_message.push(out.toString().trim()); @@ -150,9 +150,9 @@ router.get('/balance', (req, res) => { item.toLowerCase().includes('lockedcelo') || item.toLowerCase().includes('lockedgold') ) { - const balanceArray = item.split('\n'); + let balanceArray = item.split('\n'); balanceArray.forEach((x) => { - const keyValue = x.split(':'); + let keyValue = x.split(':'); walletBalances[keyValue[0].trim()] = keyValue[1].trim() / DENOM_UNIT_MULTIPLIER; }); @@ -161,7 +161,7 @@ router.get('/balance', (req, res) => { }); res.status(200).json({ - address, + address: address, balance: walletBalances, timestamp: Date.now() }); @@ -197,8 +197,8 @@ router.post('/unlock', (req, res) => { secret ]); - const err_message = []; - const out_message = []; + let err_message = [], + out_message = []; lockStatus.stdout.on('data', (out) => { out_message.push(out.toString().trim()); @@ -223,7 +223,7 @@ router.post('/unlock', (req, res) => { unlocked = true; } res.status(200).json({ - unlocked, + unlocked: unlocked, message: out_message.join(), timestamp: Date.now() }); diff --git a/src/routes/eth.route.js b/src/routes/eth.route.js index 4cc1cb7..e80dbcf 100644 --- a/src/routes/eth.route.js +++ b/src/routes/eth.route.js @@ -91,7 +91,7 @@ router.post('/balances', async (req, res) => { network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), - balances + balances: balances }); }); } catch (err) { @@ -163,8 +163,8 @@ router.post('/allowances', async (req, res) => { network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), - spender, - approvals + spender: spender, + approvals: approvals }); }); } catch (err) { @@ -230,7 +230,7 @@ router.post('/balances-2', async (req, res) => { network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), - balances + balances: balances }); }); } catch (err) { @@ -297,8 +297,8 @@ router.post('/allowances-2', async (req, res) => { network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), - spender, - approvals + spender: spender, + approvals: approvals }); }); } catch (err) { @@ -372,10 +372,10 @@ router.post('/approve', async (req, res) => { network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), - tokenAddress, - spender, + tokenAddress: tokenAddress, + spender: spender, amount: amount / (1e18).toString(), - approval + approval: approval }); } catch (err) { logger.error(req.originalUrl, { message: err }); @@ -396,7 +396,7 @@ router.post('/poll', async (req, res) => { const txHash = paramData.txHash; const txReceipt = await eth.provider.getTransactionReceipt(txHash); const receipt = {}; - const confirmed = !!(txReceipt && txReceipt.blockNumber); + const confirmed = txReceipt && txReceipt.blockNumber ? true : false; if (confirmed) { receipt.gasUsed = BigNumber.from(txReceipt.gasUsed).toNumber(); receipt.blockNumber = txReceipt.blockNumber; @@ -411,9 +411,9 @@ router.post('/poll', async (req, res) => { network: eth.network, timestamp: initTime, latency: latency(initTime, Date.now()), - txHash, - confirmed, - receipt + txHash: txHash, + confirmed: confirmed, + receipt: receipt }); return txReceipt; }); diff --git a/src/routes/perpetual_finance.route.js b/src/routes/perpetual_finance.route.js index d2acf51..e03adbb 100644 --- a/src/routes/perpetual_finance.route.js +++ b/src/routes/perpetual_finance.route.js @@ -31,7 +31,7 @@ router.get('/load-metadata', async (req, res) => { res.status(200).json({ network: perpFi.network, provider: perpFi.provider.connection.url, - loadedMetadata, + loadedMetadata: loadedMetadata, connection: true, timestamp: Date.now() }); @@ -61,14 +61,14 @@ router.post('/balances', async (req, res) => { } const balances = {}; - balances.XDAI = await perpFi.getXdaiBalance(wallet); - balances.USDC = await perpFi.getUSDCBalance(wallet); + balances['XDAI'] = await perpFi.getXdaiBalance(wallet); + balances['USDC'] = await perpFi.getUSDCBalance(wallet); try { res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - balances + balances: balances }); } catch (err) { let reason; @@ -106,13 +106,13 @@ router.post('/allowances', async (req, res) => { } const approvals = {}; - approvals.USDC = await perpFi.getAllowance(wallet); + approvals['USDC'] = await perpFi.getAllowance(wallet); try { res.status(200).json({ network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - approvals + approvals: approvals }); } catch (err) { let reason; @@ -162,8 +162,8 @@ router.post('/approve', async (req, res) => { network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - amount, - approval + amount: amount, + approval: approval }); } catch (err) { logger.error(req.originalUrl, { message: err }); @@ -229,10 +229,10 @@ router.post('/open', async (req, res) => { network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - margin, - side, - leverage, - minBaseAssetAmount, + margin: margin, + side: side, + leverage: leverage, + minBaseAssetAmount: minBaseAssetAmount, txHash: tx.hash }); } catch (err) { @@ -285,7 +285,7 @@ router.post('/close', async (req, res) => { network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - minimalQuoteAsset, + minimalQuoteAsset: minimalQuoteAsset, txHash: tx.hash }); } catch (err) { @@ -336,7 +336,7 @@ router.post('/position', async (req, res) => { network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - position + position: position }); } catch (err) { logger.error(req.originalUrl, { message: err }); @@ -411,7 +411,7 @@ router.post('/receipt', async (req, res) => { const txHash = paramData.txHash; const txReceipt = await perpFi.provider.getTransactionReceipt(txHash); const receipt = {}; - const confirmed = !!(txReceipt && txReceipt.blockNumber); + const confirmed = txReceipt && txReceipt.blockNumber ? true : false; if (txReceipt !== null) { receipt.gasUsed = ethers.utils.formatEther(txReceipt.gasUsed); receipt.blockNumber = txReceipt.blockNumber; @@ -425,9 +425,9 @@ router.post('/receipt', async (req, res) => { network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - txHash, - confirmed, - receipt + txHash: txHash, + confirmed: confirmed, + receipt: receipt }); return txReceipt; }); @@ -456,8 +456,8 @@ router.post('/price', async (req, res) => { network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - side, - price + side: side, + price: price }); } catch (err) { logger.error(req.originalUrl, { message: err }); @@ -518,7 +518,7 @@ router.post('/funding', async (req, res) => { network: perpFi.network, timestamp: initTime, latency: latency(initTime, Date.now()), - fr + fr: fr }); } catch (err) { logger.error(req.originalUrl, { message: err }); diff --git a/src/routes/terra.route.js b/src/routes/terra.route.js index 48cb9be..e385295 100644 --- a/src/routes/terra.route.js +++ b/src/routes/terra.route.js @@ -1,3 +1,5 @@ +'use strict'; + import express from 'express'; import { getParamData, @@ -21,7 +23,7 @@ router.post('/', async (req, res) => { POST / */ res.status(200).json({ - network, + network: network, lcdUrl: terra.lcd.config.URL, gasPrices: terra.lcd.config.gasPrices, gasAdjustment: terra.lcd.config.gasAdjustment, @@ -40,7 +42,7 @@ router.post('/balances', async (req, res) => { const paramData = getParamData(req.body); const address = paramData.address; - const balances = {}; + let balances = {}; try { await terra.lcd.bank.balance(address).then((bal) => { @@ -54,10 +56,10 @@ router.post('/balances', async (req, res) => { }); logger.info('terra.route - Get Account Balance'); res.status(200).json({ - network, + network: network, timestamp: initTime, latency: latency(initTime, Date.now()), - balances + balances: balances }); } catch (err) { logger.error(req.originalUrl, { message: err }); @@ -75,7 +77,7 @@ router.post('/balances', async (req, res) => { } res.status(500).json({ error: reason, - message + message: message }); } }); @@ -95,7 +97,7 @@ router.post('/start', async (req, res) => { const quoteTokenSymbol = paramData.quote; const result = { - network, + network: network, timestamp: initTime, latency: latency(initTime, Date.now()), success: true, @@ -136,13 +138,13 @@ router.post('/price', async (req, res) => { }); res.status(200).json({ - network, + network: network, timestamp: initTime, latency: latency(initTime, Date.now()), base: baseToken, quote: quoteToken, - amount, - tradeType, + amount: amount, + tradeType: tradeType, price: exchangeRate.price.amount, cost: exchangeRate.cost.amount, txFee: exchangeRate.txFee.amount @@ -163,7 +165,7 @@ router.post('/price', async (req, res) => { } res.status(500).json({ error: reason, - message + message: message }); } }); @@ -213,13 +215,13 @@ router.post('/trade', async (req, res) => { }); const swapResult = { - network, + network: network, timestamp: initTime, latency: latency(initTime, Date.now()), base: baseToken, - tradeType, + tradeType: tradeType, quote: quoteToken, - amount + amount: amount }; Object.assign(swapResult, tokenSwaps); logger.info( @@ -242,7 +244,7 @@ router.post('/trade', async (req, res) => { } res.status(500).json({ error: reason, - message + message: message }); } }); diff --git a/src/routes/uniswap.route.js b/src/routes/uniswap.route.js index 6017b14..1e9b20b 100644 --- a/src/routes/uniswap.route.js +++ b/src/routes/uniswap.route.js @@ -20,7 +20,9 @@ const fees = new Fees(); const swapMoreThanMaxPriceError = 'Price too high'; const swapLessThanMaxPriceError = 'Price too low'; -const estimateGasLimit = () => uniswap.gasLimit; +const estimateGasLimit = () => { + return uniswap.gasLimit; +}; const getErrorMessage = (err) => { /* @@ -61,7 +63,7 @@ router.post('/gas-limit', async (req, res) => { try { res.status(200).json({ network: uniswap.network, - gasLimit, + gasLimit: gasLimit, timestamp: Date.now() }); } catch (err) { @@ -134,10 +136,10 @@ router.get('/start', async (req, res) => { timestamp: initTime, latency: latency(initTime, Date.now()), success: true, - pairs, - gasPrice, - gasLimit, - gasCost + pairs: pairs, + gasPrice: gasPrice, + gasLimit: gasLimit, + gasCost: gasCost }; res.status(200).json(result); }); @@ -214,10 +216,10 @@ router.post('/trade', async (req, res) => { latency: latency(initTime, Date.now()), base: baseTokenAddress, quote: quoteTokenAddress, - amount, + amount: amount, expectedIn: expectedAmount.toSignificant(8), - price, - gasPrice, + price: price, + gasPrice: gasPrice, gasLimit, gasCost, txHash: tx.hash @@ -253,9 +255,9 @@ router.post('/trade', async (req, res) => { amount: parseFloat(paramData.amount), expectedOut: expectedAmount.toSignificant(8), price: parseFloat(price), - gasPrice, + gasPrice: gasPrice, gasLimit, - gasCost, + gasCost: gasCost, txHash: tx.hash }); } else { @@ -343,10 +345,10 @@ router.post('/price', async (req, res) => { amount: tradeAmount, expectedAmount: expectedTradeAmount, price: tradePrice, - gasPrice, - gasLimit, - gasCost, - trade + gasPrice: gasPrice, + gasLimit: gasLimit, + gasCost: gasCost, + trade: trade }; debug( `Price ${side} ${baseTokenContractInfo.symbol}-${quoteTokenContractInfo.symbol} | amount:${amount} (rate:${tradePrice}) - gasPrice:${gasPrice} gasLimit:${gasLimit} estimated fee:${gasCost} ETH` @@ -365,7 +367,8 @@ router.post('/price', async (req, res) => { let errCode = 500; if (Object.keys(err).includes('isInsufficientReservesError')) { errCode = 200; - reason = `${statusMessages.insufficient_reserves} in ${side} at Uniswap`; + reason = + statusMessages.insufficient_reserves + ' in ' + side + ' at Uniswap'; } else if (Object.getOwnPropertyNames(err).includes('message')) { reason = getErrorMessage(err.message); if (reason === statusMessages.no_pool_available) { diff --git a/src/routes/uniswap_v3.route.js b/src/routes/uniswap_v3.route.js index 6b434a0..d359588 100644 --- a/src/routes/uniswap_v3.route.js +++ b/src/routes/uniswap_v3.route.js @@ -1,12 +1,8 @@ import { ethers } from 'ethers'; import express from 'express'; -import { - getNonceManager, - getParamData, - latency, - statusMessages -} from '../services/utils'; +import { getNonceManager } from '../services/utils'; +import { getParamData, latency, statusMessages } from '../services/utils'; import { logger } from '../services/logger'; import Ethereum from '../services/eth'; import UniswapV3 from '../services/uniswap_v3'; @@ -16,17 +12,18 @@ const globalConfig = require('../services/configuration_manager').configManagerInstance; const debug = require('debug')('router'); - const router = express.Router(); const eth = new Ethereum(globalConfig.getConfig('ETHEREUM_CHAIN')); const uniswap = new UniswapV3(globalConfig.getConfig('ETHEREUM_CHAIN')); const fees = new Fees(); -// const swapMoreThanMaxPriceError = 'Price too high' -// const swapLessThanMaxPriceError = 'Price too low' +//const swapMoreThanMaxPriceError = 'Price too high' +//const swapLessThanMaxPriceError = 'Price too low' -const estimateGasLimit = () => uniswap.gasLimit; +const estimateGasLimit = () => { + return uniswap.gasLimit; +}; const getErrorMessage = (err) => { /* @@ -67,7 +64,7 @@ router.post('/gas-limit', async (req, res) => { try { res.status(200).json({ network: uniswap.network, - gasLimit, + gasLimit: gasLimit, timestamp: Date.now() }); } catch (err) { @@ -166,12 +163,12 @@ router.post('/trade', async (req, res) => { latency: latency(initTime, Date.now()), base: baseTokenAddress, quote: quoteTokenAddress, - amount, + amount: amount, expectedIn: tx.expectedAmount, price: limitPrice, - gasPrice, - gasLimit, - gasCost, + gasPrice: gasPrice, + gasLimit: gasLimit, + gasCost: gasCost, txHash: tx.hash }); } else { @@ -196,9 +193,9 @@ router.post('/trade', async (req, res) => { amount: parseFloat(paramData.amount), expectedOut: tx.expectedAmount, price: limitPrice, - gasPrice, - gasLimit, - gasCost, + gasPrice: gasPrice, + gasLimit: gasLimit, + gasCost: gasCost, txHash: tx.hash }); } @@ -236,6 +233,7 @@ router.post('/price', async (req, res) => { const baseTokenAddress = baseTokenContractInfo.address; const quoteTokenAddress = quoteTokenContractInfo.address; + //const side = paramData.side.toUpperCase() // not used for now let gasPrice; if (paramData.gasPrice) { gasPrice = parseFloat(paramData.gasPrice); @@ -259,10 +257,10 @@ router.post('/price', async (req, res) => { latency: latency(initTime, Date.now()), base: baseTokenAddress, quote: quoteTokenAddress, - prices, - gasPrice, - gasLimit, - gasCost + prices: prices, + gasPrice: gasPrice, + gasLimit: gasLimit, + gasCost: gasCost }; debug( `Mid Price ${baseTokenContractInfo.symbol}-${ @@ -278,7 +276,7 @@ router.post('/price', async (req, res) => { let errCode = 500; if (Object.keys(err).includes('isInsufficientReservesError')) { errCode = 200; - reason = `${statusMessages.insufficient_reserves} at Uniswap`; + reason = statusMessages.insufficient_reserves + ' in ' + ' at Uniswap'; } else if (Object.getOwnPropertyNames(err).includes('message')) { reason = getErrorMessage(err.message); if (reason === statusMessages.no_pool_available) { @@ -394,15 +392,15 @@ router.post('/add-position', async (req, res) => { latency: latency(initTime, Date.now()), token0: paramData.token0, token1: paramData.token1, - fee, - amount0, - amount1, - lowerPrice, - upperPrice, + fee: fee, + amount0: amount0, + amount1: amount1, + lowerPrice: lowerPrice, + upperPrice: upperPrice, hash: newPosition.hash, - gasPrice, - gasLimit, - gasCost + gasPrice: gasPrice, + gasLimit: gasLimit, + gasCost: gasCost }; debug(`New Position: ${newPosition.hash}`); res.status(200).json(result); @@ -447,16 +445,16 @@ router.post('/remove-position', async (req, res) => { timestamp: initTime, latency: latency(initTime, Date.now()), hash: removelp.hash, - gasPrice, - gasLimit, - gasCost + gasPrice: gasPrice, + gasLimit: gasLimit, + gasCost: gasCost }; debug(`Remove lp: ${removelp.hash}`); res.status(200).json(result); } catch (err) { logger.error(req.originalUrl, { message: err }); let reason; - const errCode = 500; + let errCode = 500; err.reason ? (reason = err.reason) : (reason = statusMessages.operation_error); @@ -525,13 +523,13 @@ router.post('/replace-position', async (req, res) => { network: uniswap.network, timestamp: initTime, latency: latency(initTime, Date.now()), - tokenId, - amount0, - amount1, + tokenId: tokenId, + amount0: amount0, + amount1: amount1, hash: positionChange.hash, - gasPrice, - gasLimit, - gasCost + gasPrice: gasPrice, + gasLimit: gasLimit, + gasCost: gasCost }; debug(`Position change ${positionChange.hash}`); res.status(200).json(result); @@ -578,11 +576,11 @@ router.post('/collect-fees', async (req, res) => { network: uniswap.network, timestamp: initTime, latency: latency(initTime, Date.now()), - tokenId, + tokenId: tokenId, hash: collect.hash, - gasPrice, - gasLimit, - gasCost + gasPrice: gasPrice, + gasLimit: gasLimit, + gasCost: gasCost }; debug(`Fees: ${collect.hash}`); res.status(200).json(result); diff --git a/src/services/access.js b/src/services/access.js index cf374b9..2596057 100644 --- a/src/services/access.js +++ b/src/services/access.js @@ -11,7 +11,7 @@ export const validateAccess = (req, res, next) => { const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; const method = req.method; const url = req.url; - const requestInfo = `Request from IP: ${ip} ${method} ${url}`; + const requestInfo = 'Request from IP: ' + ip + ' ' + method + ' ' + url; console.log(requestInfo); next(); } else if (cert.subject) { diff --git a/src/services/balancer.js b/src/services/balancer.js index 7fb60bc..2fe5b3e 100644 --- a/src/services/balancer.js +++ b/src/services/balancer.js @@ -108,12 +108,12 @@ export default class Balancer { debug(`Expected Out: ${expectedAmount.toString()} (${tokenOut})`); // Create correct swap format for new proxy - const swaps = []; + let swaps = []; for (let i = 0; i < swapsFormatted.length; i++) { - const swap = { + let swap = { pool: swapsFormatted[i].pool, - tokenIn, - tokenOut, + tokenIn: tokenIn, + tokenOut: tokenOut, swapAmount: swapsFormatted[i].tokenInParam, limitReturnAmount: swapsFormatted[i].tokenOutParam, maxPrice: swapsFormatted[i].maxPrice.toString() @@ -172,12 +172,12 @@ export default class Balancer { debug(`Expected In: ${expectedAmount.toString()} (${tokenIn})`); // Create correct swap format for new proxy - const swaps = []; + let swaps = []; for (let i = 0; i < swapsFormatted.length; i++) { - const swap = { + let swap = { pool: swapsFormatted[i].pool, - tokenIn, - tokenOut, + tokenIn: tokenIn, + tokenOut: tokenOut, swapAmount: swapsFormatted[i].tokenOutParam, limitReturnAmount: swapsFormatted[i].tokenInParam, maxPrice: swapsFormatted[i].maxPrice.toString() diff --git a/src/services/eth.js b/src/services/eth.js index a9d7768..2db6410 100644 --- a/src/services/eth.js +++ b/src/services/eth.js @@ -1,5 +1,5 @@ -import axios from 'axios'; import { logger } from './logger'; +import axios from 'axios'; const fs = require('fs'); const ethers = require('ethers'); @@ -18,7 +18,13 @@ export default class Ethereum { this.provider = new ethers.providers.JsonRpcProvider(providerUrl); this.erc20TokenListURL = globalConfig.getConfig('ETHEREUM_TOKEN_LIST_URL'); this.network = network; - + /* + this.spenders = { + balancer: process.env.EXCHANGE_PROXY, + uniswap: process.env.UNISWAP_ROUTER, + uniswapV3: process.UNISWAP_V3_ROUTER + } + */ // update token list this.getERC20TokenList(); // erc20TokenList } @@ -48,7 +54,7 @@ export default class Ethereum { ); try { const balance = await contract.balanceOf(wallet.address); - return balance / (10 ** decimals).toString(); + return balance / Math.pow(10, decimals).toString(); } catch (err) { logger.error(err); let reason; @@ -67,7 +73,7 @@ export default class Ethereum { ); try { const allowance = await contract.allowance(wallet.address, spender); - return allowance / (10 ** decimals).toString(); + return allowance / Math.pow(10, decimals).toString(); } catch (err) { logger.error(err); let reason; @@ -105,7 +111,7 @@ export default class Ethereum { // get current Gas async getCurrentGasPrice() { try { - this.provider.getGasPrice().then((gas) => { + this.provider.getGasPrice().then(function (gas) { // gasPrice is a BigNumber; convert it to a decimal string const gasPrice = gas.toString(); return gasPrice; @@ -135,7 +141,7 @@ export default class Ethereum { return await contract.deposit({ value: amount, gasPrice: gasPrice * 1e9, - gasLimit + gasLimit: gasLimit }); } catch (err) { logger.error(err); @@ -189,16 +195,16 @@ export default class Ethereum { // Refactor name to getERC20TokenByName getERC20TokenAddresses(tokenSymbol) { - const tokenContractAddress = this.erc20TokenList.tokens.filter( - (obj) => obj.symbol === tokenSymbol.toUpperCase() - ); + const tokenContractAddress = this.erc20TokenList.tokens.filter((obj) => { + return obj.symbol === tokenSymbol.toUpperCase(); + }); return tokenContractAddress[0]; } getERC20TokenByAddress(tokenAddress) { - const tokenContract = this.erc20TokenList.tokens.filter( - (obj) => obj.address.toUpperCase() === tokenAddress.toUpperCase() - ); + const tokenContract = this.erc20TokenList.tokens.filter((obj) => { + return obj.address.toUpperCase() === tokenAddress.toUpperCase(); + }); return tokenContract[0]; } } diff --git a/src/services/fees.js b/src/services/fees.js index a75d5a4..79fe725 100644 --- a/src/services/fees.js +++ b/src/services/fees.js @@ -1,6 +1,6 @@ +import { logger } from './logger'; import axios from 'axios'; import BigNumber from 'bignumber.js'; -import { logger } from './logger'; // constants const ethGasStationHost = 'https://ethgasstation.info'; diff --git a/src/services/perpetual_finance.js b/src/services/perpetual_finance.js index 6161076..b4e2d63 100644 --- a/src/services/perpetual_finance.js +++ b/src/services/perpetual_finance.js @@ -54,7 +54,7 @@ export default class PerpetualFinance { ); const layer2 = Object.keys(metadata.layers.layer2.contracts); - for (const key of layer2) { + for (var key of layer2) { if (metadata.layers.layer2.contracts[key].name === 'Amm') { this.amm[key] = metadata.layers.layer2.contracts[key].address; } else { @@ -74,15 +74,15 @@ export default class PerpetualFinance { async update_price_loop() { if (Object.keys(this.cacheExpirary).length > 0) { - for (const pair in this.cacheExpirary) { + for (let pair in this.cacheExpirary) { if (this.cacheExpirary[pair] <= Date.now()) { delete this.cacheExpirary[pair]; delete this.priceCache[pair]; } } - for (const pair in this.cacheExpirary) { - const amm = new Ethers.Contract( + for (let pair in this.cacheExpirary) { + let amm = new Ethers.Contract( this.amm[pair], AmmArtifact.abi, this.provider @@ -139,7 +139,7 @@ export default class PerpetualFinance { TetherTokenArtifact.abi, wallet ); - const layer2UsdcBalance = await layer2Usdc.balanceOf(wallet.address); + let layer2UsdcBalance = await layer2Usdc.balanceOf(wallet.address); const layer2UsdcDecimals = await layer2Usdc.decimals(); return Ethers.utils.formatUnits(layer2UsdcBalance, layer2UsdcDecimals); } catch (err) { @@ -200,7 +200,7 @@ export default class PerpetualFinance { } } - // open Position + //open Position async openPosition(side, margin, levrg, pair, minBaseAmount, wallet) { try { const quoteAssetAmount = { @@ -232,7 +232,7 @@ export default class PerpetualFinance { } } - // close Position + //close Position async closePosition(wallet, pair, minimalQuote) { try { const minimalQuoteAsset = { @@ -257,7 +257,7 @@ export default class PerpetualFinance { } } - // get active position + //get active position async getPosition(wallet, pair) { try { const positionValues = {}; @@ -323,7 +323,7 @@ export default class PerpetualFinance { } } - // get active margin + //get active margin async getActiveMargin(wallet) { try { const clearingHouseViewer = new Ethers.Contract( @@ -370,10 +370,12 @@ export default class PerpetualFinance { }); price = Ethers.utils.formatUnits(price.d) / amount; } - } else if (side === 'buy') { - price = this.priceCache[pair][0]; } else { - price = this.priceCache[pair][1]; + if (side === 'buy') { + price = this.priceCache[pair][0]; + } else { + price = this.priceCache[pair][1]; + } } return price; } catch (err) { @@ -388,7 +390,7 @@ export default class PerpetualFinance { // get getFundingRate async getFundingRate(pair) { try { - const funding = {}; + let funding = {}; const amm = new Ethers.Contract( this.amm[pair], AmmArtifact.abi, diff --git a/src/services/terra.js b/src/services/terra.js index 18faec6..fe2698f 100644 --- a/src/services/terra.js +++ b/src/services/terra.js @@ -1,3 +1,4 @@ +import { logger } from './logger'; import { LCDClient, Coin, @@ -6,7 +7,6 @@ import { isTxError } from '@terra-money/terra.js'; import BigNumber from 'bignumber.js'; -import { logger } from './logger'; import { getHummingbotMemo } from './utils'; const debug = require('debug')('router'); @@ -93,7 +93,7 @@ export default class Terra { // get Token Symbol getTokenSymbol(denom) { try { - const { symbol } = TERRA_TOKENS[denom]; + const symbol = TERRA_TOKENS[denom].symbol; return symbol; } catch (err) { logger.error(err); @@ -106,7 +106,7 @@ export default class Terra { } getTxAttributes(attributes) { - const attrib = {}; + let attrib = {}; attributes.forEach((item) => { attrib[item.key] = item.value; }); @@ -144,7 +144,7 @@ export default class Terra { async getTxFee() { try { const lunaFee = GAS_PRICE.uluna * GAS_ADJUSTMENT; - const feeList = { uluna: lunaFee }; + let feeList = { uluna: lunaFee }; await this.lcd.oracle.exchangeRates().then((rates) => { Object.keys(rates._coins).forEach((key) => { feeList[key] = rates._coins[key].amount * lunaFee; @@ -166,14 +166,14 @@ export default class Terra { // get Terra Swap Rate async getSwapRate(baseToken, quoteToken, amount, tradeType) { try { - let exchangeRate; - let offerCoin; - let offerDenom; - let swapDenom; - let cost; - let costAmount; - let offer; - const swaps = {}; + let exchangeRate, + offerCoin, + offerDenom, + swapDenom, + cost, + costAmount, + offer; + let swaps = {}; if (tradeType.toLowerCase() === 'sell') { // sell base @@ -184,7 +184,7 @@ export default class Terra { await this.lcd.market .swapRate(offerCoin, swapDenom) .then((swapCoin) => { - offer = { amount }; + offer = { amount: amount }; exchangeRate = { amount: swapCoin.amount / DENOM_UNIT / amount, token: quoteToken @@ -273,11 +273,9 @@ export default class Terra { const baseDenom = this.getTokenDenom(baseToken); const quoteDenom = this.getTokenDenom(quoteToken); - let offerDenom; - let swapDenom; - let swaps; - let txAttributes; - const tokenSwap = {}; + let offerDenom, swapDenom; + let swaps, txAttributes; + let tokenSwap = {}; if (tradeType.toLowerCase() === 'sell') { offerDenom = baseDenom; @@ -309,7 +307,7 @@ export default class Terra { txOptions = { msgs: [msgSwap], gasPrices: { uluna: parseFloat(gasPrice) }, - gasAdjustment, + gasAdjustment: gasAdjustment, memo: this.memo }; } else { @@ -335,8 +333,10 @@ export default class Terra { ); } const txHash = txResult.txhash; - const { events } = JSON.parse(txResult.raw_log)[0]; - const swap = events.find((obj) => obj.type === 'swap'); + const events = JSON.parse(txResult.raw_log)[0].events; + const swap = events.find((obj) => { + return obj.type === 'swap'; + }); txAttributes = this.getTxAttributes(swap.attributes); const offer = Coin.fromString(txAttributes.offer); const ask = Coin.fromString(txAttributes.swap_coin); diff --git a/src/services/uniswap.js b/src/services/uniswap.js index 7d8bf97..cbb0247 100644 --- a/src/services/uniswap.js +++ b/src/services/uniswap.js @@ -56,8 +56,7 @@ export default class Uniswap { } async fetch_route(tIn, tOut) { - let route; - let pair; + var route, pair; try { pair = await uni.Fetcher.fetchPairData(tIn, tOut); @@ -69,19 +68,19 @@ export default class Uniswap { } generate_tokens() { - for (const token of routeTokens[this.network]) { - this.tokenList[token.address] = new uni.Token( + for (let token of routeTokens[this.network]) { + this.tokenList[token['address']] = new uni.Token( this.chainID, - token.address, - token.decimals, - token.symbol, - token.name + token['address'], + token['decimals'], + token['symbol'], + token['name'] ); } } async extend_update_pairs(tokens = []) { - for (const token of tokens) { + for (let token of tokens) { if (!Object.prototype.hasOwnProperty.call(this.tokenList, token)) { this.tokenList[token] = await uni.Fetcher.fetchTokenData( this.chainID, @@ -95,7 +94,7 @@ export default class Uniswap { async update_pairs() { // Remove banned pairs after ban period if (Object.keys(this.zeroReservePairs).length > 0) { - for (const pair in this.zeroReservePairs) { + for (let pair in this.zeroReservePairs) { if (this.zeroReservePairs[pair] <= Date.now()) { delete this.zeroReservePairs[pair]; // delete this.tokenList[token]; @@ -105,21 +104,19 @@ export default class Uniswap { // Generate all possible pair combinations of tokens // This is done by generating an upper triangular matrix or right triangular matrix if (Object.keys(this.tokenSwapList).length > 0) { - for (const token in this.tokenSwapList) { + for (let token in this.tokenSwapList) { if (this.tokenSwapList[token] <= Date.now()) { delete this.tokenSwapList[token]; // delete this.tokenList[token]; } } - const tokens = Object.keys(this.tokenList); - let firstToken; - let secondToken; - let position; - const length = tokens.length; - const pairs = []; - const pairAddressRequests = []; - const pairAddressResponses = []; + let tokens = Object.keys(this.tokenList); + var firstToken, secondToken, position; + let length = tokens.length; + let pairs = []; + let pairAddressRequests = []; + let pairAddressResponses = []; for (firstToken = 0; firstToken < length; firstToken++) { for ( secondToken = firstToken + 1; @@ -127,9 +124,10 @@ export default class Uniswap { secondToken++ ) { try { - const pairString = `${this.tokenList[tokens[firstToken]].address}-${ - this.tokenList[tokens[secondToken]].address - }`; + let pairString = + this.tokenList[tokens[firstToken]].address + + '-' + + this.tokenList[tokens[secondToken]].address; if ( !Object.prototype.hasOwnProperty.call( this.zeroReservePairs, diff --git a/src/services/uniswap_v3.js b/src/services/uniswap_v3.js index 88fe990..12e90fc 100644 --- a/src/services/uniswap_v3.js +++ b/src/services/uniswap_v3.js @@ -12,7 +12,7 @@ const coreArtifact = require('@uniswap/v3-core/artifacts/contracts/UniswapV3Fact const nftArtifact = require('@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'); const routerArtifact = require('@uniswap/v3-periphery/artifacts/contracts/SwapRouter.sol/SwapRouter.json'); const poolArtifact = require('@uniswap/v3-core/artifacts/contracts/UniswapV3Pool.sol/UniswapV3Pool.json'); -// const routeTokens = require('../static/uniswap_route_tokens.json') +//const routeTokens = require('../static/uniswap_route_tokens.json') const abiDecoder = require('abi-decoder'); // constants @@ -63,18 +63,17 @@ export default class UniswapV3 { get_contract(contract, wallet) { if (contract === 'core') { return new ethers.Contract(this.core, coreArtifact.abi, wallet); - } - if (contract === 'router') { + } else if (contract === 'router') { return new ethers.Contract(this.router, routerArtifact.abi, wallet); + } else { + return new ethers.Contract(this.nftManager, nftArtifact.abi, wallet); } - return new ethers.Contract(this.nftManager, nftArtifact.abi, wallet); } async currentPrice(wallet, tokenIn, tokenOut) { - let pool; - let poolContract; - const poolPrices = []; - const poolLiquidity = []; + let pool, poolContract; + let poolPrices = []; + let poolLiquidity = []; const keys = ['LOW', 'MEDIUM', 'HIGH']; const coreContract = this.get_contract('core', wallet); @@ -101,7 +100,7 @@ export default class UniswapV3 { for (pool = 0; pool < 3; pool++) { poolPrices[pool] = poolLiquidity[pool] = 0; if (values[pool].value) { - for (const tick of values[pool].value.tickCumulatives) { + for (let tick of values[pool].value.tickCumulatives) { poolPrices[pool] = tick.toNumber() - poolPrices[pool]; } poolPrices[pool] = math.pow(1.0001, poolPrices[pool]); @@ -120,7 +119,7 @@ export default class UniswapV3 { tier, _gasPrice ) { - // sell, In => base, Out => quote + //sell, In => base, Out => quote const minPercentOut = 1 - this.slippage / 100; const amountOutMinimum = Math.floor( @@ -129,7 +128,7 @@ export default class UniswapV3 { minPercentOut * quoteTokenContractInfo.decimals ) / quoteTokenContractInfo.decimals; - // const priceFraction = math.fraction(limitPrice) + //const priceFraction = math.fraction(limitPrice) const contract = this.get_contract('router', wallet); const tx = await contract.exactInputSingle( { @@ -146,9 +145,11 @@ export default class UniswapV3 { amountOutMinimum.toString(), quoteTokenContractInfo.decimals ), + //sqrtPriceLimitX96: encodePriceSqrt(priceFraction.d, priceFraction.n) sqrtPriceLimitX96: 0 }, { + //gasPrice: gasPrice * 1e9, gasLimit: GAS_LIMIT } ); @@ -167,13 +168,13 @@ export default class UniswapV3 { tier, _gasPrice ) { - // buy, In => quote, Out => base + //buy, In => quote, Out => base const maxPercentIn = 1 + this.slippage / 100; const amountInMaximum = Math.ceil( baseAmount * limitPrice * maxPercentIn * quoteTokenContractInfo.decimals ) / quoteTokenContractInfo.decimals; - // const priceFraction = math.fraction(limitPrice) + //const priceFraction = math.fraction(limitPrice) const contract = this.get_contract('router', wallet); const tx = await contract.exactOutputSingle( { @@ -190,9 +191,11 @@ export default class UniswapV3 { amountInMaximum.toString(), quoteTokenContractInfo.decimals ), + //sqrtPriceLimitX96: encodePriceSqrt(priceFraction.d, priceFraction.n) sqrtPriceLimitX96: 0 }, { + //gasPrice: gasPrice * 1e9, gasLimit: GAS_LIMIT } ); @@ -228,8 +231,8 @@ export default class UniswapV3 { 'decreaseLiquidity', [ { - tokenId, - liquidity, + tokenId: tokenId, + liquidity: liquidity, amount0Min: 0, amount1Min: 0, deadline: Date.now() + TTL @@ -238,7 +241,7 @@ export default class UniswapV3 { ); const collectFeesData = contract.interface.encodeFunctionData('collect', [ { - tokenId, + tokenId: tokenId, recipient: wallet.signer.address, amount0Max: MaxUint128, amount1Max: MaxUint128 @@ -321,15 +324,16 @@ export default class UniswapV3 { upperPrice ); - const calls = [mintData]; + let calls = [mintData]; if (pool === ethers.constants.AddressZero) { const tx = await nftContract.multicall([initPoolData, mintData], { gasLimit: GAS_LIMIT }); return tx; + } else { + const tx = await nftContract.multicall(calls, { gasLimit: GAS_LIMIT }); + return tx; } - const tx = await nftContract.multicall(calls, { gasLimit: GAS_LIMIT }); - return tx; } async removePosition(wallet, tokenId) { @@ -342,7 +346,7 @@ export default class UniswapV3 { tokenId, positionData.liquidity ); - return contract.multicall(data, { gasLimit: GAS_LIMIT }); + return await contract.multicall(data, { gasLimit: GAS_LIMIT }); } async replacePosition( @@ -357,7 +361,7 @@ export default class UniswapV3 { upperPrice ) { const contract = this.get_contract('nft', wallet); - const positionData = await this.getPosition(wallet, tokenId); + let positionData = await this.getPosition(wallet, tokenId); const removeData = this.getRemoveLiquidityData( wallet, contract, @@ -376,16 +380,49 @@ export default class UniswapV3 { upperPrice ); - return contract.multicall(removeData.concat(mintData), { + return await contract.multicall(removeData.concat(mintData), { gasLimit: GAS_LIMIT }); } + /* + async adjustLiquidity (wallet, action, tokenId, token0, token1, amount0, amount1) { + const contract = this.get_contract("nft", wallet); + const parsedAmount0 = ethers.utils.parseUnits(amount0, token0.decimals) + const parsedAmount1 = ethers.utils.parseUnits(amount1, token1.decimals) + if (action === "INCREASE") { + return await contract.increaseLiquidity({ + tokenId: tokenId, + amount0Desired: parsedAmount0, + amount1Desired: parsedAmount1, + amount0Min: 0, + amount1Min: 0, + deadline: Date.now() + TTL}, + { gasLimit: GAS_LIMIT }); + } else { + //const liquidity = getLiquidity(ethers.utils.parseUnits(amount0, 6), ethers.utils.parseUnits(amount1, 6)) // use method from sdk to calculate liquidity from amount correctly + const liquidity = getLiquidity(amount0, amount1) + const decreaseLiquidityData = contract.interface.encodeFunctionData('decreaseLiquidity', [{ + tokenId: tokenId, + liquidity: liquidity, + amount0Min: 0, + amount1Min: 0, + deadline: Date.now() + TTL}]); + const collectFeesData = contract.interface.encodeFunctionData('collect', [{ + tokenId: tokenId, + recipient: wallet.signer.address, + amount0Max: MaxUint128, + amount1Max: MaxUint128}]); + + //return await contract.multicall([decreaseLiquidityData, collectFeesData], { gasLimit: GAS_LIMIT }); + } + } + */ async collectFees(wallet, tokenId) { const contract = this.get_contract('nft', wallet); - return contract.collect( + return await contract.collect( { - tokenId, + tokenId: tokenId, recipient: wallet.signer.address, amount0Max: MaxUint128, amount1Max: MaxUint128 diff --git a/src/services/utils.js b/src/services/utils.js index 110f170..f26a891 100644 --- a/src/services/utils.js +++ b/src/services/utils.js @@ -1,7 +1,6 @@ /* Hummingbot Utils */ - const config = require('./configuration_manager'); const lodash = require('lodash'); const moment = require('moment'); @@ -24,8 +23,8 @@ export const latency = (startTime, endTime) => export const isValidParams = (params) => { const values = Object.values(params); - // DO NOT use forEach, it returns callback without breaking the loop for (let i = 0; i < values.length; i++) { + // DO NOT use forEach, it returns callback without breaking the loop if (typeof values[i] === 'undefined') { throw new Error('Invalid input params'); } @@ -96,6 +95,11 @@ export const loadConfig = () => { return config.configManagerInstance.readAllConfigs(); }; +export const updateConfig = (data) => { + globalConfig.updateConfig(data); + return true; +}; + export const getLocalDate = () => { const gmtOffset = globalConfig.getConfig('GMT_OFFSET'); let newDate = moment().format('YYYY-MM-DD hh:mm:ss').trim(); @@ -112,11 +116,6 @@ export const getLocalDate = () => { return newDate; }; -export const updateConfig = (data) => { - globalConfig.updateConfig(data); - return true; -}; - export const nonceManagerCache = {}; export const getNonceManager = async (signer) => { diff --git a/src/static/uniswap-v3/helper_functions.js b/src/static/uniswap-v3/helper_functions.js index 7cc3ae1..6bd0603 100644 --- a/src/static/uniswap-v3/helper_functions.js +++ b/src/static/uniswap-v3/helper_functions.js @@ -1,26 +1,11 @@ import bn from 'bignumber.js'; -import JSBI from 'jsbi'; -import { BigNumber, mulShift, Q32, ZERO, ONE, MaxUint256 } from 'ethers'; +import { BigNumber } from 'ethers'; const math = require('mathjs'); - const TICK_SPACINGS = { LOW: 10, MEDIUM: 60, HIGH: 2000 }; bn.config({ EXPONENTIAL_AT: 999999, DECIMAL_PLACES: 40 }); -export function expandTo18Decimals(n) { - return BigNumber.from(n).mul(BigNumber.from(10).pow(18)); -} - -export function toHex(bigintIsh) { - const bigInt = JSBI.BigInt(bigintIsh); - let hex = bigInt.toString(16); - if (hex.length % 2 !== 0) { - hex = `0${hex}`; - } - return `0x${hex}`; -} - // returns the sqrt price as a 64x96 export function encodePriceSqrt(reserve1, reserve0) { return BigNumber.from( @@ -33,159 +18,8 @@ export function encodePriceSqrt(reserve1, reserve0) { ); } -export function getLiquidity(amount0, amount1) { - return BigNumber.from( - new bn(amount0.toString()) - .multipliedBy(amount1.toString()) - .sqrt() - .toString() - ); - /* let tokenPrice0, tokenPrice1, tokenFraction; - tokenFraction = math.fraction(amount1/amount0) - tokenPrice0 = encodePriceSqrt(tokenFraction.n, tokenFraction.d) - tokenPrice1 = encodePriceSqrt(tokenFraction.d, tokenFraction.n) - return tokenPrice0.mul(tokenPrice1) */ -} - -const TWO = JSBI.BigInt(2); -const POWERS_OF_2 = [128, 64, 32, 16, 8, 4, 2, 1].map((pow) => [ - pow, - JSBI.exponentiate(TWO, JSBI.BigInt(pow)) -]); - -export function mostSignificantBit(x) { - let y = x; - let msb = 0; - for (const [power, min] of POWERS_OF_2) { - if (JSBI.greaterThanOrEqual(y, min)) { - y = JSBI.signedRightShift(y, JSBI.BigInt(power)); - msb += power; - } - } - return msb; -} - -export function getSqrtRatioAtTick(tick) { - const absTick = tick < 0 ? tick * -1 : tick; - - let ratio = - (absTick & 0x1) !== 0 - ? JSBI.BigInt('0xfffcb933bd6fad37aa2d162d1a594001') - : JSBI.BigInt('0x100000000000000000000000000000000'); - if ((absTick & 0x2) !== 0) - ratio = mulShift(ratio, '0xfff97272373d413259a46990580e213a'); - if ((absTick & 0x4) !== 0) - ratio = mulShift(ratio, '0xfff2e50f5f656932ef12357cf3c7fdcc'); - if ((absTick & 0x8) !== 0) - ratio = mulShift(ratio, '0xffe5caca7e10e4e61c3624eaa0941cd0'); - if ((absTick & 0x10) !== 0) - ratio = mulShift(ratio, '0xffcb9843d60f6159c9db58835c926644'); - if ((absTick & 0x20) !== 0) - ratio = mulShift(ratio, '0xff973b41fa98c081472e6896dfb254c0'); - if ((absTick & 0x40) !== 0) - ratio = mulShift(ratio, '0xff2ea16466c96a3843ec78b326b52861'); - if ((absTick & 0x80) !== 0) - ratio = mulShift(ratio, '0xfe5dee046a99a2a811c461f1969c3053'); - if ((absTick & 0x100) !== 0) - ratio = mulShift(ratio, '0xfcbe86c7900a88aedcffc83b479aa3a4'); - if ((absTick & 0x200) !== 0) - ratio = mulShift(ratio, '0xf987a7253ac413176f2b074cf7815e54'); - if ((absTick & 0x400) !== 0) - ratio = mulShift(ratio, '0xf3392b0822b70005940c7a398e4b70f3'); - if ((absTick & 0x800) !== 0) - ratio = mulShift(ratio, '0xe7159475a2c29b7443b29c7fa6e889d9'); - if ((absTick & 0x1000) !== 0) - ratio = mulShift(ratio, '0xd097f3bdfd2022b8845ad8f792aa5825'); - if ((absTick & 0x2000) !== 0) - ratio = mulShift(ratio, '0xa9f746462d870fdf8a65dc1f90e061e5'); - if ((absTick & 0x4000) !== 0) - ratio = mulShift(ratio, '0x70d869a156d2a1b890bb3df62baf32f7'); - if ((absTick & 0x8000) !== 0) - ratio = mulShift(ratio, '0x31be135f97d08fd981231505542fcfa6'); - if ((absTick & 0x10000) !== 0) - ratio = mulShift(ratio, '0x9aa508b5b7a84e1c677de54f3e99bc9'); - if ((absTick & 0x20000) !== 0) - ratio = mulShift(ratio, '0x5d6af8dedb81196699c329225ee604'); - if ((absTick & 0x40000) !== 0) - ratio = mulShift(ratio, '0x2216e584f5fa1ea926041bedfe98'); - if ((absTick & 0x80000) !== 0) - ratio = mulShift(ratio, '0x48a170391f7dc42444e8fa2'); - - if (tick > 0) ratio = JSBI.divide(MaxUint256, ratio); - - // back to Q96 - return JSBI.greaterThan(JSBI.remainder(ratio, Q32), ZERO) - ? JSBI.add(JSBI.divide(ratio, Q32), ONE) - : JSBI.divide(ratio, Q32); -} - -export function getTickAtSqrtRatio(sqrtRatioX96) { - const sqrtRatioX128 = JSBI.leftShift(sqrtRatioX96, JSBI.BigInt(32)); - - const msb = mostSignificantBit(sqrtRatioX128); - - let r; - if (JSBI.greaterThanOrEqual(JSBI.BigInt(msb), JSBI.BigInt(128))) { - r = JSBI.signedRightShift(sqrtRatioX128, JSBI.BigInt(msb - 127)); - } else { - r = JSBI.leftShift(sqrtRatioX128, JSBI.BigInt(127 - msb)); - } - - let log_2 = JSBI.leftShift( - JSBI.subtract(JSBI.BigInt(msb), JSBI.BigInt(128)), - JSBI.BigInt(64) - ); - - for (let i = 0; i < 14; i++) { - r = JSBI.signedRightShift(JSBI.multiply(r, r), JSBI.BigInt(127)); - const f = JSBI.signedRightShift(r, JSBI.BigInt(128)); - log_2 = JSBI.bitwiseOr(log_2, JSBI.leftShift(f, JSBI.BigInt(63 - i))); - r = JSBI.signedRightShift(r, f); - } - - const log_sqrt10001 = JSBI.multiply( - log_2, - JSBI.BigInt('255738958999603826347141') - ); - - const tickLow = JSBI.toNumber( - JSBI.signedRightShift( - JSBI.subtract( - log_sqrt10001, - JSBI.BigInt('3402992956809132418596140100660247210') - ), - JSBI.BigInt(128) - ) - ); - const tickHigh = JSBI.toNumber( - JSBI.signedRightShift( - JSBI.add( - log_sqrt10001, - JSBI.BigInt('291339464771989622907027621153398088495') - ), - JSBI.BigInt(128) - ) - ); - - if (tickLow === tickHigh) { - return tickLow; - } - - return JSBI.lessThanOrEqual(getSqrtRatioAtTick(tickHigh), sqrtRatioX96) - ? tickHigh - : tickLow; -} - -export function getMinTick(tier) { - return Math.ceil(-887272 / TICK_SPACINGS[tier]) * TICK_SPACINGS[tier]; -} - -export function getMaxTick(tier) { - return Math.floor(887272 / TICK_SPACINGS[tier]) * TICK_SPACINGS[tier]; -} - export function getTickFromPrice(price, tier, side) { - let tick = 0; + var tick = 0; if (side === 'UPPER') { tick = math.ceil(math.log(price, 1.0001) / TICK_SPACINGS[tier]) * @@ -198,9 +32,17 @@ export function getTickFromPrice(price, tier, side) { if (tick >= getMaxTick(tier)) { return getMaxTick(tier); - } - if (tick <= getMinTick(tier)) { + } else if (tick <= getMinTick(tier)) { return getMinTick(tier); + } else { + return tick; } - return tick; +} + +export function getMinTick(tier) { + return Math.ceil(-887272 / TICK_SPACINGS[tier]) * TICK_SPACINGS[tier]; +} + +export function getMaxTick(tier) { + return Math.floor(887272 / TICK_SPACINGS[tier]) * TICK_SPACINGS[tier]; } diff --git a/yarn.lock b/yarn.lock index 30acb66..365357b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1564,9 +1564,9 @@ ajv@^6.10.0, ajv@^6.12.4: uri-js "^4.2.2" ajv@^8.0.1: - version "8.5.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.5.0.tgz#695528274bcb5afc865446aa275484049a18ae4b" - integrity sha512-Y2l399Tt1AguU3BPRP9Fn4eN+Or+StUGWCUpbnFyXSo8NZ9S4uj+AG2pjs5apK+ZMOwYOz1+a+VKvKH7CudXgQ== + version "8.6.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.0.tgz#60cc45d9c46a477d80d92c48076d972c342e5720" + integrity sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -4108,9 +4108,9 @@ node-modules-regexp@^1.0.0: integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= node-releases@^1.1.71: - version "1.1.72" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe" - integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw== + version "1.1.73" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.73.tgz#dd4e81ddd5277ff846b80b52bb40c49edf7a7b20" + integrity sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg== nodemon@^2.0.4: version "2.0.7"