2

I am trying to calculate the value of an exchange on Uniswap using Web3js and methods from the Uniswap smart contract.

This is the Uniswap contract address for the WETH (Wrapped Ether) : WBTC (Wrapped Bitcoin) pair 0xBb2b8038a1640196FbE3e38816F3e67Cba72D940

Using that contract address and the contract ABI I construct a js-object for the contract like this: const pairContract = new web3.eth.Contract(pair.abi, pair.address);

This works fine and I am able to read the contract methods as well as call methods on the contract (I'm only using read-only methods - I don't need to sign any transactions). So I am able to call the getReserves method like this

const reserves = await pairContract.methods.getReserves().call();

And here is the response (at this _blockTimestampLast)

{
  '0': '296352466321',
  '1': '37712426843492788602200',
  '2': '1621116220',
  _reserve0: '296352466321',
  _reserve1: '37712426843492788602200',
  _blockTimestampLast: '1621116220'
}

_reserve0 are the WBTC reserves and _reserve1 are the WETH reserves

Now here in this implementation is where somehow things are going wrong...

const BigNumber = require('bignumber.js');

const estimateTrade = (
  baseTokenReserves, 
  quoteTokenReserves, 
  numberOfBaseTokenTradedIn, 
  feePercent)=> {

        // x * y = k
 
        const feeMultiplier = BigNumber(1).minus(feePercent.dividedBy(100));

        const k = baseTokenReserves.times(quoteTokenReserves);

        const baseTokenNewTotal = baseTokenReserves.plus(numberOfBaseTokenTradedIn.times(feeMultiplier));

        const quoteTokenNewTotal = k.dividedBy(baseTokenNewTotal);

        const quoteTokenReceived = quoteTokenReserves.minus(quoteTokenNewTotal);

        return quoteTokenReceived;

}

Calling my estimatedTrade method with these arguments...

const baseTokenReserves = BigNumber(_reserve0);
const quoteTokenReserves = BigNumber(_reserve1);
const numberOfBaseTokenTradedIn = BigNumber(1);
const feePercent = BigNumber(0.03);

const tokensReceived = estimateTrade(baseTokensReserves, quoteTokenReserves, numberOfBaseTokenTradedIn , feePercent)

console.log(`tokensReceived = ${tokensReceived.toFixed()}`) //tokensReceived = 127151098781.56376683928985070517

This obviously is way off. When I check on Uniswap to see how many WETH I would get for 1 WBTC I see roughly 12.677. I've checked for hours and every time my answer is off by 10 decimal places (10,000,000,000 times). This method works well for every other pair I've tried (WETH_SUSHI, WETH_UNI, etc.) except for WETH_WBTC. Can anyone see what the issue is? Thank you!

2 Answers 2

2

I was getting a similar issue when looking at USDC and WETH and using ethers.js . This is how I was originally converting my Big Numbers:

const reserve0 = Number(ethers.utils.formatUnits(reserves[0], 18)); //USDC
const reserve1 = Number(ethers.utils.formatUnits(reserves[1], 18)); //WETH

I figured out that the issue was that USDC only uses 6 decimal places, not 18. So I had to change it to this:

const reserve0 = Number(ethers.utils.formatUnits(reserves[0], 6)); //USDC
const reserve1 = Number(ethers.utils.formatUnits(reserves[1], 18)); //WETH

Based on the WBTC contract on etherscan, WBTC uses 8 decimals, so I would guess that is your problem.

0

in fact, the pair is not in WETH, it is ETH

const reserveETH = reserves._reserve0.div(ethers.BigNumber.from(10).pow(8));
const reserveWBTC = reserves._reserve1.div(ethers.BigNumber.from(10).pow(18));

It works for me : 1 ETH = 19.16504854368932 WBTC 1 WBTC = 0.05217831813576494 ETH

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.