Programming Project - Phase 2

First, thanks @lucas for taking a look at my dapp, the event listener finally works :partying_face:

Here is my version:


The repo doesn’t contain node modules folder as it is huge, and the .secret file.

When the page is first loaded, it makes sure that Metamask is connected and brings it up if it is not.
When a user enters the desired amount and presses BET, a transaction is created:

On confirmation, the user gets an alert:

In Ropsten Etherscan we can see the received transaction:

Under Internal Txns, we can see that the contract has made a request to the oracle:

When the contract receives a random number, the user gets an alert:

The same message is added to the table body:

Looks like I am lucky today :smile:
In Etherscan, we can see that the oracle has responded and the user has been paid:

As the owner, I can also check the new balance of the contract:

As defined in Coinflip_deploy.js, 0.1 ETH is deposited when deploying. There is a deposit function to increase balance, and it works :smile:

The withdraw, though, doesn’t work. I don’t want to make it “withdraw all”, because that wouldn’t be optimal in real life. We want to withdraw profit, but keep some balance to continue operating.
To do that, my withdraw function takes an argument:

11

It works fine when I just enter the amount in wei and pass it to the function like that.
If, however, I try this:

let withAmount = $("#withdraw").val();
let withConfig = Number({value: web3.utils.toWei(withAmount,"ether")});

I get this:

12

And, if I try this:

let withAmount = $("#withdraw").val();
let withConfig = Number(withAmount*1e18);

I get this:

image

Thanks @dan-i for pointing out that I didn’t convert it to number before, but apparently I am still passing a wrong data type.

Other improvement points:

  • The contract doesn’t take a new bet from address until the current one is fully executed. If, however, the player tried to place another bet, they just get an error in MetaMask. It would be nice to create a listener for pendingBet variable and bring up an alert, but I didn’t really figure it and I have already been stuck on this project for some time :smile:

  • The same issue applies if the bet amount is too high.

  • When a player refreshes the webpage, the win/lose history is cleared.

  • If the player is not the owner, they shouldn’t see the owner buttons, but I haven’t looked for a solution to that yet.

1 Like

Hey @MarcisB

Well done with your project.

To convert a string to int try:
let withAmount = parseInt($("#withdraw").val());

cheers,
Dani

2 Likes

Now I don’t get an error, MetaMask sends the request, but the contract doesn’t send me any funds:

Coin Flip Dapp - Phase 2. (working with Ropsten network and ProvableAPI Oracle)

coinFlipDspp

1 Like

Hi @filip I’ve just started working on Phase 2 of my dapp
Great course btw. but I must tell you about one thing, little bit of-topic, that came through my mind when I was finishing Phase 2 lesson videos
 I understand it should be a common sense thing but I really think that you should put some kind of a warning somewhere under “Hand in” description for those reckless ones not to upload their .secret file to GitHub :sweat_smile:
I know it is stupid thing to do but people do stupid things so better be safe then sorry :vulcan_salute::nerd_face:

1 Like

When I run truffle migrate --network ropsten, it compiles the project but does not deploy it.

Truffle v5.0.42 (core: 5.0.42)
Solidity - 0.5.12 (solc-js)
Node v12.19.0
Web3.js v1.2.1

Does anyone have the same issue?

@rostyslavdzhohola

you need to use the --reset flag

truffle migrate --network ropsten --reset

3 Likes

Thank you. That worked perfectly.

2 Likes

I believe my Ganache lagging because I have too many files in the node_modules folder. Can someone send me a list of files you have in your node_mdules? I’ve evidently installed everything there was.

Hey, everyone!

After months and months and months of persistence (and many rebuilds from scratch), I’d like to share my project with you all. I know some initial improvements would be to add other networks beside Ropsten and detect account changes, but I’d love to hear any other improvement ideas. Those of you still working on this dApp, check out my code and feel free to reach out. Thank you @filip @gabba and everyone else for asking and answering questions. I know I’m still new and this project is simply a portfolio piece/learning experience, but I feel on top of the world :slight_smile: Good luck, everyone!

Here’s my project: https://github.com/andrew-fleming/project-coinflip-v-6

And here’s a short video on LBRY of the dApp in action: https://lbry.tv/@BreakLawsNotHearts:5/CoinflipDemo:3

2 Likes

Can someone check my code below? I have a function for inserting structs into mapping, but it doesn’t save the data.

