Programming Project - Phase 2

yeah lol, thanks again!

2 Likes

I’ve manage to get the Dapp working on Ropsten :smiley:
There are still some things I’m not happy with:

  1. UI could some improvement
  2. Event listeners should be added
  3. I’m not able to track the contract balance correctly due to Oracle cost. Hence “Pot” balance is always off contract actual “balance” by small amount.

I have some ideas on how to work on 1 and 2 but issue 3 I still don’t know how I can manage it. Would appreciate some advice.

Here is my code: https://github.com/Bigbrotha12/solidityLearn

Ok so I need a bit help. I can get my random number when it returns on the __callback function and then call another function to test it if its heads or tails and send back ETH. But now I have run into logic problem. If I call update with the js side i have to confirm a transaction with metamask and then i have to confirm another transaction for the second function that checks the results. I could create a function in my coinflip.sol that would call update() from the Provable.sol but I am unable to wait for the response. So my question is how do you do this all in one transaction? It almost seems impossible, like there has to be two transactions. Any hints?

@mikekai
Apologies for late reply, can you send me your github code link, because to give you full solution i need to a look at the code :slight_smile:

1 Like

@Rafael21
Amazing work!.
You did take care of every details

:white_check_mark: usage of private, internal, external, ownership
:white_check_mark: Provable api is well used and you are checking the api price :+1:

Well done :partying_face: really great project

you are not really respecting Check Effects Interactions pattern in your payout function.

Also can you explain me about removePot()?
Because you have mentioned in comments “Admin is not allowed to withdraw balance claimable by players.” but also declared modifier onlyOwner.

2 Likes

Thanks a lot Taha :smiley:

image

Regarding removePot(), the idea is that the admin should be allowed to withdraw the profits from the dapp but he/she should not be allowed to withdraw money that players have put in as bets or “won”. Hence the contract tracks how much ether has been put into the contract as well as how much players have “won” in the “committedPot” variable which the admin should not have access to since it is rightfully claimable by the players. So the admin will only be able to withdraw “Pot” minus “committedPot”.

I need to look into the “Check Effect Interaction” issue. Where did you see the clearest example where it wasn’t followed? I’ll fix and resubmit.

installing Github would solve the problem!:yum::yum:

@Rafael21

function payOut(uint amount) public {
      require(amount <= playerBalance[msg.sender]);
      require(!awaitingQuery[msg.sender]);

      playerBalance[msg.sender] -= amount;
      pot -= amount;
      committedPot -= amount;
      msg.sender.transfer(amount);
    }

in this function you can first initialise playerBalance[msg.sender] = 0

For check Effect Interaction pattern

You can also look forward to add SafeMath and proxy library.
Safemath is super important to protect your contract from overflow and underflow.
Proxy will help you upgrade smart contract.

1 Like

@leemac
Apologies, for late reply.

I was able to review your smart contract

  1. Nice usage of private, internal, external, ownership
  2. Great use of events in the frontend
  3. I like how to made separate contract for random number and coin flip dapp

The smart contract is very comprehensively written.

Point to remember

  1. You could add the SafeMath library and a proxy in the future
  2. Also don’t forget to call the provable_getPrice(“RANDOM”) function to update the balance of your smart contract after each call. Otherwise you will have an issue at some point.

anyway this is just details it’s a really good project overall so well done :+1: leemac

2 Likes

I think my smart contract is working, but the event listener in the test.js file is not working. I’m stuck here with the event listener, and can’t figure out how to triger my front end function as soon as the specific event is emitted! Looking forward to any helpful suggestions!
here is the github link !

please download the Ethler101.rar file, It has everything within.

Hey @loksaha1310

The following code works, have a look and let me know if you have any question.

function gamble(e){
  e.preventDefault();
  let bet = parseFloat($("#bet").val());
  let unit = parseInt($("#unit").val());
  if(unit==0)unit = 10**18; //10^18
  bet*= unit;
  if(!isNaN(bet)){
    if(bet>2000000000000000000 ) alert("you can't gamble more than 2 ether");
    else if(bet<100000000000000) alert("you have to put at least 0.0001 ether");
    else {
      let input = parseInt($("#Input").val());
      config = {
        value: bet,
        gas: 6000000
      };
      contractInstance.methods.Play(input).send(config).then(function(){
          contractInstance.events.statusOfCalledBackPlayer(
            (error, data)=>{
            console.log(data);
            var win = data.returnValues.status;
            getFront(win);
          })
        })
      };
    }
  }

You can look for past events but you need to make sure that the event you are looking for has been emitted.
In your case ‘statusOfCalledBackPlayer’ is fired within the function __callback() which is called some blocks after.

To better explain what I mean with the sentences above, you can try the following code (it’s a tx made by me). Check the console to see the result.

function gamble(e){
  e.preventDefault();
  let bet = parseFloat($("#bet").val());
  let unit = parseInt($("#unit").val());
  if(unit==0)unit = 1000000000000000000; //10^18
  bet*= unit;
  if(!isNaN(bet)){
    if(bet>2000000000000000000 ) alert("you can't gamble more than 2 ether");
    else if(bet<100000000000000) alert("you have to put at least 0.0001 ether");
    else {
      let input = parseInt($("#Input").val());
      config = {
        value: bet,
        gas: 6000000
      };
      contractInstance.methods.Play(input).send(config).then(async function(){
        contractInstance.getPastEvents("statusOfCalledBackPlayer",
              {fromBlock: 8529116,
              toBlock: 8529117},
              async function (error, events){
              console.log(events);
              var win = events.returnValues.status;
              getFront(win);
            })
          })
        };
      }
    }
