I am new to solidity and smart contracts and I am bit confused with sending money from metamask to my smart contract. Everything seems to work fine in remix but when I use metamask I get a revert error message. I am using ganache as my local blockchain
My smart contract looks like this: –
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.10;
import "@openzeppelin/contracts/access/Ownable.sol";
contract Bet is Ownable{
uint public Money; // set variable to display balance on contract
bool Odd; // variable to set true or false
uint TotalDiceNumber = 12; // dice numbers from 1 - 12
uint result; // variable to hold the dice roll
mapping(address => uint) allowance; //allowance for non owners of the contract
uint BetValue; //variable for original bet value
uint _amount; //variable to hold value of allowance
bool Active; // is the game active
constructor() {
}
function isOwner() internal view returns(bool) {
return owner() == msg.sender; //returns the address who deployed it
}
event BetMade(address player, uint Bet); //placeholder to send data to front end
function receiveMoney() public payable { // get money(bet) from metamask and put on smart
emit BetMade(msg.sender, BetValue); // send player and value of bet
//Money += BetValue; //added after react
Money += msg.value;
BetValue = msg.value;
if (owner() == msg.sender) {
Active = false; // owner doesnt active contract to protect funds
} else {
Active = true; // player activates contract when bet is placed
require(BetValue <= 20 ether, "Bets must be below 21 Ether"); //player can only
bet under 20 ether/ owner can put as much money as they want on
}
}
event BalanceofContract(uint Balcontract);
function getBalance()public returns(uint) {
uint Bal;
Bal = address(this).balance;
emit BalanceofContract(Bal);
return Bal;
}
event PlayerSelectOddEven(address player, bool OddEven);
function selectOddorEven(bool OddEven) public {
emit PlayerSelectOddEven(msg.sender, OddEven);
require(msg.sender != owner(), "You are the house and cannot bet"); // house cannot bet
require(Active = true, "Game not in play. Please place a bet"); // game must be active
Odd = OddEven; // create field to enter true for odd or false for Even
//default is false
}
function Random() internal view returns(uint) {
return uint(keccak256(abi.encodePacked
(block.difficulty,
block.timestamp,
TotalDiceNumber))); // create a random number from blockchain.
//in production would look at chainlink VR but looks like there is a cost so
//went with a less secure option
}
event RollDiceOutput(address player, uint DiceNumber);
function Rolldice() public returns(uint){
emit RollDiceOutput(msg.sender, result);
uint Outcome;
require(Active = true, "Game not in play. Please place a bet"); //game must be actvie
Outcome = Random() % TotalDiceNumber;
result = Outcome + 1; // use + 1 to remove 0 out of random sequence
return result; // function to create number
}
function OutcomeDice() public view returns (uint) {
uint Outcome1;
Outcome1 = result;
return Outcome1;
// function to view number from above function
}
function numberOddorEven() public view returns (bool) {
bool OddorEven; // true for odd false for even
uint _result;
_result = result;
if (_result == 1 || _result == 3 || _result == 5 || _result == 7 || _result == 9 ||
_result == 11) {
OddorEven = true;
} else {
OddorEven = false;
}
return OddorEven;
}
event Winning(address Player, uint WinningsValue);
function addAllowance() public {
emit Winning(msg.sender, _amount);
require(msg.sender != owner(), "You are the house and cannot bet");
require(Active = true, "Game not in play. Please place a bet");
address _who = msg.sender; // assign player to variable
_amount = BetValue * 2; //assign allowance twice as much original bet
allowance[_who] == _amount; // set allowance in mapping against player
}
event Won(address Player, uint Winnings);
function WinMoney() public {
emit Won(msg.sender, _amount);
bool UserInputOdd = numberOddorEven();
bool decisionOdd = Odd;
address _who = msg.sender; // assign player to variable
require(Active = true, "Game not in play. Please place a bet");
require(_amount > 0, "Add the house's money by adding a allowance to collect winning");
if (UserInputOdd == decisionOdd) {
address payable to = payable(msg.sender); //pay the player's address
to.transfer(_amount); // transfer the winning
_amount = 0; //zeroed the variable for multiplying the bet
allowance[_who] = 0; // zeroed the allowance
BetValue = 0; // zeroed the bet
Odd = false; // resets the odd/even input
Active = false; //disable the game
} else {
_amount = 0; //zeroed the variable for multiplying the bet
allowance[_who] = 0; // zeroed the allowance
BetValue = 0; // zeroed the bet
Odd = false; // resets the odd/even input
Active = false; //disable the game
}
}
receive() external payable {
receiveMoney();
}
}
On the front end I am trying to add funds to the smart contract: –
import Head from 'next/head'
import Image from 'next/image'
import styles from '../styles/Home.module.css'
import { useState } from "react" //import library for line 9
import { ethers } from "ethers" // import library for ethers
import { abi_file } from "../constants/abi"; // import abi from different file
export default function Home() {
const [isConnected, setIsConnected] = useState(false); //to show a button is not connected
const [signer, setSigner] = useState();
async function connect() { //create function to connect metameask
if (typeof window.ethereum !== "undefined") { // check to see if metamask is installed
try {
await ethereum.request({ method: "eth_requestAccounts"});
setIsConnected(true); // set variable as true
const connectedProvider = new ethers.providers.Web3Provider(window.ethereum);
setSigner(connectedProvider.getSigner());
} catch (e) {
console.log(e); // catch and log and errors in console(F12 in chrome)
}
} else {
setIsConnected(false);
}
}
async function Rolldice() { //execute function
if (typeof window.ethereum !== "undefined") { // check to see if metamask is installed
const contractAddress = "0x89f6D41f87054127066d4639e3Ada3DeEefE5EB7"; // address of the contract
const abi = abi_file;
const contract = new ethers.Contract(contractAddress, abi, signer); // calls the contract from the 3 variables
try {
// await contract.Rolldice(); //function will are calling on the sol contract
const transactionResponse = await contract.Rolldice();
const transactionReceipt = await transactionResponse.wait();
var player = (transactionReceipt.events[0].args.player);
var result = (transactionReceipt.events[0].args.DiceNumber.toString());
//alert("Dice Number pressed");
//var x = document.createElement("H3");
//var t = document.createTextNode("Dice rolled from " + player);
// x.appendChild(t);
// document.body.appendChild(x);
var z = document.createElement("H3");
var w = document.createTextNode("Dice number is " + result);
z.appendChild(w);
document.body.appendChild(z);
} catch (error) {
console.log(error);
}
} else {
document.getElementById("executeButton").innerHTML =
"Please install MetaMask";
}
}
async function receiveMoney() { //execute function
if (typeof window.ethereum !== "undefined") { // check to see if metamask is installed
const contractAddress = "0x89f6D41f87054127066d4639e3Ada3DeEefE5EB7"; // address of the contract
const abi = abi_file;
const contract = new ethers.Contract(contractAddress, abi, signer); // calls the contract from the 3 variables
try {
// await contract.Rolldice(); //function will are calling on the sol contract
const transactionResponse = await contract.receiveMoney();
const transactionReceipt = await transactionResponse.wait();
var Balance = (transactionReceipt.events[0].args.Bet.toString());
//alert("Dice Number pressed");
//var x = document.createElement("H3");
//var t = document.createTextNode("Dice rolled from " + player);
// x.appendChild(t);
// document.body.appendChild(x);
var z = document.createElement("H2");
var w = document.createTextNode("The Balance of the contract is " + Balance);
z.appendChild(w);
document.body.appendChild(z);
} catch (error) {
console.log(error);
}
} else {
document.getElementById("executeButton").innerHTML =
"Please install MetaMask";
}
}
return <div className={styles.container}>
{isConnected ?
<>
<h2>"Connected!" </h2>
<p> Please send money to 0x89f6D41f87054127066d4639e3Ada3DeEefE5EB7 but no higher than 20 ethers</p>
<button onClick= {() => receiveMoney()}>Bet Money</button>
<br></br>
<br></br>
<button onClick= {() => Rolldice()}>Roll dice</button>
<br></br>
<br></br>
</>
: (<button onClick={() =>connect()}>Connect</button>) }
</div>;
}
Can anybody suggest where I am going wrong? Many thanks