yeah lol, thanks again!
Iâve manage to get the Dapp working on Ropsten
There are still some things Iâm not happy with:
- UI could some improvement
- Event listeners should be added
- 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
@Rafael21
Amazing work!.
You did take care of every details
usage of private, internal, external, ownership
Provable api is well used and you are checking the api price
Well done 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
.
Thanks a lot Taha
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!
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.
@leemac
Apologies, for late reply.
I was able to review your smart contract
- Nice usage of private, internal, external, ownership
- Great use of events in the frontend
- I like how to made separate contract for random number and coin flip dapp
The smart contract is very comprehensively written.
Point to remember
- You could add the SafeMath library and a proxy in the future
- 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 leemac
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);
})
})
};
}
}
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?
Hey @loksaha1310
Happy to read that it worked
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
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
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
Hi
Thank you a lot, for the feedback. I have tried to update the code. You may have a look here! Thanks again man!
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
I went off road and implement my own (very naive) oracle in node! This is how it works:
- The
Oracle
contract accepts requests for random numbers emitting an event - 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 - 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
Always here if you need.
Happy coding,
Dani
use npm install @truffle/hdwallet-provider instead of the given command