0

I am posting a question here that I already posted on stackoverflow before I was aware of this ethereum forum. Not sure about the etiquette when doing this so please tell me if I should delete the stackoverflow post (https://stackoverflow.com/questions/64909327/web3-js-unable-to-read-a-public-view-function-using-call-while-the-call).

I am writing a small app (using react) for a betting smart contract inspired by a tutorial (credit to: https://medium.com/coinmonks/create-a-sports-betting-dapp-on-the-ethereum-blockchain-part-1-1f69f908b939).

The tutorial is great, but I had to make a few changes here and there due to the tutorial being a bit outdated (noticeably it was written before Metamask increased its security with .enable()). But all in all, I managed to make everything work except for one thing, and I really can't understand why it does not work (tried a lot of fixes but nothing worked).

In my solidity contract I have a very simple getter:

   // Getter for front end: amount of Bets in Pool1
   function AmountOne() public view returns(uint256){
       return totalBetOne;
   }

I'm pretty sure this function works because I have tested in Remix

enter image description here

So my guess is that the issue comes from my js script. What is also strange is that all the calls to the other functions - which are more complex - work well, only this one does not work. Now, I'm really a beginner in this language so I have a hard time understanding what is going wrong. Any help would be greatly appreciated. My app script below:

 //constructor
     constructor(){
          super();
          this.state={
            web3: '',
            Amount: '',
            InputAmount: '',
            weiConversion: 1000000000000000000
          }
          this.getAmount = this.getAmount.bind(this);
          this.Bet = this.Bet.bind(this); 
        }
//load web 3
componentDidMount(){
    getWeb3.then(results => {
      /*After getting web3, we save the informations of the web3 user by
      editing the state variables of the component */
      results.web3.eth.getAccounts( (error,acc) => {
        //this.setState is used to edit the state variables
        this.setState({
          web3: results.web3
        })
      });
      //At the end of the first promise, we return the loaded web3
      return results.web3
    }).then(results => {
      //In the next promise, we pass web3 (in results) to the getAmount function
      this.getAmount(results)
    }).catch( () => {
      //If no web3 provider was found, log it in the console
      console.log('Error finding web3.')
    })
  }

  //Smart Contract function THAT DOES NOT WORK

getAmount(web3){ //Get the contract const contract = require('@truffle/contract'); const Betting = contract(BettingContract); Betting.setProvider(web3.currentProvider); var BettingInstance; web3.eth.getAccounts((error, accounts) => { Betting.deployed().then((instance) => { //Instantiate the contract in a promise BettingInstance = instance }).then((result) => { //Calling the AmountOne function of the smart-contract return BettingInstance.AmountOne().call() // <-- issue: seems to return an empty value }).then((result) => { //Then the value returned is stored in the Amount state var.
this.setState({ Amount : result.c
}) }); }) }

  //Smart Contract function THAT WORKS
  Bet(){
        //const contract = require('truffle-contract');
        const contract = require('@truffle/contract');
    const Betting = contract(BettingContract);
    Betting.setProvider(this.state.web3.currentProvider);
    var BettingInstance;
    this.state.web3.eth.getAccounts((error, accounts) =&gt; {
      Betting.deployed().then((instance) =&gt; {
        BettingInstance = instance
      }).then((result) =&gt; {
        // Get the value from the contract to prove it worked.
        return BettingInstance.bet(1, {from: accounts[0],
        value: this.state.InputAmount})
      }).catch(() =&gt; {
        console.log(&quot;Error with betting&quot;)
      })
    })
  }

In case the error comes from my getWeb3, here is the script:

import Web3 from 'web3'

