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) => {
          Betting.deployed().then((instance) => {
            BettingInstance = instance
          }).then((result) => {
            // Get the value from the contract to prove it worked.
            return BettingInstance.bet(1, {from: accounts[0],
            value: this.state.InputAmount})
          }).catch(() => {
            console.log("Error with betting")
          })
        })
      }

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!

13
  • What version of web3.js are you on? Commented Nov 23, 2020 at 12:21
  • Hi. I think it is 1.2.9, but the console also shows 1.3.0 "deduped".
    – Thomas
    Commented Nov 23, 2020 at 13:40
  • In either case, the syntax contractInstance.methodName is no longer supported in v1.x. You should use contractInstance.methods.methodName. Commented Nov 23, 2020 at 13:47
  • Thank you, I will try it. But the call to BettingInstance.bet() worked, which is strange then. Fingers crossed
    – Thomas
    Commented Nov 23, 2020 at 13:51
  • You should print the version in the correct place then (e.g. try console.log(web3.version) right after initializing it). Commented Nov 23, 2020 at 13:52

1 Answer 1

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.