Ethereum coinflip dapp discussion

I can not deploy the contract properly to the testnet and unfortunately i have no more idea how to fix it. :grimacing: Here is my state:

As you see my Metamask is unlocked and funded.
My guess is that the contract configure does not safe the settings when i click on ā€œSAVEā€. Here is what i mean.
I do this.


Click on save and get this back.

Iā€™m not sure if this normal behavior. I have tried this with two browsers now. Chrome and Brave.
For completeness, here are my other settings:

(The code .sol & .html & .js was copy pasted from the Github link)

I also tried to go into MetaMask settings to change the Privacy Mode. But i cloud not find the option.


My MetaMask version is 7.2.1

I have to miss something. But what? :thinking:

Hmmm. Make sure you donā€™t block cookies or anything like that. Then try go intro metamask settings -> Connections and add superblocks url there. Let me know if it works. I want to get you going!

I love that you are experimenting on your own! Good job. I see a few things that look odd to me though, and it has to do with how you deal with owner.

In your getLastFlip function you take owner as an argument. But you shouldnā€™t call that owner, thatā€™s just an argument coming from the caller. The owner variable is a state variable and is only set once, in the constructor.

But then, if you actually were to use the owner state variable, then you would get the same ā€œlast flipā€ every time. Since you call it with the same address every time.

This mistake also seems to be present in the flip function.

But maybe I have misunderstood what youā€™ve tried to do here? Why did you add owner instead of msg.sender?

Hi Filip, sorry i didnā€™t mention it but i already have connected the superblocks url in the MetaMask settings. Now i have reset the googleChrome settings to default. I also tried an other Testnet (Ropsten) but nothing have changed. It must be a very stupid mistake. XD
I know now that the settings in sperblocks Configure are saved, even when they jump back to default on the interface after clicking ā€œSAVEā€. That was my apprehension but it turned out to be false.

I will try it one more time later. If i still have this issue i will move on and postpone this problem to later. :grimacing:

But anyway thank you Filip.

Hi Philip,
I was just trying to learn by experiment, trying to sharp issues that i am not totally clear with ( sometimes its not enough for me to assume that i am understandā€¦i wanted to be sure about it), so thank you very much.

i made another change - random formula (see below):