2 Likes

Yes, from your transaction, I got a result at last.

Okay!!! Thanks, man! It worked! changing from

contractInstance.getPastEvents()

to

contractInstance.events.MyEventname()

Actually, that was the first thing I tried, when I tried to understand the concept of event listeners, and I tried the same in Ganache, but I didn’t receive anything like getting the event in console. So, why do you think that could have happened?

Another thing!
When I’m using contractInstance.events.MyEventName() the function is listening to the latest block, right? suppose the user transaction is complete at blockNumber 65000, and when the __callback() arrives, the blockchain is at 65005. So, the event listener will check 65005th block, is it so?

1 Like

Hey @loksaha1310

Happy to read that it worked :slight_smile:

Actually, that was the first thing I tried, when I tried to understand the concept of event listeners, and I tried the same in Ganache, but I didn’t receive anything like getting the event in console. So, why do you think that could have happened?

I cannot tell without looking at the code you were testing.

When I’m using contractInstance.events.MyEventName() the function is listening to the latest block, right? suppose the user transaction is complete at blockNumber 65000, and when the __callback() arrives, the blockchain is at 65005. So, the event listener will check 65005th block, is it so?

It is correct, you do indeed subscribe for the event statusOfCalledBackPlayer.
I want to refer you to this documentation where events are fully explained> https://web3js.readthedocs.io/en/v1.2.0/web3-eth-contract.html#events

Happy coding,
Dani

3 Likes

Here is the whole project. link
Can you please check it once, and give me some feedback on improvements? I could implement almost everything I planned to.

Hey @loksaha1310

Think about these points. If you need help I am here :slight_smile:

Provable API Documentation

1 - The function play () requires a parameter uint Input. At the moment I am able to give whatever number I want. If I give for example 99 as Input, should I be able to play?
All the checks must be done in your smart contract, I know that your front end allows me to only bet on head or tail but your contract is accessible by everyone even without using your front end.

2 - In order to call the oracle, your contract needs to have enough balance.
The 1st call is free but after that one you must pay a fee to get a random number.
Your contract does not have any function to deposit ether into it.

3 - A user is able to call play () and send 0 ether (msg.value = 0).

Now combine points 2 and 3.

What happens if you deploy your contract and you call function play () twice sending 0 ether? Please try and you will see an error message.

4 - This is an inaccuracy and not an error: function withdrawAll()public Owned returns(uint toTransfer) does not return anything although you specified that it should.
In my opinion there is not need to return uint toTransfer so I would remove it.

5 - This is an inaccuracy and not an error: toTransfer = contractBalance; in function withdrawAll()public Owned returns(uint toTransfer) is not useful. Because you will withdraw all the ether in your contract I would just transfer address(this).balance.

6 - This is a suggestion: consider function __callback(bytes32 _queryId, string memory _result, bytes memory _proof) the parameter bytes memory _proof.
As per provable documentation you can use that parameter by proceeding as follow:

  • In your constructor add provable_setProof(proofType_Ledger);

  • In your function __callback() add

if (
      provable_randomDS_proofVerify__returnCode(
                _queryId,
                _result,
                _proof
            ) != 0
        ) {
        } else { your code ...}

Happy coding,
Dani

2 Likes

Hi

Thank you a lot, for the feedback. I have tried to update the code. You may have a look here! Thanks again man!:sunglasses::sunglasses:

This is the error I got, while implementing this code, here. I implemented the same code without the constructor,and it worked fine.Any idea what may have happened?

I think I got phase 2 here https://github.com/thenikso/b-bet

b-bet

I went off road and implement my own (very naive) oracle in node! This is how it works:

  1. The Oracle contract accepts requests for random numbers emitting an event
  2. A node program listen for those events on the blockchain, generates a random number and call an owner only method on the same Oracle contact to report the number
  3. The response is sent to the original contract via an external call

I started thinking how gas could be measured and returned to the original sender if not fully used… but that’s too much for today xD

Please check out these files if you feel like reviewing:

  • /contracts/Oracle.sol
  • /contracts/usingOracle.sol
  • /contracts/Bet.sol
  • (optional) /oracle.js

Thanks!!

The deployment fails because of the modifier costs.
What you are doing in your migration is sending ether to your constructor, not to the function Play().

I will give you some suggestions and let you think about it a bit.
As we said, the 1st call to the oracle does not require any fee.
Because you are calling Play() in the constructor that is going to be the 1st call to the oracle (not sure why you are calling Play() in the constructor :P)

I would remove the modifier costs from the function Play().
I would check if the amount (msg.value) sent to the function Play() is enough to pay the oracle fee.
provable_getPrice("random") returns a uint256 that tells you the fee required by the oracle.

Also think if you want your contract to pay the fee, or if you want to subtract the fee from the user bet :slight_smile:

Always here if you need.

Happy coding,
Dani

2 Likes

use npm install @truffle/hdwallet-provider instead of the given command

3 Likes