Solidity – How to Fix ‘Transaction Has Been Reverted by the EVM’ Error?

avalancheetherethers.jssolidityweb3js

Intro

I am making my first ever smart contract. So please cut me some slack.
Basically, I am trying to make a staking contract in which I want the ability to deposit my USDC which should be done by using stakeTokens() function that I have defined in my contract.

I successfully deployed my contract on Avalanche Fuji testnet using truffle.

Objective

I was trying to send 2 USDC from my 0x69e3E27BBA76B8789dB1E0AA0B816bF93570EFdf wallet to my contract 0x0B4ae929F3181815bA8Bd9873ED31b4e75e21aFE using the stakeTokens(2, _from, _to) function defined in my contract.
More info, I have 1.9 AVAX and 7 USDC both testnet in my wallet.

Error

Now when I tried to interact with the smart contract I had the following error:

error occured Error: Transaction has been reverted by the EVM:
{
  "blockHash": "0xea3a62f9426fcdcbb6e183dc24576e92695c6996fe8573b38614ad86ed4d8938",
  "blockNumber": 10313473,
  "contractAddress": null,
  "cumulativeGasUsed": 154456,
  "effectiveGasPrice": 25000000000,
  "from": "0x69e3e27bba76b8789db1e0aa0b816bf93570efdf",
  "gasUsed": 86686,
  "logs": [],
  "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  "status": false,
  "to": "0x0b4ae929f3181815ba8bd9873ed31b4e75e21afe",
  "transactionHash": "0xdd74634fd8496adafa4b9d733e004d13fb4a9ebb746a327b8586e43e4b00bbc6",
  "transactionIndex": 2,
  "type": "0x0"
}

Receipt:

    blockHash: '0xea3a62f9426fcdcbb6e183dc24576e92695c6996fe8573b38614ad86ed4d8938',
    blockNumber: 10313473,
    contractAddress: null,
    cumulativeGasUsed: 154456,
    effectiveGasPrice: 25000000000,
    from: '0x69e3e27bba76b8789db1e0aa0b816bf93570efdf',
    gasUsed: 86686,
    logs: [],
    logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
    status: false,
    to: '0x0b4ae929f3181815ba8bd9873ed31b4e75e21afe',
    transactionHash: '0xdd74634fd8496adafa4b9d733e004d13fb4a9ebb746a327b8586e43e4b00bbc6',
    transactionIndex: 2,
    type: '0x0'
  }
}

usdc_stake.sol

pragma solidity >=0.4.22 <0.9.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract USDC_STAKE {
    IERC20 public usdcTokenContract;
    address owner;
    mapping(address => uint256) public stakingBalance;

    /*
       Kovan DAI: 0x4F96Fe3b7A6Cf9725f59d353F723c1bDb64CA6Aa    on ethereum
       Rinkyby USDC: 0xb0Ad46bD50b44cBE47E2d83143E0E415d6A842F6 on arbitrum
       Fuji USDC: 0x3E937B4881CBd500d05EeDAB7BA203f2b7B3f74f on avalanche
    */
    constructor() {
        usdcTokenContract = IERC20(0x3E937B4881CBd500d05EeDAB7BA203f2b7B3f74f);
        owner = msg.sender;
    }

    function stakeTokens(uint256 _amount, address _from, address _to) public payable {
        // amount should be > 0
        require(_amount > 0, "amount should be > 0");
        // usdcTokenContract.approve(_from, 10);
        // usdcTokenContract.increaseAllowance(_to, 1000);
        // transfer Dai to this contract for staking
        usdcTokenContract.transferFrom(_from, _to, _amount);
        // // update staking balance
        // stakingBalance[msg.sender] = stakingBalance[msg.sender] + _amount;
    }

    // Unstaking Tokens (Withdraw)
    function unstakeTokens() public {
        uint256 balance = stakingBalance[msg.sender];
        // balance should be > 0
        // require(balance > 0, "staking balance cannot be 0");
        require(
            msg.sender == 0xB89F3c0C82679D6c8cF643e8ef9029f5eF782907,
            "Address not match"
        );
        // Transfer Mock Dai tokens to this contract for staking
        usdcTokenContract.transfer(msg.sender, balance);
        // // reset staking balance to 0
        // stakingBalance[msg.sender] = 0;
    }
}

interact_file.js

const Web3 = require('web3')
const web3 = new Web3('https://api.avax-test.network/ext/bc/C/rpc')
const { ethers, BigNumber } = require("ethers");
const contract_addr = '0xEEd3A7F0F29d5ABEF73615D435A0c8d062a2B8e5'
var abi = require('../build/contracts/USDC_STAKE.json');
// USDC testnet contract is a Proxy contract so I've used the abi of the implementation contract of USDC contract and the address of the proxy contract. I hope that's how it is supposed to be done.
var erc20_abi = require('../build/contracts/USDC_Contract.json');
let wallet_private_key='My-Priv-Key'
let contract=new web3.eth.Contract(abi.abi, contract_addr)
const wallet_addr='0x69e3E27BBA76B8789dB1E0AA0B816bF93570EFdf'
let erc20_token=new web3.eth.Contract(erc20_abi, '0x3E937B4881CBd500d05EeDAB7BA203f2b7B3f74f')

