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
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!
contractInstance.methodName
is no longer supported in v1.x. You should usecontractInstance.methods.methodName
.console.log(web3.version)
right after initializing it).