Could you please share your github repo and also please the steps to reproduce the issue?
Are you connected to metamask? Do you have any error in your console?
Waiting for your repo I wish you a nice day.
Dani
Wow thatās strange, maybe itās something related to truffle / ganache and not the code then? I donāt have my Phase 1 code saved unfortunately, but here is my current repo: https://github.com/Roushie/Coinflip.dApp
EDIT: Managed to fix it by adding an empty payable constructor function to the main contract (coinflip.sol). I guess the error was about the contract not being able to receive money even though I had defined a payable constructor in one of the imported contracts (Ownable.sol). I thought that the way inheritance worked was that the code from the inherited contracts was copied to the top of the inheriting contract, so having the constructor in Ownable.sol should be fine? Also I implemented it this way in Phase 1 and everything worked? Still quite confused to be honest, but at least the code is working now. Iād be very thankful if @filip or @dan-i could help me figure out why the bug occurred!
Hello everyone. Great task aheadā¦ I need my hand held on this one thoā¦
Can i make a suggestion for myself and maybe someone could help me out.
I am going to Get the Dapp html file designed and looking like the way i want it.
Can anyone help me with the functionality of it in my code when im finished it?
Cheers.
Here is the link to my github repository: https://github.com/Oussama994/Flip-Coin-Dapp
Iām connected to metamask, I have some errors, value inexpected.
Hey @Nara
Thanks for your repo I just double checked, and confirm that because we are deploying āCoinflipā then inheriting from Ownable, the payable constructor should be in Coinflip.
Good catch
As soon as I migrate the contracts and opened the dapp, the console prompts out this error (always check the console as it tells you whatās wrong).
Checking your main.js I see that you have not closed the $(document).ready(function() {
statement.
Add })
at the bottom of your file.
Now that the issue is fixed, if I try to play I get
The error is saying that there is a
send()
function where the sender is not specified.
contractInstance.methods.betplay(betamount).send()
, here you have to add the sender (accounts[0]) as parameter to send()
Here you have lots of different ways to do that, you can just assign the array of accounts stated inside windows.enable
ā¦ or just fetching the accounts using web3 like below
function inputData(){
var betamount = $("#bet_input").val();
web3.eth.getAccounts().then(res => {
contractInstance.methods.betplay(betamount).send({from:res[0]})
.on('transactionHash', function(hash){ // This to let us when the transaction is hashed.
console.log("tx hash");
})
.on('confirmation', function(confirmationNumber, receipt){// this is to let us know if the transaction is confirmed, in the real mainnet a 12 confirmation is required to be sure that the transaction has been confirmed
console.log("conf");
})
.on('receipt', function(receipt){// this will enable us to get a receipt, a notification when our contract is mined for the first time in the blockchain.
console.log(receipt); //We use these 3 clever functions because in the main net the transaction take time and our contract takes time to be mined in a blockchain, so we use them to know if is every is alright or not
})
})
}
Now the dapp works, you still have errors in your contract code that will revert the transaction, give it a look and try to fix them.
Happy coding,
Dani
@dan-i can you help me with something i cant get my head around lol.
file:///E:/Crypto/Etherium-course-advanced/dapp/Coinflip.html
click on my dapp via the link above.
Could i please get some help on how to make my bet functions workā¦
What functions do i need to provide on my code, do they need to be added to my Coinflip.sol ? Is there anything needed on migration.sol as well? Im well in truly confused.
Also I need metamask to talk to my dapp and none of my buttons have any code assigned. But i have everything on my dapp now ready to go. I really am struggling with it. At least i have a map now of what my dapp doesā¦ it just needs the code done.
https://github.com/Highlander-maker/CoinFlipDapp
Rob ā¦
Hi. Iāve almost finished this first project. But Iām having an issue on the withdrawal function.
Iāve posted my code on github https://github.com/LSilveira/FlipCoin.
Iāve tested the contracts on Remix IDE and the withdrawal function works there. However when I run it in the web server the transactions fails. I see the following errors and logs:
I appreciate any help on fixing this issue. Thank you
Hey Rob!
I cannot access the link: file:///E:/Crypto/Etherium-course-advanced/dapp/Coinflip.html as that is local in your machine
In your main.js you have successfully created a web3 instance of your contract
contractInstance = new web3.eth.Contract(window.abi, "0xc22f6f52Ad85613b4a27eD86Dd414Be9952dF3e6", {from: accounts[0]});
Thanks to that declaration, you can now access all the methods (public) you have in your contract.
You can access a method using your web3 instance by proceeding as follow:
contractInstance.methods.nameOfTheMethod
lets assume the following
Smart contract:
function get () public view returns (uint) {
return 1;
}
Main.js
async function getTest () {
let result = await contractInstance.methods.get().call();
console.log(result);
}
If the function you are calling is not a getter you will need to send a tx instead.
smart contract
uint total;
function run () public payable {
total += msg.value;
}
main.js
async function runTest () {
await contractInstance.methods.run().send(from: accounts[0], value: 10000);
}
Web3 docs: https://web3js.readthedocs.io/en/v1.2.0/web3-eth.html
Check the docs and try to play with web3.
Let me know if you have questions.
Hey @Luis_Silveira
Check the following:
- Your withdraw function has a onlyOwner modifier. Are you calling the withdraw function using the owner account (usually is accounts[0], the same one that you used to deploy the contracts).
If you do that already, reset metamask and retry: https://metamask.zendesk.com/hc/en-us/articles/360015488891-Resetting-an-Account
Let me know!
EDITED FOR MORE GUIDANCE.
Hey @dan-i sorry i had to delete a few previous posts so i have condenst in to this one.
- No metamask appears on Dapp asking to connect.
- Functions arent working on the Dapp
- Image does not appear from the Html file when i run the Dapp via Python Server
I have added some code from other peoples projects to try and make some sense but what i dont get is what i have to do to connect these functions to what my Dapp has.
i have updated my poor code on my github now could you please have a look and help me join the dots.
I am really sorry if this is frustrating for you helping me as i feel that Iām so far away from achieving anything on this nowā¦ Hard work man
Thank you Daniele. I was doing the withdrawal with an account that was not the contract owner
thank! I was able to proceed a bit now
at the moment iām trying to check if the withdraw function works:
- player with a balance should withdraw to his address
- contract owner should withdraw to his address from contract address
Anyway they donāt seem to work properly:
by clicking on the buttons nothing happens.
when clicking on the input fields (not the withdraw button) only with the player account (also on the withdraw input field which should be only for the contract owner)
this display:
it seem wrong because there is a tx from the player account (account 4) to the contract but it should be the opposite).
besides this happen when clicking the input field and not the button
besides this happen also for the withdraw input fields which should start only with the owner account but it doesnāt.
this is my code, can you help me to find what is wrong?
MAIN
var web3 = new Web3(Web3.givenProvider);
var contractInstance;
$(document).ready(function() {
window.ethereum.enable().then(function(accounts){
contractInstance = new web3.eth.Contract(abi, "0x6623444594c3555F9652AD1ed273f8317a55b35f", {from: accounts[0]});
console.log(contractInstance);
});
$("#bet0").click(function(){
bet = 0;
})
$("#bet1").click(function(){
bet = 1;
})
$("#confirm").click(inputData)
$("#get_data_button").click(fetchAndDisplay)
$("#withdraw").click(startWithdraw)
$("#withdrawPlayer").click(startWithdrawPlayer)
$("#get_balance_button").click(function(){
let res = contractInstance.methods.balance().call().then(function(res){
$("#balance_output").text(res);
})
});
$("#get_playerBalance_output").click(function(){
let res = contractInstance.methods.playerBalance().call().then(function(res){
$("#playerBalance_output").text(res);
})
});
});
function startWithdraw(){
var withdraw = $("#withdraw").val();
contractInstance.methods.withdrawFunds(withdraw).send();
}
function startWithdrawPlayer(){
var withdraw = $("#withdrawPlayer").val();
contractInstance.methods.withdrawFundsPlayer(withdraw).send()
.on("transactionHash", function(hash){ /
console.log(hash);
})
.on("confirmation", function(confirmationNr){
console.log(confirmationNr);
})
.on("receipt", function(receipt){
console.log(receipt);
alert("done");
})
}
function inputData(){
var amount = $("#amount").val();
var config = {
value: web3.utils.toWei("1", "ether")}
contractInstance.methods.setBet(amount, bet).send() /
.on("transactionHash", function(hash){
console.log(hash);
})
.on("confirmation", function(confirmationNr){
console.log(confirmationNr);
})
.on("receipt", function(receipt){
console.log(receipt);
alert("done");
})
}
function fetchAndDisplay(){
contractInstance.methods.getResult().call().then(function(res){
$("#amount_output").text(res.amount);
$("#bet_output").text(res.bet);
$("#message_output").text(res.message);
$("#result_output").text(res.result);
$("#playerBalance_output").text(res.playerBalance);
})
}
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>People</title>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
crossorigin="anonymous"></script>
<script type="text/javascript" src="./web3.min.js"></script>
<script type="text/javascript" src="./abi.js"></script>
<script type="text/javascript" src="./main.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
</head>
<body>
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-4">Welcome to Coinchain</h1>
<p class="lead">Make your bet safely through blockchain </p>
</div>
</div>
<div class="container">
<div>
<h2>Set your stake</h2>
<div class="input-group mb-3">
<input type="text" class="form-control" id="amount" placeholder="Set your stake" >
<input type="button" value="0" id="bet0" placeholder="0" >
<input type="button" value="1" id="bet1" placeholder="1" >
</div>
<button type="button" id="confirm" class="btn btn-primary">CONFIRM AMOUNT</button>
<div class="container">
<p class="lead">Make your bet safely through blockchain </p>
</div>
<div>
<h2>BET</h2>
<div>
Amount: <span id="amount_output"></span>
</div>
<div>
What did you bet: <span id="bet_output"></span>
</div>
<div>
YOU: <span id="message_output"></span>
</div>
<div>
coin flip was: <span id="result_output"></span>
</div>
Player Balance: <span id="playerBalance_output"></span>
</div>
<button type="button" id="get_data_button" class="btn btn-primary">Get Data</button>
</div>
<div>
Balance: <span id="balance_output"></span>
</div>
<div>
<button type="button" id="get_balance_button" class="btn btn-primary">Get balance</button>
</div>
<div>
Player balance: <span id="playerBalance_output"></span>
</div>
<div>
<button type="button" id="get_playerBalance_output" class="btn btn-primary">Get player balance</button>
</div>
<div>
<input type="text" class="form-control" id="withdraw" placeholder="amount to withdraw" >
<button type="button" id="withdraw" class="btn btn-primary">WITHDRAW</button>
</div>
<input type="text" class="form-control" id="withdrawPlayer" placeholder="amount to withdraw Player" >
<button type="button" id="withdrawPlayer" class="btn btn-primary">WITHDRAW PLAYER</button>
<div>
</body>
</html>
CONTRACT
import "./Ownable.sol";
pragma solidity 0.5.16;
contract coin3 is Ownable{
struct player {
uint amount;
uint bet;
string message; // message after flip: WIN or LOSE
uint result; // result of the coin flip return from Provable
uint playerBalance;
}
uint public balance;
uint public minBet;
modifier costs(uint cost){
require(msg.value >= cost);
_;
}
constructor() public payable{
require(msg.value >= 9*1000000000000000000);
balance += msg.value;
}
mapping (address => player) private players;
// address[] private playersArr;
// link amount player want ot pay to his address
function setBet(uint amount, uint bet) public payable costs( (players[msg.sender].amount)*1000000000000000000 ){
require(bet == 1 || bet == 0);
player memory newPlayer;
newPlayer.amount = amount;
newPlayer.bet = bet;
newPlayer.playerBalance = players[msg.sender].playerBalance;
insertPlayer(newPlayer);
// playersArr.push(msg.sender);
require((players[msg.sender].amount)*1000000000000000000 <= balance/2, "Bet over contract funds");
balance += msg.value;
if(random() == (players[msg.sender].bet)){
balance = balance - (players[msg.sender].amount)*1000000000000000000*2;
players[msg.sender].playerBalance = players[msg.sender].playerBalance + (players[msg.sender].amount)*1000000000000000000*2;
players[msg.sender].message = "WIN";
players[msg.sender].result = random();
}
else{
players[msg.sender].message ="LOSE";
players[msg.sender].result = random();
}
//maxBet = balance/2;
}
// coin win or lose
function random() public view returns(uint){
return now % 2;
}
function getResult() public view returns(uint amount, uint bet, string memory message, uint result, uint playerBalance){
address creator = msg.sender;
return (players[creator].amount, players[creator].bet, players[creator].message, players[creator].result, players[creator].playerBalance);
}
// only owner can withdraw money
function withdrawFunds(uint withdraw) public onlyOwner {
balance = balance - withdraw*1000000000000000000;
msg.sender.transfer(withdraw*1000000000000000000);
//maxBet = balance/2;
}
function withdrawFundsPlayer(uint withdraw) public {
require(withdraw<players[msg.sender].playerBalance);
players[msg.sender].playerBalance = players[msg.sender].playerBalance - (withdraw*1000000000000000000);
msg.sender.transfer(withdraw*1000000000000000000);
}
function insertPlayer(player memory newPlayer) private {
address creator = msg.sender; // variabile creator contiene address del giocatore
players[creator] = newPlayer; // collego player al suo address
}
}
where do i insert this?
Hey @enrico
All your send() methods are missing the sender address.
It is a mandatory field that you have to populate:
contractInstance.methods.withdrawFunds(withdraw).send();
Should be
contractInstance.methods.withdrawFunds(withdraw).send({from: accounts[0]});
Hey @Rob_McCourt
I suggest you to go through these lessons once again just to grasp the basic concepts of how a dapp works
Filip explains them step by step and you can follow him: https://academy.ivanontech.com/products/ethereum-smart-contract-programming-201/categories/1993956/posts/6668113
Give it a try and let me know.
Edit: If needed I can dm you my github with a really basic version of the dapp so that you can take a look. But first please try to do it yourself by googling and watching Filipās video. A bit of struggle is really helpful when learning a new thing
Keep in mind that we are here anyway
Cheers,
Dani
sorry,
is not clear to me, two doubts here:
the withdrawFunds function should allow the owner of the contract to withdraw money from the contract to his address (account 0).
writing as you suggested contractInstance.methods.withdrawFunds(withdraw).send({from: accounts[0]});
doesnāt this mean that the money are sent from the owner address (account 0) to the contract (so the opposite of what Iād like to do)?
with the withdrawFundsPlayer function I want to make it possible for the player to withdraw its wins.
writing the account of the player in the main.js file as follow:
contractInstance.methods.withdrawFunds(withdraw).send({from: accounts[X]});
how can I manage different players?
for example if i play first with account 1 from ganache and then with account 2 from ganache, should I always change the main.js file?
thanks :)!
Hi @dan-i got my metamask connectedā¦ Thanks. I was being an idiot and never clicked the directory which then took me to the Dapp. Then metamask asked me to log in which is working now.
Its just the functionality im struggling with.
Can you dm me the dapp so i can have a look please.
EDITā¦
Been working hard at it last night and updated some stuff scrounged from other Students but i am getting there nowā¦
I will update my Github Repo and let you know so you can check it out.
MAIN.JS
const contractId = CONTRACT_ID;
const abi = ABI;
const web3 = new Web3(Web3.givenProvider);
let playerAddress;
let contractInstance;
$(document).ready(() => {
window.ethereum.enable().then((accounts) => {
playerAddress = accounts[0];
contractInstance = new web3.eth.Contract(abi, contractId, {from: playerAddress});
displayDappBalance();
displayPlayerBalance();
$('#wager_button').click(inputData);
});
});
function displayDappBalance() {
contractInstance.methods.getDappBalance().call().then((res) => {
$('#dapp_balance_output').text(web3.utils.fromWei(res, "ether"));
});
}
function displayPlayerBalance() {
web3.eth.getBalance(playerAddress).then((res) => {
$('#player_balance_output').text(web3.utils.fromWei(res, "ether"))
});
}
function inputData() {
let config = {
value: web3.utils.toWei($('#wager_input').val(), 'ether')
};
let flipValue = $('#inlineFormCustomSelect').val() === 'Heads' ? true : false;
contractInstance.methods.flip(flipValue).send(config)
.on('transactionHash', (hash) => {
// console.log('1: ', hash);
})
.on('confirmation', (confirmationNr) => {
// console.log('2: ', confirmationNr);
})
.on('receipt', (receipt) => {
let result = receipt.events.flipResult.returnValues.value === '1' ? 'Heads' : 'Tails';
let waitingPeriod;
let n = 4;
waitingPeriod = setInterval(() => {
$('#result').text(n-=1);
}, 1000);
setTimeout(() => {
if (receipt.events.flipResult.returnValues.result === true) {
$('#result').text(result + '... You Won!')
} else {
$('#result').text(result + '... You Lost!')
}
clearInterval(waitingPeriod);
displayDappBalance();
displayPlayerBalance();
}, 4000);
});
}
Rob.