Skip to content
This repository was archived by the owner on Feb 25, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down
41 changes: 32 additions & 9 deletions src/services/uniswap.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 = {}
Expand Down Expand Up @@ -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);
Expand All @@ -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){
Expand All @@ -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));
Expand All @@ -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));
Expand Down