在 NodeJs 中调用我的合同方法时执行恢复

Execution reverted when calling a method of my contract in NodeJs

我正在尝试在 Solidity 中创建自己的令牌,并使用 Web3 将令牌从一个帐户转移到另一个帐户 NodeJS/ExpressJS.

我一直在使用 Infurarinkeby

我可以调用我的方法balanceOf,但我不能调用transferFrom

错误:

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`)
})

我在 Solidity 中的代码 here

我苦苦挣扎了好几天,一点进展都没有。看不出问题出在哪里。

我的目标是在 NodeJS 中将令牌从一个帐户转移到另一个帐户。

第106行抛出异常,因为不满足这个条件:_value <= allowance[_from][msg.sender]

您需要在调用 transferFrom() 函数之前设置 allowance,很可能是通过调用 approve() 函数。

或者如果您想要简单的转账(不使用津贴),请改用 transfer() 功能。


此外,call() 用于读取 pure/view 函数的输出。要与 external/public 函数交互(发送以太坊交易),请使用 .send({from: <senderAddress>}).

示例来自 https://web3js.readthedocs.io/en/v1.3.4/web3-eth-contract.html#web3-eth-contract

contract.methods.somFunc().send({from: ....})