const tx_dict={
  nonce: web3.eth.getTransactionCount(wallet_addr),
  gasPrice: web3.utils.toHex('35000000000'),
  gasLimit: web3.utils.toHex('3000000'),
  value: web3.utils.toHex(0),
  chainId: 43113,
  data: erc20_token.methods.approve(contract_addr,1000000000).encodeABI()
    };

const sign_Tx=web3.eth.accounts.signTransaction(tx_dict,wallet_private_key)
sign_Tx.then((signedTx)=>{
  const sentTx=web3.eth.sendSignedTransaction(signedTx.raw||signedTx.rawTransaction);
  sentTx.on("receipt", receipt => {
      console.log(receipt)
  });
  sentTx.on("error", err => {
      console.log("error occured", err)
  });
}).catch((err) => {
    console.log("promise failed", err)
});

console.log("<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>")

const tx={
  from: wallet_addr,
  to: contract_addr,
  nonce: web3.eth.getTransactionCount(wallet_addr),
  // gas: ethers.utils.hexlify(25000),
  gasPrice: web3.utils.toHex('110000000000'),
  gasLimit: web3.utils.toHex('3000000'),
  value: web3.utils.toHex(2),
  data: contract.methods.stakeTokens(2000000,wallet_addr,contract_addr).encodeABI()
    };

const signPromise=web3.eth.accounts.signTransaction(tx, wallet_private_key);
signPromise.then((signedTx)=>{
  const sentTx = web3.eth.sendSignedTransaction(signedTx.raw||signedTx.rawTransaction);
  sentTx.on("receipt", receipt => {
      console.log(receipt)
  });
  sentTx.on("error", err => {
      console.log("error occured", err)
  });
}).catch((err) => {
    console.log("promise failed", err)
});

ether_gist.js

const ethers = require('ethers');
const provider = new ethers.providers.JsonRpcProvider("https://api.avax-test.network/ext/bc/C/rpc");
const signer = new ethers.Wallet("My-Private-Key");
var contract_abi = require('../build/contracts/USDC_STAKE.json');
var erc20_abi = require('../build/contracts/USDC_coin.json');
const tokenContract = new ethers.Contract("0x3E937B4881CBd500d05EeDAB7BA203f2b7B3f74f", erc20_abi, signer);
const stakeContract = new ethers.Contract("0x7c64ca28A9e14030A19b51D95128d0F9F946EB19", contract_abi.abi, signer);
const approveAndStake = async() => {
  const approveTx = await tokenContract.approve("0x7c64ca28A9e14030A19b51D95128d0F9F946EB19", 10000000);
  await approveTx.wait();
  const stakeTx = await stakeContract.stakeTokens(2, '0x4f5feA23DF8B2c4bbB5aDB8fEAe76142bE8927B7', '0x7c64ca28A9e14030A19b51D95128d0F9F946EB19');
  await stakeTx.wait();
}

Error in ethers_gist.js

/home/mohit/aave-v3/aave-fork/node_modules/@ethersproject/logger/lib/index.js:233
        var error = new Error(message);
                    ^

Error: missing provider (operation="sendTransaction", code=UNSUPPORTED_OPERATION, version=abstract-signer/5.6.2)
    at Logger.makeError (/home/mohit/aave-v3/aave-fork/node_modules/@ethersproject/logger/lib/index.js:233:21)
    at Logger.throwError (/home/mohit/aave-v3/aave-fork/node_modules/@ethersproject/logger/lib/index.js:242:20)
    at Wallet.Signer._checkProvider (/home/mohit/aave-v3/aave-fork/node_modules/@ethersproject/abstract-signer/lib/index.js:395:20)
    at Wallet.<anonymous> (/home/mohit/aave-v3/aave-fork/node_modules/@ethersproject/abstract-signer/lib/index.js:144:30)
    at step (/home/mohit/aave-v3/aave-fork/node_modules/@ethersproject/abstract-signer/lib/index.js:48:23)
    at Object.next (/home/mohit/aave-v3/aave-fork/node_modules/@ethersproject/abstract-signer/lib/index.js:29:53)
    at /home/mohit/aave-v3/aave-fork/node_modules/@ethersproject/abstract-signer/lib/index.js:23:71
    at new Promise (<anonymous>)
    at __awaiter (/home/mohit/aave-v3/aave-fork/node_modules/@ethersproject/abstract-signer/lib/index.js:19:12)
    at Wallet.Signer.sendTransaction (/home/mohit/aave-v3/aave-fork/node_modules/@ethersproject/abstract-signer/lib/index.js:139:16) {
  reason: 'missing provider',
  code: 'UNSUPPORTED_OPERATION',
  operation: 'sendTransaction'
}

Here is testnet block explorer transaction.

Help

Please share whatever mistake you can think of I might be making in this.

Best Answer

The error says: ERC20: transfer amount exceeds allowance. It is thrown from transferFrom function.

You are trying to give approval from the stake function. Which is wrong. Because the msg.sender will be the contract. In other words, you are trying to approve tokens from: stake contract, to: parameter. You have the take approval from your js side.

Related Topic