I get this error when doing a transaction through Metamask and a NextJS application using this Solidity contract:

The error:

Error: cannot estimate gas; transaction may fail or may require manual gas limit 
[ See: https://links.ethers.org/v5-errors-UNPREDICTABLE_GAS_LIMIT ] 
(reason="execution reverted", method="estimateGas", transaction=
"data":"0xde905f830000000000000000000000000000000000000000000000000000000000000060000000000000000000000000c99da3a663604c43f6296f3f95e9ea7b6481f01f000000000000000000000000bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c00000000000000000000000000000000000000000000000000000000000000143956764a6a6c33674a726f6b6762767a456d4e64000000000000000000000000","accessList":null}, error={"code":-32603,"message":"Internal JSON-RPC error.","data":{"code":-32000,"message":"execution reverted"},"stack":"{\n  \"code\": -32603,\n  \"message\": \"Internal JSON-RPC error.\",\n  \"data\": {\n    \"code\": -32000,\n    \"message\": \"execution reverted\"\n  }

Solidity Code:

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.9;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";

// Import this file to use console.log
import "hardhat/console.sol";

contract CryptoPayments {
    using SafeMath for uint256;

    uint256 public ownerPercentage;
    address payable public owner;

    event NewPayment(string txId, address from, address to, address token, uint256 when);

    constructor() payable {
        owner = payable(msg.sender);
        ownerPercentage = 5;

    function createPayment(string memory txId, address payable seller, address token) public payable {    
        uint256 ownerPortion = msg.value.mul(ownerPercentage).div(100);
        uint256 sellerPortion = msg.value - ownerPortion;

        IERC20 _token = IERC20(token);
        _token.transferFrom(msg.sender, address(this), msg.value);

        _token.transfer(owner, ownerPortion);
        _token.transfer(seller, sellerPortion);

        emit NewPayment(txId, msg.sender, seller, token, block.timestamp);

    function setOwnerPercentage(uint256 percentage) public {
        require(msg.sender == owner, "You aren't the owner");

        ownerPercentage = percentage;

    function setOwner(address newOwner) public {
        require(msg.sender == owner, "You aren't the owner");
        owner = payable(newOwner);

JS code responsible for the execution:

const [ token, setToken ] = useState({
    bnb: {
        name: 'WBNB',
        selected: false,
        address: "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"

const contractAddr = "<CONTRACT_ADDR_HERE>"
const trxData = {seller_wallet_address: "<WALLET_ADDRESS_HERE>"}

async function initiatePayment(){
   const provider = new ethers.providers.Web3Provider(window.ethereum)
   const signer = provider.getSigner()

   let tokenAbi = ["function approve(address _spender, uint256 _value) public returns 
   (bool success)"];
   let tokenContract = new ethers.Contract(token['bnb'].address, tokenAbi, signer);
   await tokenContract.approve(contractAddr, value);

   const contract = new ethers.Contract(contractAddr, ctrct.abi, signer)
   const val = await contract.createPayment(id, trxData.seller_wallet_address, 
   token['bnb'].address, {value});

  • Why are you using payable modifier but later using ERC20 transfer?
    – Ismael
    Aug 6, 2022 at 16:50
  • I'm trying to get some amount of tokens inside the contract and then transfer them to two wallets. I'm not sure this is the correct way
    – Harshana
    Aug 7, 2022 at 2:17
  • You don't have to use msg.value if you aren't accepting ether. Add an amount parameter instead. I don't seen an evident error, try debugging step by step, make sure the account has enough token balance to operate.
    – Ismael
    Aug 9, 2022 at 2:55

1 Answer 1


msg.value in Ethereum is always Ether so you need an amount parameter instead.

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.