在 NodeJs 中调用我的合约方法时执行恢复
Posted
技术标签:
【中文标题】在 NodeJs 中调用我的合约方法时执行恢复【英文标题】:Execution reverted when calling a method of my contract in NodeJs 【发布时间】:2021-05-31 14:31:14 【问题描述】:我正在尝试在 Solidity 中创建自己的令牌,并使用 Web3 将令牌从一个帐户转移到另一个帐户,使用 NodeJS/ExpressJS
。
我一直在使用Infura
和rinkeby
。
我可以调用我的方法balanceOf
,但我不能调用transferFrom
错误:
返回错误:执行恢复
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 中将令牌从一个帐户转移到另一个帐户。
【问题讨论】:
【参考方案1】:因为不满足这个条件,所以在第 106 行抛出异常:_value <= allowance[_from][msg.sender]
您需要在调用transferFrom()
函数之前设置allowance
,很可能是通过调用approve()
函数。
或者,如果您想要简单的转账(不使用配额),请改用transfer()
函数。
另外,call()
用于读取纯/视图函数的输出。如需与外部/公共功能交互(发送以太坊交易),请使用.send(from: <senderAddress>)
。
来自https://web3js.readthedocs.io/en/v1.3.4/web3-eth-contract.html#web3-eth-contract的示例
contract.methods.somFunc().send(from: ....)
【讨论】:
感谢您的回复。我曾尝试在transferFrom
之前致电approve()
,但我收到了相同的错误消息。检查我使用approve()
编辑的问题。关于send()
,我不确定是否应该在我的 NodeJs 代码中的三个方法中使用它。尝试仅将其与 transferFrom
一起使用,但收到不同的错误。你能再给我支票,再帮我一把吗?
是的,你应该使用send(from: ...)
而不是call()
...命名有点不幸,但我会尝试简单描述:call()
在JS中用于只读。每当您需要将数据写入区块链(使用合约的外部或公共功能)时,您都需要发送以太坊交易 - 这是使用 JS 中的send()
函数完成的。
知道了。我在三个调用中都使用了.send(from: SENDER_PUBLIC_KEY)
,但是transferFrom()
方法返回The method eth_sendTransaction does not exist/is not available
。很奇怪,因为我的合同中没有使用该名称的方法。你知道我该如何解决这个新错误吗?顺便感谢您的帮助。
您走在正确的道路上。 eth_sendTransaction
是您正在调用的节点的 JSON-RPC 方法(在您的情况下是 Infura 的一些节点)。这意味着,流程已经通过了 JS 代码,生成了 Ethereum tx,将 tx 提交给节点,现在节点拒绝了它......这已经超出了我的专业知识,但我猜你有一些不正确的凭据连接到节点(因为 Infura 是广泛使用的提供商,他们不太可能限制这一点)。
显然,Infura 不允许发送未签名的交易。一个话题here。似乎我需要做很多工作,签名,序列化和发送。我不确定我应该在代码的哪一部分执行此操作,我想是在调用 transferFrom()
方法之前?我不明白正确的步骤和首先需要做什么。以上是关于在 NodeJs 中调用我的合约方法时执行恢复的主要内容,如果未能解决你的问题,请参考以下文章