let getWeb3 = new Promise(function(resolve, reject) { // Wait for loading completion before loading web3, to be sure it's // already injected window.addEventListener('load', function() { var results var web3 = window.web3

// Pop-up to ask user to connect his Metamask
// Modern DApp Browsers
if (window.ethereum) {
  web3 = new Web3(window.ethereum);
  try { 
    window.ethereum.enable().then(function() {
        // User has allowed account access to DApp...
    });
  } catch(e) {
    // User has denied account access to DApp...
  }
}
// Legacy DApp Browsers
else if (window.web3) {
  web3 = new Web3(window.web3.currentProvider);
}
// Non-DApp Browsers
else {
  alert('You have to install MetaMask !');
}

// Connect to Metamask
// Checking if Web3 has been injected by the browser MetaMask
if (typeof web3 !== 'undefined') {
  // Use MetaMask's provider.
  web3 = new Web3(web3.currentProvider)
  results = {
    web3: web3
  }
  console.log('Injected web3 detected.');
  resolve(results)
} else {
  // If no web3 is detected, then the local web3 provider is loaded.
  var provider = new Web3.providers.HttpProvider('http://127.0.0.1:9545')
  web3 = new Web3(provider)
  results = {
    web3: web3
  }
  console.log('No web3 instance injected, using Local web3.');
  resolve(results)
}

}) }) export default getWeb3

I haven't included all the other bits of the Apps as this post is long enough like this but please ask away and I'll be happy to include them if you think it could be relevant.

Thank you for your help!

Thomas
  • 87
  • 1
  • 9
  • What version of web3.js are you on? – goodvibration Nov 23 '20 at 12:21
  • Hi. I think it is 1.2.9, but the console also shows 1.3.0 "deduped". – Thomas Nov 23 '20 at 13:40
  • In either case, the syntax contractInstance.methodName is no longer supported in v1.x. You should use contractInstance.methods.methodName. – goodvibration Nov 23 '20 at 13:47
  • Thank you, I will try it. But the call to BettingInstance.bet() worked, which is strange then. Fingers crossed – Thomas Nov 23 '20 at 13:51
  • You should print the version in the correct place then (e.g. try console.log(web3.version) right after initializing it). – goodvibration Nov 23 '20 at 13:52
  • Ok, so I try adding methods and nothing changed. Sorry I do not understand, I should try console.log(web3.version) after initialising what? – Thomas Nov 23 '20 at 14:01
  • Please explain what doesn't work, what error you're getting, and what line in your code throws this error. – goodvibration Nov 23 '20 at 14:24
  • Ok sure, sorry if confusing. So, the app should display the amount of ETH locked in the pool by calling the function "BettingInstance.AmountOne().call()", then placing this result in the state "Amount". Then there is a render that displays the Amount State. What does not work is that the app does not display the amount, it is empty. (also, my debugging skills aren't great with this as it is all very new to me so please feel free to suggets tests I could do on my side if you think it could be relevant). Thank you – Thomas Nov 23 '20 at 14:46
  • "the app does not display the amount" - please find out what value is at hand, at the point in the code where the app is supposed to display the amount. In addition to that, please point out where exactly this is located in the code. Otherwise, you leave it for others to do this research. – goodvibration Nov 23 '20 at 14:51
  • Ok will do. But to be fair I do have pointed it out in the code, see "// <-- issue: seems to return an empty value" – Thomas Nov 23 '20 at 15:01
  • How'd you figure it's an empty value (what does "an empty value" even mean)? – goodvibration Nov 23 '20 at 15:08
  • I've tried inputting a scalar and it showed in the app so figured out that since this worked it meant that my function call returned nothing. But you make a fair point. I'll figure out how to workout the debugger in Visual Code and get back to you with more info. Thank you for your help – Thomas Nov 23 '20 at 16:12

1 Answers1

0

ok so actually it appears that the main issue was resolved here: Problem with Truffle Console: Cannot read property 'call' of undefined

I had to make a few other changes so will paste the code that works in my context in case someone is trying to do the tutorial and can't make it work:

getAmount(web3){
//Get the contract
const contract = require('@truffle/contract');
const Betting = contract(BettingContract);
Betting.setProvider(web3.currentProvider);
//var BettingInstance;
web3.eth.getAccounts((error, accounts) => {
Betting.deployed().then(function(instance) {
return instance.AmountTwo.call({from: accounts[0]})
}).then(function(AmountTwo){
const myres = AmountTwo.toString();
return myres
}).then((myres)=>{
this.setState({
Amount : myres/10**18
})
})
})
} 
Thomas
  • 87
  • 1
  • 9