EatTheBlocks Forum

Error: call revert exception

So I am trying to set up the profitable-flashloans script on the Kovan test network, partly because of the great amount of funds needed to execute it on Mainnet.

I have therefore found all the Kovan addresses of the services used (dydx, kyber, the tokens to be exchanged etc.) and made a new key called ‘kovan’ with those addresses within the ‘addresses’ folder.

I then finally succeeded in deploying the contract on Kovan. And the websocket interaction of getting and displaying the blocks also works.

I expect it to be error-free while waiting for a transaction to go through. But every time it receives a new block, it gives me an error saying:

UnhandledPromiseRejectionWarning: Error: call revert exception (method="decimals()", errorSignature=null, errorArgs=[null], reason=null, code=CALL_EXCEPTION, version=abi/5.0.1)

This is the whole console log:

λ node run-arbitrage.js
{
  kyber: { kyberNetworkProxy: '0x692f391bCc85cefCe8C237C01e1f636BbD70EA4D' },
  uniswap: { router: '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D' },
  dydx: { solo: '0x4EC3570cADaAEE08Ae384779B0f3A45EF85289DE' },
  tokens: {
    dai: '0xc4375b7de8af5a38a93548eb8453a498222c4ff2',
    usdc: '0xdcfab8057d08634279f8201b55d311c2a67897d2',
    weth: '0xd0a1e359811322d97991e03f863a0c30c2cf029c'
  }
}
web3-shh package will be deprecated in version 1.3.5 and will no longer be supported.
web3-bzz package will be deprecated in version 1.3.5 and will no longer be supported.
New block received. Block # 24267204
(node:20188) UnhandledPromiseRejectionWarning: Error: call revert exception (method="decimals()", errorSignature=null, errorArgs=[null], reason=null, code=CALL_EXCEPTION, version=abi/5.0.1)
    at Logger.makeError (C:\Users\Frederik\Rod\m3\node_modules\@ethersproject\logger\lib\index.js:179:21)
    at Logger.throwError (C:\Users\Frederik\Rod\m3\node_modules\@ethersproject\logger\lib\index.js:188:20)
    at Interface.decodeFunctionResult (C:\Users\Frederik\Rod\m3\node_modules\@ethersproject\contracts\node_modules\@ethersproject\abi\lib\interface.js:286:23)
    at Contract.<anonymous> (C:\Users\Frederik\Rod\m3\node_modules\@ethersproject\contracts\lib\index.js:300:56)
    at step (C:\Users\Frederik\Rod\m3\node_modules\@ethersproject\contracts\lib\index.js:46:23)
    at Object.next (C:\Users\Frederik\Rod\m3\node_modules\@ethersproject\contracts\lib\index.js:27:53)
    at fulfilled (C:\Users\Frederik\Rod\m3\node_modules\@ethersproject\contracts\lib\index.js:18:58)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
(node:20188) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:20188) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

And this is my run-arbitrage.js file:

require("dotenv").config()
const Web3 = require('web3');
const { ChainId, Token, TokenAmount, Pair } = require('@uniswap/sdk');
const abis = require('./abis');
const { kovan: addresses } = require('./addresses');
console.log(addresses)
const Flashloan = require('./build/contracts/Flashloan.json');

const web3 = new Web3(
  new Web3.providers.WebsocketProvider(process.env.INFURA_KOVAN_URL)
);
const { address: admin } = web3.eth.accounts.wallet.add(process.env.PRIVATE_KEY);

const kyber = new web3.eth.Contract(
  abis.kyber.kyberNetworkProxy,
  addresses.kyber.kyberNetworkProxy
);

const ONE_WEI = web3.utils.toBN(web3.utils.toWei('1'));
const AMOUNT_DAI_WEI = web3.utils.toBN(web3.utils.toWei('20000'));
const DIRECTION = {
  KYBER_TO_UNISWAP: 0,
  UNISWAP_TO_KYBER: 1
};

