Programming Project - Phase 2

Hey @dan-i

i am not sending any ether, and balance is 5.5.

ropsten: {
provider: () => new HDWalletProvider(mnemonic, https://ropsten.infura.io/v3/3ae275a25c7849609b9981ca125397c5),
network_id: 3,
gas: 5500000,
confirmations: 2,
timeoutBlocks: 200,
skipDryRun: true
}

Hey @Jian_Hao_Wei

Can I have the link to your github repo?

thanks!

It is really strange, are you sure that the mnemonic phrase belongs to the wallet with 5 eth and that you are not sending ether when migrating?
Please push your project on github and share the link, I want to double check this one :slight_smile:

Cheers,
Dani

Hi there,

The working version of my coinToss-dApp is as below:

  1. User Making a Bet.
  2. While a user is waiting for the betting result, the same user cannot make a second bet.
  3. Once the betting result is back, displaying results in the ā€œYour Betting Resultā€ area.
    coinTossGame_v3

The repo link is: https://github.com/AikenChung/coinToss.git
Any suggestions and advises are very welcome. Thanks a lot in advance!!

Cheers,

Here is my github repo:

https://github.com/CatalystJesal/CoinFlip/tree/part-2

Notable issues:

I tried to fool-proof the UI such as not being able to flip again during an ongoing game session, but in the case where the player refreshes the page and the event has yet to fire the buttons remain active, before they go grey indefinitely after event firing until the session has completed.

Also, I tried to foolproof cases where the player decides to switch to a different Metamask while they are currently waiting for the game result from their original account. Though I think it requires some kind of key, value mapping to separate each Player object on the front-end since currently there’s only one Player object whose values are written to, not good if the player is utilizing multiple account addresses to play the game.

Would appreciate any assistance/guidance on achieving this as an improvement for future projects or current one should this be required.

Thanks!

EDIT (23/11/2020)

I have fixed the bug where the game outcome was showing for a different selected address on the front-end if I had played from a different address. I added a check to the queryId -> player address vs the current contract instance’s address to fix this issue as soon as FlipOutcome event is triggered.

@cryptocrom Thanks for the guidance

2 Likes

You could have a getter function that fires as soon as the page is loaded that checks the waiting status mapped to that player (from your Player struct). If waiting is false, buttons are displayed or functional else buttons are hidden or have no functionality or whatever you want to do to them.

I hope I’ve understood you correctly here, but your contract deals with the separation of players through the mapping of address to Player struct so front end doesn’t really need to separate…it should just be reading the contract from the perspective of whatever address is connected and communicating that data only. If you set up the event listeners correctly then player B shouldn’t get player A’s results etc (which is where the queryId comes in handy).

Good luck with it and its good to see how much thought you are putting into real world use cases.

2 Likes

@dan-i
https://github.com/TobyKreiselmaier/Coinflipper

Contract is deployed on Kovan testnet and uses Chainlink VRF for randomness.
For safety, the user access is controlled in the frontend and funds must be manually withdrawn.

Thanks for the feedback!

For the first part, I did that and it works but the issue is the time it takes between the event to fire once the transaction has been sent (the coinflip bet). So once the bet is submitted the buttons are disabled but say as a user I decide to refresh the page very shortly after submitting my flip. Then the buttons will go back to being enabled again, because the state of whether or not we are still isWaiting from the contract is still false until the transaction has been sent successfully, not sure how to make it instantaneously set to isWaiting = true through the contract :confused:

Okay, so I may have explained it in an unclear way. Also, I have since looked at your JS file and can see that you already have most of it sorted.
My suggestion was to have a getter that fires before anything else and then make your buttons either active or inactive depending on the results from the getter - turns out you’ve already done exactly that…you just need define the if statement correctly I think.

if (player.isWaiting) {   //should this part not be == to something?
        enableButtons(false);
      } else {
        enableButtons(true);

See how that works out, good luck.

Hey @Spartak,

I tested your repo, you are facing that issue due to not enough ether in your wallet, use a faucet to get some :slight_smile:
I have removed the post with your github repo, check your DMs, I will send a message.

Happy learning,
Dani

player.isWaiting is the same as saying player.isWaiting == true when it comes to bools in programming. I did try it for laughs incase it did anything but it led to the same result. :frowning:

Oh yeah of course, there is a statement written like that in the Smart Contract Security course so not sure why I thought that, I think out of habit I tend to define if statements fully for my own readability. Anyway, I had something similar to what you have done, obviously written differently and it worked for me so the concept is right, just gotta figure out the flow. Good luck

1 Like

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");
        }
    }
    
}