Programming Project - Phase 2

Ah, I’ll try some alternative way to get it to update. Thanks!

@cryptocrom
So basically as soon as you submit your bet and you refresh the page immediately, the buttons are still unclickable for you?

@dan-i Any idea to my problem? I basically have an issue where my isWaiting property as part of my mapping for the player struct stays false until the transaction has been sent. This causes a delay before the buttons are greyed out if I refresh the page right after submitting my bet.

If I don’t refresh the page then as soon as the button is clicked, both guessing buttons get disabled which is good but only until I refresh the page when the state of the buttons being greyed out is lost and then I’m having to wait until the property for the player’s isWaiting returns ‘true’ in which case the buttons will disable automatically.

It’s the issue with the property updating as soon as I set it in the function which is the main problem. Not sure what the work-around is…

I don’t have a waiting condition in my contract or front end anymore, I decided that I wanted a player to be able to have multiple games running at once, plus my DApp has 3 different games (coin flip, dice roll and high card draw) and I want a player to be able to play as many as they like at once. The contract requirements determine whether the player has enough to cover multiple bets/games and then funds are locked until each bet’s conclusion.

At the risk of pointing to something that is not in fact incorrect again (like I did with the if(player.isWaiting) bit)…the loadPlayerStats() function looks incorrect to me…