const init = async () => {
  const networkId = await web3.eth.net.getId();
  const flashloan = new web3.eth.Contract(
    Flashloan.abi,
    Flashloan.networks[networkId].address
  );
  
  let ethPrice;
  const updateEthPrice = async () => {
    const results = await kyber
      .methods
      .getExpectedRate(
        '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', 
        addresses.tokens.dai, 
        1
      )
      .call();
    ethPrice = web3.utils.toBN('1').mul(web3.utils.toBN(results.expectedRate)).div(ONE_WEI);
  }
  await updateEthPrice();
  setInterval(updateEthPrice, 15000);

  web3.eth.subscribe('newBlockHeaders')
    .on('data', async block => {
      console.log(`New block received. Block # ${block.number}`);

      const [dai, weth] = await Promise.all(
        [addresses.tokens.dai, addresses.tokens.weth].map(tokenAddress => (
          Token.fetchData(
            ChainId.MAINNET,
            tokenAddress,
          )
      )));
      const daiWeth = await Pair.fetchData(
        dai,
        weth,
      );

      const amountsEth = await Promise.all([
        kyber
          .methods
          .getExpectedRate(
            addresses.tokens.dai, 
            '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', 
            AMOUNT_DAI_WEI
          ) 
          .call(),
        daiWeth.getOutputAmount(new TokenAmount(dai, AMOUNT_DAI_WEI)),
      ]);
      const ethFromKyber = AMOUNT_DAI_WEI.mul(web3.utils.toBN(amountsEth[0].expectedRate)).div(ONE_WEI);
      const ethFromUniswap = web3.utils.toBN(amountsEth[1][0].raw.toString());

      const amountsDai = await Promise.all([
        kyber
          .methods
          .getExpectedRate(
            '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', 
            addresses.tokens.dai, 
            ethFromUniswap.toString()
          ) 
          .call(),
        daiWeth.getOutputAmount(new TokenAmount(weth, ethFromKyber.toString())),
      ]);
      const daiFromKyber = ethFromUniswap.mul(web3.utils.toBN(amountsDai[0].expectedRate)).div(ONE_WEI);
      const daiFromUniswap = web3.utils.toBN(amountsDai[1][0].raw.toString());

      console.log(`Kyber -> Uniswap. Dai input / output: ${web3.utils.fromWei(AMOUNT_DAI_WEI.toString())} / ${web3.utils.fromWei(daiFromUniswap.toString())}`);
      console.log(`Uniswap -> Kyber. Dai input / output: ${web3.utils.fromWei(AMOUNT_DAI_WEI.toString())} / ${web3.utils.fromWei(daiFromKyber.toString())}`);

      if(daiFromUniswap.gt(AMOUNT_DAI_WEI)) {
        const tx = flashloan.methods.initiateFlashloan(
          addresses.dydx.solo, 
          addresses.tokens.dai, 
          AMOUNT_DAI_WEI,
          DIRECTION.KYBER_TO_UNISWAP
        );
        const [gasPrice, gasCost] = await Promise.all([
          web3.eth.getGasPrice(),
          tx.estimateGas({from: admin}),
        ]);

        const txCost = web3.utils.toBN(gasCost).mul(web3.utils.toBN(gasPrice)).mul(ethPrice);
        const profit = daiFromUniswap.sub(AMOUNT_DAI_WEI).sub(txCost);

        if(profit > 0) {
          console.log('Arb opportunity found Kyber -> Uniswap!');
          console.log(`Expected profit: ${web3.utils.fromWei(profit)} Dai`);
          const data = tx.encodeABI();
          const txData = {
            from: admin,
            to: flashloan.options.address,
            data,
            gas: gasCost,
            gasPrice
          };
          const receipt = await web3.eth.sendTransaction(txData);
          console.log(`Transaction hash: ${receipt.transactionHash}`);
        }
      }

      if(daiFromKyber.gt(AMOUNT_DAI_WEI)) {
        const tx = flashloan.methods.initiateFlashloan(
          addresses.dydx.solo, 
          addresses.tokens.dai, 
          AMOUNT_DAI_WEI,
          DIRECTION.UNISWAP_TO_KYBER
        );
        const [gasPrice, gasCost] = await Promise.all([
          web3.eth.getGasPrice(),
          tx.estimateGas({from: admin}),
        ]);
        const txCost = web3.utils.toBN(gasCost).mul(web3.utils.toBN(gasPrice)).mul(ethPrice);
        const profit = daiFromKyber.sub(AMOUNT_DAI_WEI).sub(txCost);

        if(profit > 0) {
          console.log('Arb opportunity found Uniswap -> Kyber!');
          console.log(`Expected profit: ${web3.utils.fromWei(profit)} Dai`);
          const data = tx.encodeABI();
          const txData = {
            from: admin,
            to: flashloan.options.address,
            data,
            gas: gasCost,
            gasPrice
          };
          const receipt = await web3.eth.sendTransaction(txData);
          console.log(`Transaction hash: ${receipt.transactionHash}`);
        }
      }
    })
    .on('error', error => {
      console.log(error);
    });
}
init();

A bit hard to know exactly whats wrong with just these info, but I would suggest to comment out progressively until you dont have the error so that you can isolate the error

Hi guys,

I just finished FlashLoan course and hit the same error after deploying. I did some logging and found out that the gasPrice query is the problem.

tx.estimateGas({from: admin}) is throwing the revert but without the error message, which seems to be issue on dydx side I think.

@jklepatch As a quick fix, could we set gasCost = gasPrice *2;?