From c70b37c33888ef06b90d949c3c46b74391c1b3fa Mon Sep 17 00:00:00 2001 From: vic-en Date: Tue, 23 Mar 2021 22:48:08 +0100 Subject: [PATCH] (feat) optimize Uniswap connector --- .env.example | 6 ++++++ src/services/uniswap.js | 41 ++++++++++++++++++++++++++++++++--------- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/.env.example b/.env.example index ff57de7..14a061e 100644 --- a/.env.example +++ b/.env.example @@ -42,6 +42,12 @@ EXCHANGE_PROXY={exchange_proxy} # Uniswap # Reference: https://uniswap.org/docs/v2/smart-contracts/router02/ UNISWAP_ROUTER=0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D +# allowed slippage for swap transactions +UNISWAP_ALLOWED_SLIPPAGE=1 +# restrict updating pairs that have no reserves or failed for 5 minutes +UNISWAP_NO_RESERVE_CHECK_INTERVAL=300000 +# cache info about pair for 1 second +UNISWAP_PAIRS_CACHE_TIME=1000 # cert CERT_PATH={full_path_to_certs_folder} diff --git a/src/services/uniswap.js b/src/services/uniswap.js index ea732d1..747040e 100644 --- a/src/services/uniswap.js +++ b/src/services/uniswap.js @@ -8,7 +8,7 @@ const routeTokens = require('../static/uniswap_route_tokens.json') // constants const ROUTER = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'; const GAS_LIMIT = 150688; -const TTL = 60; +const TTL = 300; const UPDATE_PERIOD = 300000; // stop updating pair after 5 minutes from last request export default class Uniswap { @@ -17,9 +17,13 @@ export default class Uniswap { this.network = process.env.ETHEREUM_CHAIN this.provider = new ethers.providers.JsonRpcProvider(this.providerUrl) this.router = ROUTER; - this.allowedSlippage = new uni.Percent('0', '100') + this.allowedSlippage = new uni.Percent(process.env.UNISWAP_ALLOWED_SLIPPAGE, '100') + console.log(this.allowedSlippage) + 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 = {} @@ -59,7 +63,7 @@ export default class Uniswap { } } - async update_tokens(tokens=[]){ + 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); @@ -69,6 +73,15 @@ export default class Uniswap { } async update_pairs(){ + // Remove banned pairs after ban period + if (Object.keys(this.zeroReservePairs).length > 0){ + for (let pair in this.zeroReservePairs){ + if (this.zeroReservePairs[pair] <= Date.now()) { + delete this.zeroReservePairs[pair]; + // delete this.tokenList[token]; + } + } + } // 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){ @@ -80,26 +93,36 @@ export default class Uniswap { } let tokens = Object.keys(this.tokenList); - var firstToken, secondToken; + 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{ - pairAddressRequests.push(await uni.Fetcher.fetchPairData(this.tokenList[tokens[firstToken]], this.tokenList[tokens[secondToken]])); + let 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) { logger.error(err); } } } - this.pairs = pairAddressRequests; + + 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), 2000); // update every 2 seconds + setTimeout(this.update_pairs.bind(this), 1000); } async priceSwapIn (tokenIn, tokenOut, tokenInAmount) { - await this.update_tokens([tokenIn, 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)); @@ -121,7 +144,7 @@ export default class Uniswap { } async priceSwapOut (tokenIn, tokenOut, tokenOutAmount) { - await this.update_tokens([tokenIn, tokenOut]); + 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));