I'm making a simple dapp using React, Hardhat, Ethers.js, and Solidity.
I've been following along a tutorial on YouTube but I got stuck at the part where you call the Solidity functions from the created contract object.
Whenever I try to call a function from my contract it keeps producing the following error:
"contract runner does not support calling"
Querying the contract works since I can get the balance of the contract but I can't find any resources on how to fix the contract runner error. Would appreciate the help. Here follows the code in React.
const providerInitializer = async() => {
if (window.ethereum == null) {
console.log("MetaMask not installed; using read-only defaults")
provider = ethers.getDefaultProvider()
} else {
provider = new ethers.BrowserProvider(window.ethereum)
signer = await provider.getSigner();
}
}
const ABI = [
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"inputs": [],
"name": "changeAvailability",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "getBikes",
"outputs": [
{
"components": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "uint256",
"name": "rangePower",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "maxSpeed",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "batteryCapacity",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "costPerHour",
"type": "uint256"
},
{
"internalType": "bool",
"name": "isAvailable",
"type": "bool"
}
],
"internalType": "struct Rental.Bike[]",
"name": "",
"type": "tuple[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getNumOfBikes",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_totalHours",
"type": "uint256"
}
],
"name": "rent",
"outputs": [],
"stateMutability": "payable",
"type": "function"
}
]
const contract = new ethers.Contract(contractAddress, ABI, provider);
useEffect(()=>{
providerInitializer()
.catch(console.error);
const getBalance = async() =>{
const balance = await provider.getBalance(contractAddress);
const formattedBalance = ethers.formatEther(balance);
setRunningBalance(formattedBalance);
}
const getNumber = async() =>{
const number = await contract.getNumOfBikes(); //Throws error here for me
setNumberOfBikes(number);
}
getBalance().catch(console.error);
getNumber().catch(console.error);
});
Solidity code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
contract Rental {
struct Bike{
string name;
uint rangePower;
uint maxSpeed;
uint batteryCapacity;
uint costPerHour;
bool isAvailable;
}
//admin variables
address owner;
uint totalHours=0;
uint totalRents=0;
uint totalEbikes;
//array of bikes
Bike[] bikes;
constructor(){
//contract deployer address
owner = msg.sender;
//initialization of bike values
bikes.push(Bike("48v/12ah Electric Bicycle Electric Bike", 60, 50, 576, 70, true));
bikes.push(Bike("51v/17ah Electric Bicycle Electric Bike", 60, 50, 867, 70, true));
bikes.push(Bike("43v/11ah Electric Bicycle Electric Bike", 60, 50, 473, 70, true));
bikes.push(Bike("60v/18ah Electric Bicycle Electric Bike", 60, 50, 1080, 70, true));
totalEbikes=bikes.length;
}
function getBikes() public view returns (Bike[] memory){
return bikes;
}
function getNumOfBikes() public view returns (uint){
return bikes.length;
}
function changeAvailability() public {
bikes[1].isAvailable=false;
}
function rent(uint _totalHours) payable public {
totalHours+=_totalHours;
totalRents++;
}
}
The tutorial I was watching seems to be using Ethers v5 and I'm using Ethers v6 but based on the documentation the part where I get stuck seems to be the same on both.