function insertPlayer(bytes32 _queryId, uint _betBalance) private {
    Player memory newPlayer;
    newPlayer.betPlayerBalance = _betBalance;
    newPlayer.isWating = true;
    players_byID[_queryId] = newPlayer;
    emit PlayerInserted(_queryId, players_byID[_queryId].betPlayerBalance, players_byID[_queryId].isWating);
  }

After some issues in code, network ropsten problems and even ganache bugs, i manage to do it. Thanks to everyone to share ideas and solutions!

https://github.com/i0709/Dapp-Flip-Coin_Ropsten

2 Likes

Hello, this exercise has brought up a few questions about seed phrases that I’m hoping someone can help answer.

Please correct me if I’m wrong in this. I understand that a metamask wallet uses one seed phrase to generate new addresses (each with a unique private key). So anyone’s metamask wallet might have multiple addresses each with a unique private key but will only have one seed.

My main question is, why does truffle need this seed as a mnemonic? And why does the mnemonic have to be the seed from my metamask account?

My guess is that it uses one of the addresses generated by the mnemonic in order to pay gas fees, set the contract owner, and fund the contract upon deployment. Is that right?

If this is true, why can’t I provide a private key instead of the seed phrase? It seems safer to me to be messing around with private keys than seed phrases because if I lose a seed phrase, all of my metamask accounts are compromised rather than just one if i lose a private key (is that right?).

Further, since we’re providing the seed and not a private key, how do we know which account is getting set as the contract owner? What if my metamask account has multiple addresses with ETH on the ropsten network? Does it just pick one randomly to deploy the contract?

If I’m wrong about what truffle is doing with the mnemonic, can I just make up a new seed phrase rather than using my metamask phrase?

I’m also wondering about the infuraKey. I see it is being saved as a constant in the truffle-config.js file for some reason but doesn’t appear to get used anywhere else in the config file. What is the purpose of it and is it okay to leave to leave it out of the config file?

Hey @andrewfleming

Thanks for posting the video and congrats for completing your first dapp :slight_smile:
Keep going now, you have endless possibilities to explore :muscle:

Happy coding,
Dani

1 Like

Hey @MrGanD

Thanks for the feedback really appreciate it.
I will implement it soon.

Edit: Implemented!
https://academy.ivanontech.com/products/ethereum-smart-contract-programming-201/categories/2004134/posts/6718484
Schermata 2020-10-22 alle 12.50.46

Happy learning,
Dani

1 Like

Hey @rostyslavdzhohola

Your function looks right to me, what happens when you try to add a player? Also does the function need to be private?

function insertPlayer(bytes32 _queryId, uint _betBalance) private {
    Player memory newPlayer;
    newPlayer.betPlayerBalance = _betBalance;
    newPlayer.isWating = true;
    players_byID[_queryId] = newPlayer;
    emit PlayerInserted(_queryId, players_byID[_queryId].betPlayerBalance, players_byID[_queryId].isWating);
  }

Another way to add data in your struct would be:

function insertPlayer(bytes32 _queryId, uint _betBalance) public {
    players_byID[_queryId].betPlayerBalance = _betBalance;
    players_byID[_queryId]. isWating = true;

    emit PlayerInserted(_queryId, players_byID[_queryId].betPlayerBalance, players_byID[_queryId].isWating);
  }
3 Likes

Hey @rostyslavdzhohola
This looks like it should work. Can you post a link to your GitHub repo or the rest of your contract?

Thank you so much, @dan-i!

1 Like

https://github.com/RostyslavDzhohola/Coinflip-test-Project

Hey @rostyslavdzhohola. The structs and mapping are working; however, the reason you’re not seeing the payout when the user wins is in the coinflipGet(). After receiving the callback from provable, your callback calls the coinflipGet(). If the user wins, it’s sending the funds to the provable address(msg.sender) that sent the callback:

function coinflipGet(bytes32 _queryId, uint256 _randomNumber) private {
uint betBalance = player_id[_queryId].betPlayerBalance;
    uint toTransafer = 0;
    uint luck = _randomNumber;

    if(luck == 1){
      win_loose = true;
      toTransafer = betBalance *2;
      balance -= betBalance;
      msg.sender.transfer(toTransafer);
      //here^

The way I handled this was to map the msg.sender address to the struct and then created another mapping from queryId to the address (still mapped to the struct). Perhaps, you could begin setting these mappings in the coinflipSet(). There’s a ton of ways to handle this, though. Test your code on remix and look through the internal tx’s on etherscan from the callback. Let me know when you get this down :slight_smile:

1 Like