function random () private view returns (uint8) {
       return uint8(uint256(keccak256(msg.value,block.timestamp))); 

uint time= random(); //block.timestamp;

I tried to make it more randomizeā€¦(that it will be subject to additional factors that are uncontrolled by the minersā€¦)

your opinion,
thanks

Hi
I have noticed that if we want to reduce the balance amount X2 while winning
we need to multipy by 3 as followes:

 if(time % 2== 0){
        msg.sender.transfer(bet*3);   /*2*/
        lastFlip [msg.sender]= true;
    }

Hey @Paultier !

Thomas from Superblocks here.

I have an idea what the problem might be.

Thing is that Metamask has increased their privacy and are not exposing Metamask accounts to any site you visit, which a very good thing. However it breaks some apps, because the app now has to enable it self to be used with Metamask, and the user has to agree to this in the Metamask UI.

This version of Superblocks does not do that automatically, but you can hack it (yaā€™ll hackers right?).
Open the javascript console in the same window you have Superblocks loaded, be sure Metamask is unlocked and run this in the javascript console:

web3.currentProvider.enable()

Metmask will popup a window for you to agree do enable Superblocks to use Metamask.

Let me know how it goes,
Keep hacking!

2 Likes

I am on the third part of DApps content and this is the first time when I completely donā€™t know what is going in the course even after watching the video 4 times.

These web3, function callbacks, receipt status etc. it not clear enough for me now.

My point is that maybe for future update you will take more time for deeper explanation of all these things, for now I will watch the rest of the videos and then dig deeper in the google for more info. Maybe it is too early to submit that feedback and everything will get clear at the end of the series.

I have problem with deploying the contract on the testnet, I have exactly the same code as you Filip and the Superblocks is saying that arguments are wrong in the constructor, wtf?

Got receipt: 0x9ad1389d2311b9d133f75a88720ba74331bcbbd9230f44e6d6ca7f19ca4435e6
Waiting for contract to be deployedā€¦
Transaction mined, verifying codeā€¦
Contract did not get deployed. Wrong arguments to constructor?

pragma solidity ^0.4.17;

contract Coinflip {
    address owner;
    
    function Coinflip() public {
        owner = msg.sender;
    }

    function getBalance() constant public returns(uint) {
        return this.balance;
    }

    function getBet() public payable {
        uint bet = msg.value;
        uint randomNumber = block.timestamp;

        if (randomNumber % 2 == 0){
            msg.sender.transfer(bet * 2);
        }
    }

    function deposit() public payable {
        
    }

}

Never mind, I leave it for future students. There was a problem because I consciously have chosen the Ropsten testnet instead Rinkeby. I thought it doesnā€™t matter, but it does.

The reason I have used Ropsten was that the faucet from the link automatically send ETH to Metamast for this testnet and I couldnā€™t change that, then I used faucet dedicated for Rinkeby and it is working now.

1 Like

Yeeha, it worked at the first attempt.

Thank you @bashlund (Thomas) for the hack! :sunglasses: Now iā€™m really relieved.

2 Likes

I will take that feedback into consideration when I remake these videos.

But did you solve your issue?

Hi,

Iā€™ve been experimenting. I modified the flip function so that the player provides some input
so that the miner does not have all the control over the result of flip function. But now the dapp does not work. Here is my code.

contract:

pragma solidity ^0.4.17;
/// problem: if txn fee is more than you bet, you end uo losing eth even
/// if you won flip
contract Coinflip2 {
  address owner;
  mapping(address => bool) lastFlip;

  function Coinflip() public{
    owner = msg.sender;
  }

  function getBalance() constant public returns (uint){
    return address(this).balance;
  }

  function getLastFlip(address player) constant public returns (bool){
    return lastFlip[player];
  }


  function flip() payable public{
    uint time = block.number;
    uint bet = msg.value;

    if( time % 2 == 0){
      msg.sender.transfer(bet*2);
      lastFlip[msg.sender] = true;
    }
    else{
      lastFlip[msg.sender] = false;
    }
  }

  function flipT(uint playersChoice ) payable public{
    uint time = block.number;
    uint bet = msg.value;

    if( (time+playersChoice) % 2 == 0){
      msg.sender.transfer(bet*2);
      lastFlip[msg.sender] = true;
    }
    else{
      lastFlip[msg.sender] = false;
    }
  }

  function deposit() payable public {
  }
}

js

(function (Contract) {
    var web3_instance;
    var instance;
    var accounts;

// in this version try to display in html if player wins or losses

    function init(cb) {
        web3_instance = new Web3(
            (window.web3 && window.web3.currentProvider) ||
            new Web3.providers.HttpProvider(Contract.endpoint));

        accounts=web3.eth.accounts;

        var contract_interface = web3_instance.eth.contract(Contract.abi);
        instance = contract_interface.at(Contract.address);
        cb();
    }

    function getBalance() {
        instance.getBalance(function (error, result) {
            if(error){
                alert(error);
            }
            else{
                $("#balance").html(result.toString());
            }
        });
    }


    function waitForReceipt(txHash,cb){
        web3_instance.eth.getTransactionReceipt(txHash, function(error, receipt){
            if(error){
                elert(error);
            }
            else if(receipt !=null){
                cb(receipt);
            }
            else{
                window.setTimeout(function(){
                    waitForReceipt(txHash,cb);
                },5000);
            }
        });
    }



    function getResult(){
        instance.getLastFlip(accounts[0],function(error, result){
            if(result){
                $('#result').html("You won!");
            }
            else{
                $('#result').html("You lost!");
            }
        });
    }


    function flip(){
        let val=parseInt($("#bet").val());
        let playersChoice=parseInt($("#playersChoice").val());
        instance.flipT(playersChoice).sendTransaction({from: accounts[0], gas: 100000, value: val },
        function(error, txHash){
            if(error){
                alert(error);
            }
            else{
                waitForReceipt(txHash, function(receipt){
                    if(receipt.status === "0x1"){
                        getResult();
                        getBalance();
                    }
                    else{
                        alert("Receipt status fail");
                    }
                });
             }
        });
    }

    $(document).ready(function () {
        init(function () {
            getBalance();
        });
        $("#submit").click(function(){
            flip();
        });
    });

})(Contracts['Coinflip2']);

html

<!DOCTYPE html>
<html lang="en">
    <head>
        <script type="text/javascript" src="https://unpkg.com/[email protected]/dist/jquery.js"></script>
        <script type="text/javascript" src="https://unpkg.com/[email protected]/dist/web3.min.js"></script>
        <!-- JAVASCRIPT -->
        <!-- STYLE -->
    </head>
    <body>
        <h1>Coinflip Game</h1>
        <p> Welcome to coinflip contract. You are playing vs. the contract. </p>
        <h2>Balance in contract: <span id="balance"></span></h2>
         <p> Choose 1 for talis and 0 for heads </p>
        <input id="playersChoice" type="number"/> 

        <input id="bet" type="number"/>
        <button id="submit"> Submit </button>
        <h3 id="result"> </h3>

    </body>
</html>

Dapp is very similar to Filipā€™s. I included two functions on my contract: the original flip and flipT (T is for testing). When I use flip in js flie it works but with flipT it doesnā€™t. I can use ā€œinteractā€ in Superblocks and the contract works fine, with both flip and flipT, but there is some problem with the js (I guess).
Any help would be appreciated.

There is an error in how you call your function with arguments. This is the blueprint for how we call functions with arguments attached.

myContractInstance.myMethod.sendTransaction(param1 [, param2, ...] [, transactionObject] [, callback]);

Taken from the docs: https://github.com/ethereum/wiki/wiki/JavaScript-API#contract-methods

This would mean that your call would be written like this.

instance.flipT.sendTransaction(playersChoice, {from: accounts[0], gas: 100000, value: val },
        function(error, txHash){........

Thanks Filip! that does it. Works fine!

Now, I am trying to setup dapp outside superblocks. Iā€™m using github
to post the code and get a webpage. So I created a repository, upload
the code from superblocks (the one you get from view tab when you click
Show source) and enable metamask using the hack ā€œweb3.currentProvider.enable()ā€
that @bashlund gave us.

HTML displays fine and I can send transactions to contract. Using superblocks and a block explorer I can see the flip function works fine but my problem is that the webpage does not update balance nor display the ā€œyou wonā€ or ā€œyou lossā€ text. Any ideas how to fix it, please?

Here is code from superblocks and below is the error from console in chrome.

<!DOCTYPE html>
<html lang="en">
    <head>
        <script type="text/javascript" src="https://unpkg.com/[email protected]/dist/jquery.js"></script>
        <script type="text/javascript" src="https://unpkg.com/[email protected]/dist/web3.min.js"></script>
        
<script type="text/javascript">
/* Autogenerated - do not fiddle */
if(typeof(Contracts)==="undefined") var Contracts={};
(function(module, Contracts) {
    var data={
        address: "0x55e205dbdc84ef9bff23c88106acc94163bc06f4",
        network: "rinkeby",
        endpoint: "https://rinkeby.infura.io/",
        abi: [{"constant":true,"inputs":[],"name":"getBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"player","type":"address"}],"name":"getLastFlip","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"flip","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]
    };
    Contracts["Coinflip"]=data;
    module.exports=data;
})((typeof(module)==="undefined"?{}:module), Contracts);

(function (Contract) {
    var web3_instance;
    var instance;
    var accounts;

// in this version try to display in html if player wins or losses

    function init(cb) {
        web3_instance = new Web3(
            (window.web3 && window.web3.currentProvider) ||
            new Web3.providers.HttpProvider(Contract.endpoint));

        accounts=web3.eth.accounts;

        var contract_interface = web3_instance.eth.contract(Contract.abi);
        instance = contract_interface.at(Contract.address);
        cb();
    }

    function getBalance() {
        instance.getBalance(function (error, result) {
            if(error){
                alert(error);
            }
            else{
                $("#balance").html(result.toString());
            }
        });
    }


    function waitForReceipt(txHash,cb){
        web3_instance.eth.getTransactionReceipt(txHash, function(error, receipt){
            if(error){
                elert(error);
            }
            else if(receipt !=null){
                cb(receipt);
            }
            else{
                window.setTimeout(function(){
                    waitForReceipt(txHash,cb);
                },5000);
            }
        });
    }



    function getResult(){
        instance.getLastFlip(accounts[0],function(error, result){
            if(result){
                $('#result').html("You won!");
            }
            else{
                $('#result').html("You lost!");
            }
        });
    }


    function flip(){
        let val=parseInt($("#bet").val());
        instance.flip.sendTransaction({from: accounts[0], gas: 100000, value: val },
        function(error, txHash){
            if(error){
                alert(error);
            }
            else{
                waitForReceipt(txHash, function(receipt){
                    if(receipt.status === "0x1"){
                        getResult();
                        getBalance();
                    }
                    else{
                        alert("Receipt status fail");
                    }
                });
             }
        });
    }

    $(document).ready(function () {
        init(function () {
            getBalance();
        });
        $("#submit").click(function(){
            flip();
        });
    });

})(Contracts['Coinflip']);

</script>


        <style type="text/css">
body {
    background-color: midnightblue;
    color: darksalmon;
    font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
    text-align: center;
}
</style>

    </head>
    <body>
        <h1>Coinflip Game</h1>
        <p> Welcome to coinflip contract </p>
        <h2>Balance: <span id="balance"></span></h2>
        <input id="bet" type="number"/>
        <button id="submit"> Submit </button>
        <h3 id="result"> </h3>

    </body>
</html>

error message

inpage.js:1 Uncaught Error: Invalid number of arguments to Solidity function
    at Object.InvalidNumberOfSolidityArgs (inpage.js:1)
    at u.validateArgs (inpage.js:1)
    at u.toPayload (inpage.js:1)
    at u.call (inpage.js:1)
    at u.execute (inpage.js:1)
    at getResult (home.html:71)
    at home.html:92
    at Object.callback (home.html:58)
    at inpage.js:1
    at inpage.js:1

can you send me the url you are using to interact with it? Would help me debug.

Hi Filip. Yes, sure

https://tfranciscoj.github.io/Dapp_test/home.html

Github repository

Thanks !

Alright, Iā€™ve figured out what the issue is. I havenā€™t figured out why it happens though.

The issue is that the account array is empty. So when you are making the call to getLastFlip with account[0] as the argument, it is null. The account array is initialized in the init function, but it doesnā€™t seem to be available from metamask when the init function runs.

You should be able to solve it by setting account = web3.eth.accounts in the flip function. Try that :slight_smile:

Thanks Filip, it worked! Just one detail: set accounts=web.eth.accounts in getResult(), instead of flip().

Iā€™ve been enjoying the course :grinning:

1 Like

Great! Good job on building and hosting your own dapp :slight_smile:

Hi @filip,

Happy New Year. Iā€™m currently on coinflip part 4, and everything compiles fine, any transfer I send from metamask works, and the contract has zero issues deploying. However, thereā€™s an issue where my balance doesnā€™t seem to update (it doesnā€™t even display ā€œ0ā€ when I add a value to it. Was hoping to see if thereā€™s anything Iā€™ve done wrong. Please see what my ā€œviewā€ folder looks like below;

also, below is my code:

CoinFlip

Welcome to the coinflip contract

Balance:

Submit

JS:
(function (Contract) {
var web3_instance;
var instance;
var accounts;

function init(cb) {
    web3_instance = new Web3(
        (window.web3 && window.web3.currentProvider) ||
        new Web3.providers.HttpProvider(Contract.endpoint));

        accounts=web3.eth.accounts;

    var contract_interface = web3_instance.eth.contract(Contract.abi);
    instance = contract_interface.at(Contract.address);
    cb();
}

function getBalance() {
    instance.getBalance(function (error, result) {
        if (error){
            alert("there's been an error");
        }
        else{
            //set value HTML
            $("#Balance-id").html(result.toString());
        }
    });
}

function waitForReceipt(txHash, cb){
    web3_instance.eth.getTransactionReceipt(txHash,function(error,receipt){
        if(error){
            alert(error);
        }

        else if (receipt !== null){
            cb(receipt);
        }

        else{
            window.setTimeout(function(){
                waitForReceipt(txHash, cb);
            },5000);
        }
    })
}

   function flip(){
  let val = parseInt($("#bet-input").val());
  instance.flip.sendTransaction({from: accounts[0] , gas:100000, value: val}, function(error, txHash){
    if(error){
      alert(error);
    }
    else{
        waitForReceipt(txHash, function(receipt){
          if(receipt.status === "0x1"){
            alert(JSON.stringify(receipt));
          }
          else{
            alert("receipt status fail");
          }
        });
    }
  })
}
$(document).ready(function () {
    init(function () {
        getBalance() ;
    });

$("#submit").click(function(){
    flip();
})
});

    })(Contracts['CoinFlip']);

Solidity:
pragma solidity ^0.4.17;

contract CoinFlip {
address owner;

function CoinFlip() public {
    owner = msg.sender;
}

function getBalance() constant public returns(uint){
    return address (this).balance;
}

function flip() payable public {
    uint time= block.timestamp;
    uint bet= msg.value;

    if (time % 2==0){
        msg.sender.transfer(bet*2);
    }

}

function deposit() payable public {

}

}

oh, the HTML coding actually wrote out the code, here is a screenshot instead