Search code examples
javascriptchainlinkhardhat

underlying.transferFrom in compound docs guide throws this error: ProviderError: Error: Transaction reverted without a reason string hardhat


I'm trying to lend to the compound protocol in an App I'm building.

Also following the compound doc & guide here: Compound Blog Post

After forking the mainnet locally and impersonating an address with large USDT, I'm now trying to lend to the compound protocol.

In my test, this line underlying.transferFrom always fails with this error: ProviderError: Error: Transaction reverted without a reason string

Any suggestions on what could be the reason? I've asked on the compound discord, and gotten no reply.

Also done lots of research, couldn't find a similar issue... don't know what else to do.

Below is a sample of my code

Dev Environment: Hardhat
OS: Windows 10

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "hardhat/console.sol";
import "../interfaces/ICompound.sol";

contract CompoundController {
    mapping(address => mapping(address => UserInvestedTokenDetails))
        public UserInvestments;

    struct UserInvestedTokenDetails {
        uint256 tokenAmount;
        bool isExists;
    }

    function _setUserInvestments(
        address userAddress,
        address tokenAddress,
        uint256 tokenAmount
    ) internal {
        if (UserInvestments[userAddress][tokenAddress].isExists) {
            UserInvestments[userAddress][tokenAddress]
                .tokenAmount += tokenAmount;
        } else {
            UserInvestments[userAddress][
                tokenAddress
            ] = UserInvestedTokenDetails(tokenAmount, true);
        }
    }

    function supplyErc20ToCompound(
        address _erc20,
        address _cErc20,
        uint256 tokenAmount
    ) public returns (bool) {
        console.log("contract!");
        // Token being supplied to compound
        Erc20 underlying = Erc20(_erc20);
        // Token sent from compound in return
        CErc20 cToken = CErc20(_cErc20);
        require(
            underlying.transferFrom(msg.sender, address(this), tokenAmount),
            "compound: transferring tokens from user failed!"
        );

        underlying.approve(_cErc20, tokenAmount);
        require(cToken.mint(tokenAmount) == 0, "compound: mint failed!");
        _setUserInvestments(msg.sender, _erc20, tokenAmount);
        return true;
    }

}

Also the test file as requested:

const { expect } = require("chai");
const { BigNumber } = require("ethers");
const { ethers } = require("hardhat");
const DAI = process.env.DAI;
const USDT = process.env.USDT;
//
const cDAI = process.env.DAI;
const cUSDT = process.env.CUSDT;

const USDT_WHALE = process.env.USDT_WHALE;

describe("CompoundController", function () {
  before(async () => {
    [deployer, user1, user2] = await ethers.getSigners();
    CompoundController = await ethers.getContractFactory("CompoundController");
    compoundController = await CompoundController.deploy();

    // FUND USERS ACCOUNT WITH PAYMENT OPTIONs TOKEN
    Usdt = await ethers.getContractAt("IERC20", USDT);
    Dai = await ethers.getContractAt("IERC20", DAI);
  });
  describe("sendErc20", function () {
    it("should supply tokens to compound", async () => {
      let depositAmount = BigNumber.from("100000000000000000000"); //  100
      await hre.network.provider.request({
        method: "hardhat_impersonateAccount",
        params: [USDT_WHALE],
      });
      const signer = await ethers.getSigner(USDT_WHALE);
      await Usdt.connect(signer).approve(
        compoundController.address,
        depositAmount
      );
      let tx = await compoundController
        .connect(signer)
        .supplyErc20ToCompound(USDT, cUSDT, depositAmount);
      console.log(tx);
    });
  });
});

Solution

  • These were the issues, ultimately:

    • The USDT contract seems for some reason do not comply with the eip20 standard. It doesn't return a bool, so my interface for all erc20 contracts didn't match with their function.

    Immediately I tested with DAI which was eip20 compliant, it worked.

    • Also at some point, while forking the mainnet, my signer account (account I was testing with) didn't have the token (enough USDT) I was trying to supply to compound.