Web3js

web3 - 在 Ropsten Infura 上使用 @truffle/contract 呼叫 sendTransaction 時出錯

  • March 16, 2020

我的智能合約已經部署在由 Infura 提供的 Ropsten TestNet 上0x63865E0F065C7b865e1a2EE4d99C383A414Bec22。我想使用 NodeJS(v.10.16.1) + Web3(v.1.2.6) + @truffle/contract (v.4.1.11) 發送事務。這是我的 NodeJS 程式碼 -

var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var session = require('express-session');

var Web3            = require('web3');
var contract        = require("@truffle/contract");
var path            = require('path');
var MyContractJSON  = require(path.join(__dirname, 'build/contracts/contract.json'));

var provider    = new Web3.providers.HttpProvider("https://ropsten.infura.io/v3/PROJECT_ID");

var MyContract = contract(MyContractJSON);
MyContract.setProvider(provider);
const contract_address = "0x63865E0F065C7b865e1a2EE4d99C383A414Bec22";


app.post("/register", function(req, res){
   var newUser = req.body.username;
   var account = req.body.account;
   req.session.currentUser = account;

   MyContract.at(contract_address).then(function(instance) {

       return instance.registerUser.sendTransaction(newUser, {from: account});

   }).then(function(result) {
       console.log(result);

       res.render("dashboard", {name: newUser, account: account});

   }).catch(function(error) {
       console.log(error);
       res.redirect("/");
   });
});

我收到此錯誤-sendTransaction

Error: Returned error: The method eth_sendTransaction does not exist/is not available\n    at Object.ErrorResponse (...\\node_modules\\web3-core-helpers\\src\\errors.js:29:16)\n    at ...\\node_modules\\web3-core-requestmanager\\src\\index.js:140:36\n    at XMLHttpRequest.request.onreadystatechange (...\\node_modules\\web3\\node_modules\\web3-providers-http\\src\\index.js:110:13)\n    at XMLHttpRequestEventTarget.dispatchEvent (...\\node_modules\\xhr2-cookies\\dist\\xml-http-request-event-target.js:34:22)\n    at XMLHttpRequest._setReadyState ...\\node_modules\\xhr2-cookies\\dist\\xml-http-request.js:208:14)\n    at XMLHttpRequest._onHttpResponseEnd (...\\node_modules\\xhr2-cookies\\dist\\xml-http-request.js:318:14)\n    at IncomingMessage.<anonymous> (...\\node_modules\\xhr2-cookies\\dist\\xml-http-request.js:289:61)\n    at IncomingMessage.emit (events.js:203:15)\n    at endReadableNT (_stream_readable.js:1145:12)\n    at process._tickCallback (internal/process/next_tick.js:63:19)'

我正在使用Metamask (v.7.7.8) 並通過express-session. 我知道Infura不支持sendTransaction,但**@truffle/contract**也不支持sendRawTransaction。請幫助我使用@truffle/contract 找到更簡單的解決方案。

我根據您在評論中發布的契約創建並編制了一份契約。

我已經將它部署到 Ropsten,然後在 Etherscan 上進行了驗證。

正如你在Etherscan上看到的,它的字節碼包含序列704f1b94,它是 function 的函式選擇器registerUser(string)

正如你在Etherscan上看到的,你的合約的字節碼包含這個函式選擇器,這意味著你的合約沒有實現這個函式!

這本身就足以讓您的交易恢復。

一些技術說明:

  1. 您可以通過獲取列印輸出的前 4 個字節(8 個十六進製字元)來生成上面的函式選擇器console.log(Web3.utils.keccak256("registerUser(string)"));
  2. 這是我在 Etherscan 上編譯、部署和驗證的合約:
pragma solidity 0.4.26;

contract MyContract {

   struct user {
       address id;
       string name;
   }

   uint internal totalUsers = 0;
   mapping(address => user) internal users;

   function registerUser(string memory name) public {
       user storage u = users[msg.sender];
       require(keccak256(abi.encodePacked((name))) != keccak256(abi.encodePacked((""))));
       if(msg.sender == u.id) {
           revert("already registered");
       } else {
           users[msg.sender] = user(msg.sender, name);
           totalUsers++;
       }
   }
}
  1. 這是我用來測試合約功能的 NodeJS 腳本:
const Web3 = require("web3");

const PROJECT_ID  = process.argv[2];
const PRIVATE_KEY = process.argv[3];

const ABI  = [{"type":"function","name":"registerUser","inputs":[{"name":"name","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable","constant":false,"payable":false}];
const ADDR = "0x6285F7CC0cD9D4E5DBB81353276DCc099fa9C6B9";

async function send(web3, account, transaction, value = 0) {
   const options = {
       to      : transaction._parent._address,
       data    : transaction.encodeABI(),
       gas     : await transaction.estimateGas({from: account.address}),
       gasPrice: await web3.eth.getGasPrice(),
       value   : value
   };
   const signed  = await web3.eth.accounts.signTransaction(options, account.privateKey);
   const receipt = await web3.eth.sendSignedTransaction(signed.rawTransaction);
   return receipt;
}

async function run() {
   const web3     = new Web3("https://ropsten.infura.io/v3/" + PROJECT_ID);
   const contract = new web3.eth.Contract(ABI, ADDR);
   const account  = web3.eth.accounts.privateKeyToAccount(PRIVATE_KEY);
   const receipt  = await send(web3, account, contract.methods.registerUser("myName"));
   console.log(receipt);
}

run();

引用自:https://ethereum.stackexchange.com/questions/80610