From 68ceced11176a54f390df2ea8bee0da10ea2877a Mon Sep 17 00:00:00 2001 From: vic-en Date: Mon, 23 Nov 2020 23:12:14 +0100 Subject: [PATCH 1/4] (refactor) refactor price routes to use execution price from Uniswap's trade class --- src/routes/uniswap.route.js | 46 ++++++++++++++++++++----------------- src/services/uniswap.js | 40 +++++++++++++++++++++----------- 2 files changed, 52 insertions(+), 34 deletions(-) diff --git a/src/routes/uniswap.route.js b/src/routes/uniswap.route.js index 992fb6c..ae3017c 100644 --- a/src/routes/uniswap.route.js +++ b/src/routes/uniswap.route.js @@ -53,15 +53,17 @@ router.post('/sell-price', async (req, res) => { const paramData = getParamData(req.body) const baseTokenAddress = paramData.base const quoteTokenAddress = paramData.quote + const amount = new BigNumber(parseInt(paramData.amount * denomMultiplier)) try { // fetch the optimal pool mix from uniswap - const route = await uniswap.fetch_route( + const { trade, expectedOut} = await uniswap.priceSwapIn( baseTokenAddress, // tokenIn is base asset quoteTokenAddress, // tokenOut is quote asset + amount ) - if (route != null) { + if (trade != null && expectedOut != null) { res.status(200).json({ network: uniswap.network, timestamp: initTime, @@ -69,9 +71,9 @@ router.post('/sell-price', async (req, res) => { base: baseTokenAddress, quote: quoteTokenAddress, amount: parseFloat(paramData.amount), - expectedOut: parseFloat(paramData.amount * route.midPrice.toSignificant(8)), - price: route.midPrice.toSignificant(8), - swaps: route.path, + expectedOut: expectedOut.toSignificant(8), + price: trade.executionPrice.toSignificant(8), + swaps: trade, }) } else { // no pool available res.status(200).json({ @@ -103,14 +105,16 @@ router.post('/buy-price', async (req, res) => { const paramData = getParamData(req.body) const baseTokenAddress = paramData.base const quoteTokenAddress = paramData.quote + const amount = new BigNumber(parseInt(paramData.amount * denomMultiplier)) try { // fetch the optimal pool mix from uniswap - const route = await uniswap.fetch_route( + const { trade, expectedIn } = await uniswap.priceSwapOut( quoteTokenAddress, // tokenIn is quote asset baseTokenAddress, // tokenOut is base asset + amount ) - if (route != null) { + if (trade != null && expectedIn != null) { res.status(200).json({ network: uniswap.network, timestamp: initTime, @@ -118,9 +122,9 @@ router.post('/buy-price', async (req, res) => { base: baseTokenAddress, quote: quoteTokenAddress, amount: parseFloat(paramData.amount), - expectedIn: parseFloat(paramData.amount * route.midPrice.invert().toSignificant(8)), - price: route.midPrice.invert().toSignificant(8), - swaps: route.path, + expectedIn: expectedIn.toSignificant(8), + price: trade.executionPrice.invert().toSignificant(8), + swaps: trade, }) } else { // no pool available res.status(200).json({ @@ -129,6 +133,7 @@ router.post('/buy-price', async (req, res) => { }) } } catch (err) { + console.log(err) let reason err.reason ? reason = err.reason : reason = statusMessages.operation_error res.status(500).json({ @@ -173,20 +178,20 @@ router.post('/sell', async (req, res) => { try { // fetch the optimal pool mix from uniswap - const route = await uniswap.fetch_route( + const { trade, expectedOut} = await uniswap.priceSwapIn( baseTokenAddress, // tokenIn is base asset quoteTokenAddress, // tokenOut is quote asset + amount ) - const price = route.midPrice.toSignificant(8) + const price = trade.executionPrice.toSignificant(8) debug(`Price: ${price.toString()}`) if (!maxPrice || price >= maxPrice) { // pass swaps to exchange-proxy to complete trade const txObj = await uniswap.swapExactIn( wallet, - route, + trade, baseTokenAddress, - amount, gasPrice, ) @@ -198,7 +203,7 @@ router.post('/sell', async (req, res) => { base: baseTokenAddress, quote: quoteTokenAddress, amount: parseFloat(paramData.amount), - expectedOut: parseFloat(paramData.amount * route.midPrice.toSignificant(8)), + expectedOut: expectedOut.toSignificant(8), price: price, gasUsed: parseInt(txObj.gasUsed), txHash: txObj.transactionHash, @@ -253,21 +258,20 @@ router.post('/buy', async (req, res) => { try { // fetch the optimal pool mix from uniswap - const route = await uniswap.fetch_route( + const { trade, expectedIn} = await uniswap.priceSwapOut( quoteTokenAddress, // tokenIn is quote asset baseTokenAddress, // tokenOut is base asset - // amount, + amount, ) - const price = route.midPrice.invert().toSignificant(8) + const price = trade.executionPrice.invert().toSignificant(8) debug(`Price: ${price.toString()}`) if (!maxPrice || price <= maxPrice) { // pass swaps to exchange-proxy to complete trade const txObj = await uniswap.swapExactOut( wallet, - route, + trade, baseTokenAddress, - amount, gasPrice, ) @@ -279,7 +283,7 @@ router.post('/buy', async (req, res) => { base: baseTokenAddress, quote: quoteTokenAddress, amount: parseFloat(paramData.amount), - expectedIn: parseFloat(paramData.amount * route.midPrice.invert().toSignificant(8)), + expectedIn: expectedIn.toSignificant(8), price: price, gasUsed: parseInt(txObj.gasUsed), txHash: txObj.transactionHash, diff --git a/src/services/uniswap.js b/src/services/uniswap.js index 11ebde3..a2863b3 100644 --- a/src/services/uniswap.js +++ b/src/services/uniswap.js @@ -46,12 +46,28 @@ export default class Uniswap { return route } - async swapExactIn (wallet, route, tokenAddress, amountIn, gasPrice) { - const tIn = await uni.Fetcher.fetchTokenData(this.chainID, tokenAddress) - const tokenAmountIn = new uni.TokenAmount(tIn, amountIn) + async priceSwapIn (tokenIn, tokenOut, tokenInAmount) { + const tIn = await uni.Fetcher.fetchTokenData(this.chainID, tokenIn) + const tokenAmountIn = new uni.TokenAmount(tIn, tokenInAmount) + const route = await this.fetch_route(tokenIn, tokenOut) + const trade = uni.Trade.exactIn(route, tokenAmountIn) + const expectedOut = trade.minimumAmountOut(this.allowedSlippage) + return { trade, expectedOut } + } + + async priceSwapOut (tokenIn, tokenOut, tokenOutAmount) { + const tOut = await uni.Fetcher.fetchTokenData(this.chainID, tokenOut) + const tokenAmountOut = new uni.TokenAmount(tOut, tokenOutAmount) + const route = await this.fetch_route(tokenIn, tokenOut) + const trade = uni.Trade.exactOut(route, tokenAmountOut) + const expectedIn = trade.maximumAmountIn(this.allowedSlippage) + return { trade, expectedIn } + } + + async swapExactIn (wallet, trade, tokenAddress, gasPrice) { const result = uni.Router.swapCallParameters( - uni.Trade.exactIn(route, tokenAmountIn), - { + trade, + { ttl: TTL, recipient: wallet.address, allowedSlippage: this.allowedSlippage @@ -73,15 +89,13 @@ export default class Uniswap { return txObj } - async swapExactOut (wallet, route, tokenAddress, amountOut, gasPrice) { - const tOut = await uni.Fetcher.fetchTokenData(this.chainID, tokenAddress) - const tokenAmountOut = new uni.TokenAmount(tOut, amountOut) + async swapExactOut (wallet, trade, tokenAddress, gasPrice) { const result = uni.Router.swapCallParameters( - uni.Trade.exactOut(route, tokenAmountOut), - { - ttl: TTL, - recipient: wallet.address, - allowedSlippage: this.allowedSlippage + trade, + { + ttl: TTL, + recipient: wallet.address, + allowedSlippage: this.allowedSlippage } ) From 840f9f8670e731c1ca3d10f2d7a8135e3b6de88f Mon Sep 17 00:00:00 2001 From: vic-en Date: Tue, 24 Nov 2020 11:51:00 +0100 Subject: [PATCH 2/4] (fix) parse amout correctly --- src/routes/uniswap.route.js | 21 ++++++++------------- src/services/uniswap.js | 4 ++-- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/routes/uniswap.route.js b/src/routes/uniswap.route.js index ae3017c..c82c319 100644 --- a/src/routes/uniswap.route.js +++ b/src/routes/uniswap.route.js @@ -1,4 +1,3 @@ -import BigNumber from 'bignumber.js'; import { ethers } from 'ethers'; import express from 'express'; @@ -11,7 +10,6 @@ const debug = require('debug')('router') const router = express.Router() const uniswap = new Uniswap(process.env.ETHEREUM_CHAIN) -const denomMultiplier = 1e18 const swapMoreThanMaxPriceError = 'Price too high' const swapLessThanMaxPriceError = 'Price too low' @@ -53,7 +51,7 @@ router.post('/sell-price', async (req, res) => { const paramData = getParamData(req.body) const baseTokenAddress = paramData.base const quoteTokenAddress = paramData.quote - const amount = new BigNumber(parseInt(paramData.amount * denomMultiplier)) + const amount = paramData.amount try { // fetch the optimal pool mix from uniswap @@ -70,7 +68,7 @@ router.post('/sell-price', async (req, res) => { latency: latency(initTime, Date.now()), base: baseTokenAddress, quote: quoteTokenAddress, - amount: parseFloat(paramData.amount), + amount: amount, expectedOut: expectedOut.toSignificant(8), price: trade.executionPrice.toSignificant(8), swaps: trade, @@ -105,7 +103,7 @@ router.post('/buy-price', async (req, res) => { const paramData = getParamData(req.body) const baseTokenAddress = paramData.base const quoteTokenAddress = paramData.quote - const amount = new BigNumber(parseInt(paramData.amount * denomMultiplier)) + const amount = paramData.amount try { // fetch the optimal pool mix from uniswap @@ -121,7 +119,7 @@ router.post('/buy-price', async (req, res) => { latency: latency(initTime, Date.now()), base: baseTokenAddress, quote: quoteTokenAddress, - amount: parseFloat(paramData.amount), + amount: amount, expectedIn: expectedIn.toSignificant(8), price: trade.executionPrice.invert().toSignificant(8), swaps: trade, @@ -162,7 +160,7 @@ router.post('/sell', async (req, res) => { const wallet = new ethers.Wallet(privateKey, uniswap.provider) const baseTokenAddress = paramData.base const quoteTokenAddress = paramData.quote - const amount = new BigNumber(parseInt(paramData.amount * denomMultiplier)) + const amount = paramData.amount let maxPrice if (paramData.maxPrice) { @@ -173,9 +171,6 @@ router.post('/sell', async (req, res) => { gasPrice = parseFloat(paramData.gasPrice) } - const minAmountOut = maxPrice / amount - debug('minAmountOut', minAmountOut) - try { // fetch the optimal pool mix from uniswap const { trade, expectedOut} = await uniswap.priceSwapIn( @@ -202,7 +197,7 @@ router.post('/sell', async (req, res) => { latency: latency(initTime, Date.now()), base: baseTokenAddress, quote: quoteTokenAddress, - amount: parseFloat(paramData.amount), + amount: amount, expectedOut: expectedOut.toSignificant(8), price: price, gasUsed: parseInt(txObj.gasUsed), @@ -245,7 +240,7 @@ router.post('/buy', async (req, res) => { const wallet = new ethers.Wallet(privateKey, uniswap.provider) const baseTokenAddress = paramData.base const quoteTokenAddress = paramData.quote - const amount = new BigNumber(parseInt(paramData.amount * denomMultiplier)) + const amount = paramData.amount let maxPrice if (paramData.maxPrice) { @@ -282,7 +277,7 @@ router.post('/buy', async (req, res) => { latency: latency(initTime, Date.now()), base: baseTokenAddress, quote: quoteTokenAddress, - amount: parseFloat(paramData.amount), + amount: amount, expectedIn: expectedIn.toSignificant(8), price: price, gasUsed: parseInt(txObj.gasUsed), diff --git a/src/services/uniswap.js b/src/services/uniswap.js index a2863b3..2d41e80 100644 --- a/src/services/uniswap.js +++ b/src/services/uniswap.js @@ -48,7 +48,7 @@ export default class Uniswap { async priceSwapIn (tokenIn, tokenOut, tokenInAmount) { const tIn = await uni.Fetcher.fetchTokenData(this.chainID, tokenIn) - const tokenAmountIn = new uni.TokenAmount(tIn, tokenInAmount) + const tokenAmountIn = new uni.TokenAmount(tIn, ethers.utils.parseUnits(tokenInAmount, tIn.decimals)) const route = await this.fetch_route(tokenIn, tokenOut) const trade = uni.Trade.exactIn(route, tokenAmountIn) const expectedOut = trade.minimumAmountOut(this.allowedSlippage) @@ -57,7 +57,7 @@ export default class Uniswap { async priceSwapOut (tokenIn, tokenOut, tokenOutAmount) { const tOut = await uni.Fetcher.fetchTokenData(this.chainID, tokenOut) - const tokenAmountOut = new uni.TokenAmount(tOut, tokenOutAmount) + const tokenAmountOut = new uni.TokenAmount(tOut, ethers.utils.parseUnits(tokenOutAmount, tOut.decimals)) const route = await this.fetch_route(tokenIn, tokenOut) const trade = uni.Trade.exactOut(route, tokenAmountOut) const expectedIn = trade.maximumAmountIn(this.allowedSlippage) From 36ae4b4465ba102044e11cfc1fbfaa14065f34c5 Mon Sep 17 00:00:00 2001 From: Michael Feng Date: Tue, 24 Nov 2020 15:28:42 -0800 Subject: [PATCH 3/4] (fix) minor fixes + changed gasLimit to 150k --- src/routes/uniswap.route.js | 11 ++++++----- src/services/uniswap.js | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/routes/uniswap.route.js b/src/routes/uniswap.route.js index c82c319..129d97d 100644 --- a/src/routes/uniswap.route.js +++ b/src/routes/uniswap.route.js @@ -61,7 +61,7 @@ router.post('/sell-price', async (req, res) => { amount ) - if (trade != null && expectedOut != null) { + if (trade !== null && expectedOut !== null) { res.status(200).json({ network: uniswap.network, timestamp: initTime, @@ -71,7 +71,7 @@ router.post('/sell-price', async (req, res) => { amount: amount, expectedOut: expectedOut.toSignificant(8), price: trade.executionPrice.toSignificant(8), - swaps: trade, + trade: trade, }) } else { // no pool available res.status(200).json({ @@ -80,6 +80,7 @@ router.post('/sell-price', async (req, res) => { }) } } catch (err) { + debug(err) let reason err.reason ? reason = err.reason : reason = statusMessages.operation_error res.status(500).json({ @@ -112,7 +113,7 @@ router.post('/buy-price', async (req, res) => { baseTokenAddress, // tokenOut is base asset amount ) - if (trade != null && expectedIn != null) { + if (trade !== null && expectedIn !== null) { res.status(200).json({ network: uniswap.network, timestamp: initTime, @@ -122,7 +123,7 @@ router.post('/buy-price', async (req, res) => { amount: amount, expectedIn: expectedIn.toSignificant(8), price: trade.executionPrice.invert().toSignificant(8), - swaps: trade, + trade: trade, }) } else { // no pool available res.status(200).json({ @@ -131,7 +132,7 @@ router.post('/buy-price', async (req, res) => { }) } } catch (err) { - console.log(err) + debug(err) let reason err.reason ? reason = err.reason : reason = statusMessages.operation_error res.status(500).json({ diff --git a/src/services/uniswap.js b/src/services/uniswap.js index 2d41e80..39bca1f 100644 --- a/src/services/uniswap.js +++ b/src/services/uniswap.js @@ -5,7 +5,7 @@ const debug = require('debug')('router') // constants const ROUTER = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'; -const GAS_LIMIT = 1200000; +const GAS_LIMIT = 150000; const TTL = 60; export default class Uniswap { From cf789cfa90f499c9981ed7b7e806671e09bac865 Mon Sep 17 00:00:00 2001 From: Michael Feng Date: Tue, 24 Nov 2020 16:43:42 -0800 Subject: [PATCH 4/4] use custom gasLimit for Uniswap --- src/services/uniswap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/uniswap.js b/src/services/uniswap.js index 39bca1f..2216074 100644 --- a/src/services/uniswap.js +++ b/src/services/uniswap.js @@ -5,7 +5,7 @@ const debug = require('debug')('router') // constants const ROUTER = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'; -const GAS_LIMIT = 150000; +const GAS_LIMIT = 150688; const TTL = 60; export default class Uniswap {