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;?

If you can search the Discord - Profitable Flashloans channel for gas estimate, you will see a student came up with a work around until the estimategas function works again.

Would it be possible to have that solution posted here? I’m not exactly sure where the link for the Discord is located.

38%20AM

1 Like