Execution reverted when calling a method of my contract in NodeJs

16,967

An exception is thrown on the line 106 because this condition is not met: _value <= allowance[_from][msg.sender]

You need to set the allowance prior to calling the transferFrom() function, most likely by calling the approve() function.

Or if you want a simple transfer (not using the allowance), use the transfer() function instead.


Also, call() is used for reading the output of pure/view functions. For interacting with external/public functions (sending ethereum transactions), use .send({from: <senderAddress>}).

Example from https://web3js.readthedocs.io/en/v1.3.4/web3-eth-contract.html#web3-eth-contract

contract.methods.somFunc().send({from: ....})
Share:
16,967

Related videos on Youtube

RRGT19
Author by

RRGT19

Updated on June 04, 2022

Comments

  • RRGT19
    RRGT19 almost 2 years

    I'm trying to do my own token in Solidity and use Web3 to transfer a token from one account to another using NodeJS/ExpressJS.

    I have been using Infura with rinkeby.

    I can call my method balanceOf, but I cannot call transferFrom

    Error:

    Returned error: execution reverted

    const express = require('express');
    const app = express();
    const web3 = require('web3');
    
    const INFURA_BASE_URL = 'https://rinkeby.infura.io/v3/';
    const INFURA_API_KEY = '........';
    web3js = new web3(new web3.providers.HttpProvider(INFURA_BASE_URL + INFURA_API_KEY));
    
    /*
      Sender & Receiver keys
     */
    const SENDER_PUBLIC_KEY = '........';
    const SENDER_PRIVATE_KEY = '.......';
    const RECEIVER_PUBLIC_KEY = '......';
    
    /*
      Contract ABI.
     */
    const CONTRACT_ABI = [
      {
        "constant": true,
        "inputs": [],
        "name": "name",
        "outputs": [
          {
            "name": "",
            "type": "string"
          }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
      },
      {
        "constant": false,
        "inputs": [
          {
            "name": "_spender",
            "type": "address"
          },
          {
            "name": "_value",
            "type": "uint256"
          }
        ],
        "name": "approve",
        "outputs": [
          {
            "name": "success",
            "type": "bool"
          }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
      },
      {
        "constant": true,
        "inputs": [],
        "name": "totalSupply",
        "outputs": [
          {
            "name": "",
            "type": "uint256"
          }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
      },
      {
        "constant": false,
        "inputs": [
          {
            "name": "_from",
            "type": "address"
          },
          {
            "name": "_to",
            "type": "address"
          },
          {
            "name": "_value",
            "type": "uint256"
          }
        ],
        "name": "transferFrom",
        "outputs": [
          {
            "name": "success",
            "type": "bool"
          }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
      },
      {
        "constant": true,
        "inputs": [],
        "name": "decimals",
        "outputs": [
          {
            "name": "",
            "type": "uint8"
          }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
      },
      {
        "constant": false,
        "inputs": [
          {
            "name": "_value",
            "type": "uint256"
          }
        ],
        "name": "burn",
        "outputs": [
          {
            "name": "success",
            "type": "bool"
          }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
      },
      {
        "constant": true,
        "inputs": [
          {
            "name": "",
            "type": "address"
          }
        ],
        "name": "balanceOf",
        "outputs": [
          {
            "name": "",
            "type": "uint256"
          }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
      },
      {
        "constant": false,
        "inputs": [
          {
            "name": "_from",
            "type": "address"
          },
          {
            "name": "_value",
            "type": "uint256"
          }
        ],
        "name": "burnFrom",
        "outputs": [
          {
            "name": "success",
            "type": "bool"
          }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
      },
      {
        "constant": true,
        "inputs": [],
        "name": "symbol",
        "outputs": [
          {
            "name": "",
            "type": "string"
          }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
      },
      {
        "constant": false,
        "inputs": [
          {
            "name": "_to",
            "type": "address"
          },
          {
            "name": "_value",
            "type": "uint256"
          }
        ],
        "name": "transfer",
        "outputs": [
          {
            "name": "success",
            "type": "bool"
          }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
      },
      {
        "constant": false,
        "inputs": [
          {
            "name": "_spender",
            "type": "address"
          },
          {
            "name": "_value",
            "type": "uint256"
          },
          {
            "name": "_extraData",
            "type": "bytes"
          }
        ],
        "name": "approveAndCall",
        "outputs": [
          {
            "name": "success",
            "type": "bool"
          }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
      },
      {
        "constant": true,
        "inputs": [
          {
            "name": "",
            "type": "address"
          },
          {
            "name": "",
            "type": "address"
          }
        ],
        "name": "allowance",
        "outputs": [
          {
            "name": "",
            "type": "uint256"
          }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
      },
      {
        "inputs": [
          {
            "name": "initialSupply",
            "type": "uint256"
          },
          {
            "name": "tokenName",
            "type": "string"
          },
          {
            "name": "tokenSymbol",
            "type": "string"
          }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "constructor"
      },
      {
        "anonymous": false,
        "inputs": [
          {
            "indexed": true,
            "name": "from",
            "type": "address"
          },
          {
            "indexed": true,
            "name": "to",
            "type": "address"
          },
          {
            "indexed": false,
            "name": "value",
            "type": "uint256"
          }
        ],
        "name": "Transfer",
        "type": "event"
      },
      {
        "anonymous": false,
        "inputs": [
          {
            "indexed": true,
            "name": "_owner",
            "type": "address"
          },
          {
            "indexed": true,
            "name": "_spender",
            "type": "address"
          },
          {
            "indexed": false,
            "name": "_value",
            "type": "uint256"
          }
        ],
        "name": "Approval",
        "type": "event"
      },
      {
        "anonymous": false,
        "inputs": [
          {
            "indexed": true,
            "name": "from",
            "type": "address"
          },
          {
            "indexed": false,
            "name": "value",
            "type": "uint256"
          }
        ],
        "name": "Burn",
        "type": "event"
      }
    ];
    const CONTRACT_ABI_ADDRESS = '............';
    
    /*
      A controller listening at: http://localhost:3000/send
     */
    app.get('/send', async function (req, apiResponse) {
    
      // Creating contract object
      const contract = new web3js.eth.Contract(CONTRACT_ABI, CONTRACT_ABI_ADDRESS, {from: SENDER_PUBLIC_KEY});
    
      // Check the balance (working good)
      await contract.methods.balanceOf(RECEIVER_PUBLIC_KEY)
        .call()
        .then(res => {
          const str = web3.utils.fromWei(res);
          console.log('balance: ', str);
        })
        .catch(err => {
          console.log(err);
        });
    
      // Set the allowance (working)
      await contract.methods.approve(SENDER_PUBLIC_KEY, 1)
      .call()
      .then(res => {
         console.log('approve: ', res);
       })
      .catch(err => {
         console.log('Error [approve]', err);
       });
    
      // Initiate a transfer (not working)
      await contract.methods.transferFrom(SENDER_PUBLIC_KEY, RECEIVER_PUBLIC_KEY, 1)
        .call()
        .then(res => {
          console.log('transferFrom: ', res);
        })
        .catch(err => {
          console.log('Error [transferFrom]', err);
        });
    
    });
    
    app.listen(3000, () => {
      console.log(`Example app listening at http://localhost:3000`)
    })
    

    My code in Solidity here.

    I have been struggling for days without any progress. Cannot see where the issue is.

    My goal is to transfer a token from one account to another one in NodeJS.

  • RRGT19
    RRGT19 about 3 years
    Thanks for your reply. I have tried to call approve() before transferFrom, but I received the same error message. Check my question edited with the use of approve(). Something about the send(), I'm not sure if I should use it on my three methods in my NodeJs code. Tried to use it only with transferFrom but received a different error. Can you give check again and give me another hand?
  • Petr Hejda
    Petr Hejda about 3 years
    Yes, you should use the send({from: ...}) instead of the call()... The naming is a bit unfortunate, but I'll try to simply describe: call() in JS is used for read-only. Whenever you need to write data to the blockchain (using external or public function of a contract), you need to send an Ethereum transaction - which is done using the send() function in JS.
  • RRGT19
    RRGT19 about 3 years
    Got it. I have used .send({from: SENDER_PUBLIC_KEY}) on my three calls, but the transferFrom() method returns The method eth_sendTransaction does not exist/is not available. Weird since I don't have a method in my contract with that name. Do you know how can I workaround this new error? Thanks for all your help by the way.
  • Petr Hejda
    Petr Hejda about 3 years
    You're on the right path. eth_sendTransaction is a JSON-RPC method of the node that you're calling (in your case some of Infura's nodes). Which means, the flow has gone through the JS code, generated Ethereum tx, submit the tx to the node, and now the node refuses it... This is already out of my expertise, but my guess is that you have some incorrect credentials connecting to the node (since Infura is widely-used provider and it's unlikely they would have restricted this).
  • RRGT19
    RRGT19 about 3 years
    Apparently, Infura don't allow to send an unsigned transaction. A topic here. Seems that there is a lot of work that I need to do, sign, serialize and send. I'm not sure in what part of my code should I do this, I suppose it's before calling the transferFrom() method? I don't understand the correct steps and what need to be done first.
  • Petr Hejda
    Petr Hejda about 3 years
    It should be enough to set the private key (or mnemonic phrase and key index) and pass it to web3 as the default account. See github.com/ChainSafe/web3.js/issues/1527#issuecomment-395987‌​528 ... Web3 then should be able to sign the transaction with this key automatically.
  • RRGT19
    RRGT19 about 3 years
    Nice. We are in the right path now. I have tried it and received an error saying gas is missing so, I added it and now I receives the error Please pass numbers as string or BN objects to avoid precision errors. I'm passing the gas as string so, don't understand the error. Could you check my code updated here at line 354 to 370? Maybe I'm missing something that I don't see.
  • Petr Hejda
    Petr Hejda about 3 years
    I'm guessing the "gas is missing" is related to the transactions sent by send() functions on lines 374, 385 and 395. Unfortunately I don't have the capacity to debug the whole thing right now, but I'm glad that we've solved the original issue and that you're making progress.
  • RRGT19
    RRGT19 about 3 years
    Thanks for your help to fix the original issue. Now I am in the right path.