从 Web.js 连接到 Solidity 合约时地址无效

Posted

技术标签:

【中文标题】从 Web.js 连接到 Solidity 合约时地址无效【英文标题】:invalid address when connecting to Solidity contract from Web.js 【发布时间】:2019-12-21 16:00:03 【问题描述】:

** 根据评论更新

当与合约交互并直接使用'合约地址:'直接从松露迁移输出的输出调用函数时,错误也是无效地址。

-

Solidity 合约和 web3.js 的新手——(尽管我已经尝试让它工作好几个星期了!!)

我正在使用 react.js、truffle-contract 和 web3 创建一个 Dapp 并从 Ganache 连接到我的智能合约。我也在通过 webpack 管理我的应用程序。

我已经用 Solidity 编写了一个简单的合约(版本如下) - 并且可以从 truffle 控制台毫无问题地连接到合约。

当通过一个简单的(用于此演示的)enroll() 函数连接到合约时,我收到了一个 Error: invalid address 我现在已经以多种方式重写了代码,无论如何总是会收到相同的错误。

在这里查看了很多帖子后,我了解到这样做时一个相当常见的问题是我需要设置“默认值”——当我在 componentDidMount 函数中第一次连接到 web3 时,我已经这样做了通过 contract.defaults 函数连接到合约时也是如此。到目前为止,这也没有什么不同。

任何关于我在这里做错的想法将不胜感激!

相关版本如下

"web3": "^1.2.1", "webpack": "^4.20.2", “反应”:“^16.2.0”,

"truffle-contract": "^3.0.4",

"solc": "0.4.18",

下面是尝试连接合约的页面

    componentDidMount = () => 
    if(this.state.web3MetaON == false && this.state.accUnlock == false) 

      if (typeof web3 != 'undefined') 

        this.web3Provider = web3.currentProvider
        web3 = new Web3(web3.currentProvider)
        this.setState(web3MetaON: true)
        const accountID = web3.eth.accounts[0];
        web3.eth.defaultAccount = accountID;
        console.log('Window opening in older browser') 

        // check if accountID is available
        if(accountID !== null || accountID !== undefined) 
        this.setState(accUnlock: true)
        this.setState(account: accountID)

        this.loadDataContract(accountID)

    
    else 
        console.log('Error on accessing account')
          this.setState(accUnlock: false)
    
  
    else 
          window.alert("Please connect to Metamask.")
          this.setState(web3MetaON: false)
          // ::TO-DO method to invoke retry after 2 seconds
        
      

      // Below loads web3 and sets state if browser
      // is and a modern ethereum browser 
      else if (window.ethereum && this.state.web3MetaON == false && this.state.accUnlock == false) 
        window.web3 = new Web3(ethereum)
        try 
          // Request account access if needed
          const accountID = ethereum.enable()
          web3.eth.sendTransaction(/* ... */)
          // setting state to accountID
          this.setState(account: accountID)
          this.setState(accUnlock: true)

          console.log('Window opening in modern browser')

         catch (error) 
          console.log(error, 'Modern Browser failed')
          this.setState(web3MetaON: false)
        
        console.log('Non-Ethereum browser detected. You should consider trying MetaMask!')
      
    ;

  loadDataContract = () =>  
      const contract = TruffleContract(DataAccess)
      contract.setProvider(this.web3Provider)
      contract.defaults(from: this.web3Provider);

      // deploy contract
      contract.deployed().then((DataAccessInstance) => 
              this.DataAccessInstance = DataAccessInstance;
              DataAccessInstance.enroll()
                ).then(data => 
                window.alert("contract loaded.", data)

              ).catch(err => console.log("data load data this is ", err))
            ;

下面是solidity合约的一部分



contract DataAccess 

    // This declares a new complex type which
    // will be used for variables
    // it represents a single usersData
    struct DataLocation 
        string ownerName;
        string ownerID;
        string url;
        string dateOfAccess;
        string timeOfAccess;
        uint accessCount;
        uint index;
    

    struct Index 
        uint indexLocation;
    

    // store Data that has a location
    mapping(address => DataLocation) private datastores;

    mapping (address => uint) private balances;

    // store datalocation Count
    uint public datalocationsCount;

    // userIndex stors location of pointers
    address[] public userIndex;

    // stored event
    event storedEvent (
        uint indexed _dataLocationId
    );

    // event for new data location 
    event LogNewData   (
        address indexed dataAddress, 
        string ownerName,
        string url,
        string ownerID,
        string dateOfAccess,
        string timeOfAccess,
       // uint accessCount,
        uint index);


    // event for new updated data  location 
    event LogUpdateData   (
        address indexed dataAddress,
        string ownerName,
        string url,
        string ownerID,
        string dateOfAccess,
        string timeOfAccess,
     //   uint accessCount,
        uint index);

    function enroll() public returns (uint)
      /* Set the sender's balance to 1000, return the sender's balance */
        address user = msg.sender;

        balances[user] = 1000; 
        return user.balance;
    

当尝试根据反馈重写合约时,结果仍然是无效地址的错误。


  loadDataContract = () =>  

      const contract = TruffleContract(DataAccess)
      contract.setProvider(this.web3Provider)
      contract.defaults(from: this.web3Provider);


      // initial function
      contract.at('0x8a4A12479486A427109e964e90CaEB5798C13A01').enroll().then((Output) => 
        this.setState(value: Output)
      ).catch(err => console.log("Enroll function error ", err))

    ;

【问题讨论】:

【参考方案1】:

您应该使用contract.new() 来部署新合约。如果你想使用已经部署的合约,请使用contract.at(<address of deployed contract>)

contract.deployed() 用于例如测试,当您运行truffle test 命令时,它会返回部署在迁移脚本中的合约。

【讨论】:

谢谢@igor Sobolev。重写代码时,我仍然无法访问合约并且出现相同的错误。请参阅问题的更新代码 sn-p。任何其他想法将不胜感激 contract.defaults 中的from 参数应该是发送交易的地址(this.web3Provider 是否返回地址?)另外,您可以尝试重写.then() 中的函数调用,如下所示:@ 987654329@ 非常感谢您的建议!我现在要加载合同,但必须使用 this.web3Provider.selectedAddress contract.defaults(from: this.web3Provider.selectedAddress); 是否应该将用户地址传递给合同,因为我阅读的文档似乎没有使用它?您对如何在不编写contract.at('0x8a4A12479486A427109e964e90CaEB5798C13A01') 并传递变量而不是合同 ID 的情况下连接到合同有任何建议吗?再次感谢伊戈尔

以上是关于从 Web.js 连接到 Solidity 合约时地址无效的主要内容,如果未能解决你的问题,请参考以下文章

使用 Web3 从 Solidity 调用函数

使用简单的 Solidity 合约和脚本的无效操作码错误

第一行代码:以太坊-使用Solidity语言开发和测试智能合约

我们可以在智能合约中使用 Solidity 获取过去区块中记录的交易信息吗?

智能合约从入门到精通:Solidity语言的开发规范和开发流程

web3.js 调用传递函数返回 Solidity 函数的参数数量无效