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
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!
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
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
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
Answered yesterday to your dm
hello,
thanks 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
thanks
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
Hey, I finally got all the obvious bugs ironed out from my phase 2 implementation, so here it is in all its glory:
Github: https://github.com/Roushie/Coinflip.dApp
Demo: https://youtu.be/Vof2B78b5f0
I’m sure there will be bugs to fix in my code before I’m really done with Eth201, but I just want to say thanks to the IoT team for this course - I really like the independent / project-based style of learning and I’m already gaining some confidence that I’ll actually be able to implement things that have real-world value and hopefully find a job in the blockchain space. In particular, I’m grateful to @filip as the head instructor and @dan-i for helping out with my noob mistakes.
Hey @Nara
I watched your youtube video and I really like it.
I took a look at your code and I have not found critical bugs.
However I have some questions for you:
This could be an issue if lots of users use your dapp if (address(this).balance < (msg.value * 2))
Example:
contract balance: 2.1 ether;
user A: bets 1 ether; -> valid bet.
contract balance: 3.1 -> the contract calls the oracle and waits for the answer.
user B: bets 1.5 ether -> valid bet.
contract balance: 4.5 ether;
user A wins -> 4.5 ether - 2 ether = 2.5 eth left in the contract.
user B wins -> 2.5 ether - 3 = invalid.
function withdraw(uint amount) public onlyOwner{ //Withdraws specified amount in wei
msg.sender.transfer(amount);
}
Technically this function is not wrong, it will allow the transfer if the contract balance is >= amount, will fail otherwise. I would at least require than amount =< address(this).balance
and add a nice error message otherwise.
Also do you need this variable bytes public resulttest;
?
Well done here, whenever you feel ready I suggest you to take the smart contract security course.
That is one of my favourite and you will learn an insane amount of stuff.
If you need help we are here.
Happy learning,
Dani
Hey @dan-i , thanks a lot for your feedback!
I think you were being too kind when you said that you found no critical bugs, since using address(this).balance to determine bet validity in an asynchronous environment with long oracle wait times seems pretty critical to me. The fix was pretty straightforward though - just keeping track of available balance in a separate variable and freeing up that balance (if the user loses the bet) when we get a callback from the oracle seems to do the trick. Lesson learned!
You are also right that bytes public resulttest;
was a useless variable - pretty sure I used it at an earlier point in development and forgot to delete it.
Regarding your recommendation to take the smart contract security course - it is high on my list! I think I will take React development first and follow that up with the security course. The security course definitely looks fun, so I’m looking forward to it!
Thanks again for all of your hard work!
@Nara Pleasure to help you
Have fun with the academy and keep learning! If you need help we are here.
I finally finished phase 2 of the project. Kind of because there are two problems I cant solve.
Here is video how app works.
https://www.dropbox.com/s/cc5xjqufea9bn2o/2020-12-14%2023-07-32.mov?dl=0
Here is code
https://github.com/dominno/coinflip
Problems I cant solve
- Sometimes there is no callback from provable, and this breaks the app
Here you can see that last event was betStarted, but there was never a betFinished event so this means that provable didnt made a callback. How to predict that ?
https://ropsten.etherscan.io/address/0x56a726966ABFdC9e8B0D34F3aAc48A56a49d7C31#events
- I can’t find why when contract balance is bellow 1 ether then on every try to bet I get error from contract. When I deposit more ether to contract then it start working again.
It would be great if someone could review my code.
thanks,
I was able to migrate the contract in the ropsten network.
when I try to interact with the contract I get this error from metamask:
is it a metamask issue? (i tried to reset the account as you told me but it gives the same error)
in the account I have 0,5 eth and setting 1 on the stake should mean 1000000 gwei
- Sometimes there is no callback from provable, and this breaks the app
Here you can see that last event was betStarted, but there was never a betFinished event so this means that provable didnt made a callback. How to predict that ?
Because you are using Ropsten (a testnet) sometimes it just does not work as expected.
You should not have the same issue in mainnet (if you do then you have to contact the team of provable api).
I can’t find why when contract balance is bellow 1 ether then on every try to bet I get error from contract. When I deposit more ether to contract then it start working again.
That probably is because you have a require statement in your contract. Give it a look