await contractInstance.methods.getPlayer.call().call().then(function(res) {

it has .call() twice in a row. This may or may not be affecting things but I would’ve thought this would be unrecognised by your JS file and appear in your console as an error (it does for me if I have call().call() in my getter functions). In my head, this would mean the player object does not in fact have the data you are looking for and therefore the if(player.isWaiting) {} statement will just always be false upon page refresh…or am I understanding this incorrectly? However I can see in your screenshots that there is in fact user information displayed, so I’m probably incorrect yet again haha. If that solves it, yay otherwise you could problem solve this yourself though by adding a heap of console.logs in your JS file at each step and then just keep an eye on what is being logged and in what order, then you will be able to see where it falls apart. Good luck with it

1 Like

Here is my project phase 2 - flipcoin. It was a fight but it seems, I made it! :slight_smile:
https://github.com/tomas819/flipcoin

I must say, it is not easy to develop smart contracts… I had several issues on the project :-/
Here are some points:

  • the truffle-hdwallet-provider was not working, I had to use “npm install @truffle/hdwallet-provider”

  • the Ganache GUI is very slow or just stops working. The GUI is basically not necessary, it is sufficient to use only cli

  • using the constructor (for provable):
    constructor() public {
    provable_setProof(proofType_Ledger);
    }
    was causing the following error by the deployment on my local network, on the ropsten testnet it was OK
    “Flipcoin” hit a require or revert statement somewhere in its constructor. Try:
    *Verifying that your constructor params satisfy all require conditions.
    *Adding reason strings to your require statements.

  • by deploying on ropsten testnet I received a few times this error (which, what I found, was caused by Infura)
    Error: PollingBlockTracker - encountered an error while attempting to update latest block:
    Error: ETIMEDOUT

  • testing on the ropsten testnet is very slow, sometimes I had to wait several minutes for the response from the oracle

In the end, it is a good experience!

Now, I started the course about smart contract security, so I will keep working on the project. And sure, there is a space for some improvements, for example funding the contract in advance, etc.

Also, it would be good to upgrade it to the latest version of solidity - here I expect some challenges, because what I saw in the documentation, there are many things already deprecated… this area is evolving really fast!

1 Like

Hey @dan-i,

Here is the link to my Github account and thanks for taking a look at it.
https://github.com/TopgunJHW/CoinFlip-Dapp/blob/provable-oracle/project/contracts/RandomExample.sol

My problem is that I cannot call the update function in truffle console, while the contract is already deployed on the ropsten testnet. I get the error:
Uncaught TypeError: Cannot read property ‘address’ of undefined

Cheers,
Jian

1 Like

Basically I had to call .call() twice because when I did it 1x it errored on the console:

The issue is on the back-end since that’s where the property values take time to update since it’s waiting for the transaction to be sent before the values are updated. I checked by loading the smart contract via Remix and calling getPlayer() to confirm this and the isWaiting property remained false until the oracle query was sent.

From what I understood in your own game you decided not to send a payable transaction until the bet is complete. So once it is completed, you deduct the player’s funds. That makes sense actually, so you just check before hand if the person has enough funds. I’ll see if I can try something along the lines of that, thanks!

Hey @Jian_Hao_Wei

Follow this one first and let me know: FAQ - How to downgrade Node.Js

1 Like

Hey @dan-i,

Thanks a lot it works now!

1 Like

Hi,

I’m stuck with phase 2, and need your help. I have a problem with provable transaction.
Here is my code https://www.dropbox.com/s/cw9axm4y4buos9f/contracts.zip?dl=0

Here is simple smart contract I made to test provable,
for some reason transaction send to provable is failing
https://ropsten.etherscan.io/tx/0xbfffc754e895d2d3f93d284b65131d7cbbeb88fb0f4f76305d71f4cb76b1c4b4

please help

pragma solidity > 0.6.1 < 0.7.0;
import"./provableAPI.sol";

contract RandomTest is usingProvable {
    
    uint256 public myNumber;
    uint public balance;
    uint public provablePrice;
    uint256 constant NUM_RANDOM_BYTES_REQUESTED = 1;

    event newProvableQuery(string description);

    constructor() payable public {
        provable_setProof(proofType_Ledger);
    }
    
    function deposit() payable public {
        balance += msg.value;
    }
    
    function update() public payable {
        uint256 GAS_FOR_CALLBACK = 200000;
        uint256 QUERY_EXECUTION_DELAY = 0;
        
        provable_newRandomDSQuery(
            QUERY_EXECUTION_DELAY,
            NUM_RANDOM_BYTES_REQUESTED,
            GAS_FOR_CALLBACK
        );
        emit newProvableQuery("update started");
        
    }
    
    function __callback(bytes32 _queryId, string memory _result, bytes memory _proof) override public {
         if (
                provable_randomDS_proofVerify__returnCode(
                    _queryId,
                    _result,
                    _proof
                ) != 0
        ) {
        } else {
            myNumber = uint(keccak256(abi.encodePacked(_result))) % 2;
            emit newProvableQuery("callback finished");
        }
    }
    
}

edit, I found what was wrong, there was wrong type used. Are there any tips how to debug that provable queries ?

Took me a while to finish it. Please review my code and tell me ways to improve it :slight_smile:
Here’s my github
https://github.com/nelabv/CoinFlip
And here’s the video of it working
https://www.youtube.com/watch?v=626hGEBKti8

Great thanks!

2 Likes

Hey @Dominik_Szopa

You can take a look at their docs: https://docs.provable.xyz/

Hey @newavel

I have not found critical bugs by reading your contract.
If you want to improve it I could suggest two things.

  • Verify the sender or the random number as explained in the oracle docs;
  • If you followed the smart contract security course, implement safemath. If you have not done that course yet, I strongly suggest to do it :slight_smile:
1 Like

Hosted on github pages:
https://endre-szucs.github.io/coinflip_ropsten/

Source code:
https://github.com/endre-szucs/coinflip_ropsten

Screencap with working dapp:
https://media.giphy.com/media/mxeOUHskKpmOEDCopR/source.gif

1 Like

hello,

i wasn’t able to get ethereum for ropsten network from any faucet.

this is my file on github with contract and everything.

https://github.com/enricofabris/coin_flip/

Can you please tell me if it is without mistake and it is working?

how can I use remix with ropsten network as in the video? are necessary ethereum in metamask as well to do it in this way?

thanks

Hey @enrico

i wasn’t able to get ethereum for ropsten network from any faucet.

Faucets are sometimes buggy, here a list that I use (Ropsten):

https://faucet.ropsten.be/
https://faucet.dimensions.network/

You just have to paste your wallet address.

Let me know,
Dani

2 Likes

Answered yesterday to your dm :slight_smile:

1 Like

hello,

thanks :slight_smile: finally i got the eth on metamask ropsten network.
I get the same mistake when migrating as in the other post you are helping me with, so some error with the constructor

"coin" hit a require or revert statement somewhere in its constructor. Try:
   * Verifying that your constructor params satisfy all require conditions.
   * Adding reason strings to your require statements.

this is the contract

import"./Ownable.sol";
import"./provableAPI.sol";

pragma solidity 0.5.16;

 contract coin is Ownable, usingProvable{

    struct player {
      uint amount;                          // amount the player want to bet in ether
      uint bet;                             // what the player want to bet: 0 or 1
      address payable playerAddress;        // address of the player
      string message;                       // message after flip: WIN or LOSE
      uint result;                          // result of the coin flip returned from provable
    }

    uint public balance;                                    // updated balance of the contract
    uint public minBet;                                     // minimum bet set by the owner
    uint256 constant NUM_RANDOM_BYTES_REQUESTED = 1;
    bytes32 queryId;

    event logNewProvableQuery(string description);
    event generateRandomNumber(uint256 randomNumber);

    modifier costs(uint cost){
        require(msg.value >= cost);
        _;
    }

// owner send money to the contract at the moment of deployment
    constructor() public payable{
        require(msg.value >= 1000000);
        balance += msg.value;
    }


    mapping (address => player) private players;  // link player to his address
    mapping (bytes32 => player) private playerId; // link player to his queryId
    mapping (address => bool) private waiting;    // link player to his waiting status: true or false



// player set his bet (0 or 1), his bet amount and send that amount to the contract
    function setBet(uint amount, uint bet) public payable costs( (players[msg.sender].amount)*1000000000000000000 ){

        require(waiting[msg.sender] = false);  // player which is waiting for bet result can't bet before to know the result

        waiting[msg.sender] = true;  // once th player set the bet his waiting status is set to true

        player memory newPlayer;
        newPlayer.amount = amount;
        newPlayer.bet = bet;
        newPlayer.playerAddress = msg.sender;

        insertPlayer(newPlayer);   // players[msg.sender] = newPlayer

// require that the amount bet is lower than half balance
        require((players[msg.sender].amount)*1000000000000000000 <= balance/2, "Bet over contract funds");
        balance += msg.value;

        update();

        playerId[queryId] = newPlayer;
    }


    function __callback(bytes32 _queryId, string memory _result, bytes memory proof) public {
        require(msg.sender == provable_cbAddress()); //l'address deve essere quello dell'oracle

        uint256 randomNumber = uint256(keccak256(abi.encodePacked(_result))) % 2;

        emit generateRandomNumber(randomNumber);

        if(randomNumber == (playerId[_queryId].bet)){

        balance = balance - (playerId[_queryId].amount)*1000000000000000000*2;
        playerId[_queryId].playerAddress.transfer( (playerId[_queryId].amount)*1000000000000000000*2 );

        players[playerId[_queryId].playerAddress].message = "WIN";
        players[playerId[_queryId].playerAddress].result = randomNumber;

        }
            else{

            players[playerId[_queryId].playerAddress].message = "LOSE";
            players[playerId[_queryId].playerAddress].result = randomNumber;
            }

    waiting[playerId[_queryId].playerAddress] = false;
    }


    function update() payable public {
        uint256 QUERY_EXECUTION_DELAY = 0;
        uint256 GAS_FOR_CALLBACK = 20000;
        queryId = provable_newRandomDSQuery(
        QUERY_EXECUTION_DELAY,
        NUM_RANDOM_BYTES_REQUESTED,
        GAS_FOR_CALLBACK
        );

        emit logNewProvableQuery("Provable query was sent, standing by for answer");
    }


   function getResult() public view returns(uint amount, uint bet, string memory message, uint result){
        address creator = msg.sender;
        return (players[creator].amount, players[creator].bet, players[creator].message, players[creator].result);
    }

// only owner can set the minimum bet
    function minimumBet(uint minimum) public onlyOwner {
       minBet = minimum;
    }


// only owner can withdraw money
    function withdrawFunds(uint withdraw) public onlyOwner {

       balance = balance - withdraw*1000000000000000000;
       msg.sender.transfer(withdraw*1000000000000000000);
   }

  function insertPlayer(player memory newPlayer) private {
        address creator = msg.sender;
        players[creator] = newPlayer;
        }

}

in this case the constructor is sending much less than 1 eth but still there is the error (in metamask I have 1 eth)

please post your migration file

thanks, i didn’t realize to check the migration file, now i fix it and it works :slight_smile:
thanks :slight_smile:

at this point i compiled and migrated the contract on truffle, so how can now interact with the contract?

should I start the server (py -m http.server) and open the html page? (like we did previously)

or should we somehow connect remix?

sorry but i didn’t get how to proceed from the videos

thanks

You are migrating with truffle therefore Remix is not involved in any way. You can run your dapp in your python server

1 Like