Hello,
I can’t find the Oracle code. Can you provide the code please.
Thank You
Hey @KlodyCodez
You can find the link below Filip’s video
https://academy.ivanontech.com/products/old-ethereum-smart-contract-programming-201/categories/2004134/posts/6702343
Cheers,
Dani
Hey @Su.kal.Crypto
We noticed that Ropsten oracle does not seem to respond at the moment.
Nothing we can do unfortunately, might be worth to check if the Rinkeby one works.
Cheers,
Dani
Hi @dan-i
What are rinkeby truffle-config configurations ?
can you send a File ?/.
thanks
su.kal Crypto
Thanks, appreciate it
Claude
Hi @dan-i
It seems the Oracle service on rinkeby is also not working as its been 30 minutes but no sign of the eventFlipResult
Any Other way you suggest ? Because i Really want to get to the next Course now, However want to be sure that my Code is 100% correct
Thanks and Regards
Su.Kal Crypto
Hey @dan-i,
I’ve started trying to re-do my code to work with multiple players, and trying to do so with Filip’s “fake provable” function he does with testRandom() in the video.
In his code:
function testRandom() public returns (bytes32) {
bytes32 queryId = bytes32(keccak256(abi.encodePacked(msg.sender)));
__callback(queryId, "1", bytes("test"));
return queryId;
}
function __callback(bytes32 _queryId, string memory _result, bytes memory _proof) {
uint256 randomNumber = uint256(keccak256(abi.encodePacked(_result))) % 2;
latestNumber = randomNumber;
emit generatedRandomNumber(randomNumber);
}
When calling the __callback() function, why do we pass bytes(“test”) as an argument? Also why is “1” passed as the _result string? Is the _result string the actual random number in string form when using provable?
For the sake of testing at this point so I can restructure my code into using this fake_provable() function for now, I’m using a randomString() function in order to simulate the __callback() function for now, just so I can test getting a “random” number while simulating __callback(). Is this accomplishing the same test random function that Filip is doing?
function fake_provable() public returns (bytes32) {
bytes32 queryId = bytes32(keccak256(abi.encodePacked(msg.sender))); //get fake test queryId using keccak256 on msg.sender address
__callback(queryId, randomString(), bytes("test")); //simulate __callback, in reality this occurs after a wait
return queryId;
}
function __callback(bytes32 _queryId, string memory _result, bytes memory _proof) internal {
uint256 randomNumber = uint256(keccak256(abi.encodePacked(_result))) % 2;
latestNumber = randomNumber;
emit generatedRandomNumber(randomNumber);
}
function randomString() public view returns (string memory) {
if(now % 2 == 0) {
return "0";
} else {
return "1";
}
}
For now, I’m simply trying to get latestNumber as a 0 or a 1. Thanks for the help!
Hey @mervxxgotti
When calling the __callback() function, why do we pass bytes(“test”) as an argument? Also why is “1” passed as the _result string? Is the _result string the actual random number in string form when using provable?
The callback function requires 3 arguments bytes32 _queryId, string memory _result, bytes memory _proof
therefore you still have to pass these 3 parameters if you want to simulate its functionality.
For now, I’m simply trying to get latestNumber as a 0 or a 1. Thanks for the help!
You can do that it’s ok, the oracle however will send you a large number that you than have to convert to a 0 or 1.
Cheers,
Dani
hey @dan-i,
I have my new version of the betting contract working in remix using a fake_provable() and fake __callback() function. I would like to test this first using the real provable API and the testnet through remix but looking at the comments above there is some issue with the oracles on the testnets?
Can you let me know how I can proceed with generating a random number in my contract in remix through a testnet as well as converting this to a 1 or 0 once I receive it? I have my code below.
Thanks for the help!
pragma solidity 0.5.12;
contract Betting {
uint256 constant NUM_RANDOM_BYTES_REQUESTED = 1;
uint256 public latestNumber;
uint private contractBalance;
struct player {
address playerAddress;
uint balance;
uint bet;
bool isPlaying;
}
//struct for oracle queries
struct query {
bytes32 id;
address playerAddress;
}
mapping(address => player) public players;
mapping(bytes32 => query) public queries;
event LogNewProvableQuery(string description);
event LogBetPlaced(address playerAddress, uint bet, bytes32 query_id);
event LogGeneratedRandomNumber(uint256 randomNumber, string description);
event LogBetFinished(address playerAddress, uint bet, bytes32 query_id, bool winFlag);
event LogPlayersBalanceUpdate(address playerAddress, uint balance);
event LogContractBalanceUpdate(uint balance);
modifier costs(uint cost){
require(msg.value >= cost, "Minimum bet or deposit is 1 ether!");
_;
}
modifier deploymentCosts(uint cost){
require(msg.value >= cost, "Contract needs 10 ether to initialize contract.");
_;
}
modifier ready() {
require(contractBalance > 0, "Cannot play. Contract balance is empty.");
require(players[msg.sender].isPlaying == false, "Cannot play. This player address is already playing.");
_;
}
modifier canWithdraw() {
require(msg.sender != address(0));
require(players[msg.sender].balance > 0, "This address has no funds to withdraw.");
require(!players[msg.sender].isPlaying, "Cannot withdraw while playing.");
_;
}
//constructor takes initial 5 ether from default player
constructor() public payable deploymentCosts(10 ether) {
contractBalance += msg.value;
players[msg.sender].playerAddress = msg.sender;
players[msg.sender].bet = 0;
players[msg.sender].isPlaying = false;
}
function placeBet() public payable costs(1 ether) ready {
//save new player in players mapping
players[msg.sender].playerAddress = msg.sender;
players[msg.sender].bet = msg.value;
players[msg.sender].isPlaying = true;
/* FOR USE LATER
uint QUERY_EXECUTION_DELAY = 0;
uint GAS_FOR_CALLBACK = 200000;
bytes32 query_id = provable_newRandomDSQuery(QUERY_EXECUTION_DELAY, NUM_RANDOM_BYTES_REQUESTED, GAS_FOR_CALLBACK);
emit LogNewProvableQuery("Provable query sent. Waiting for answer...");
*/
bytes32 query_id = fake_provable();
queries[query_id].id = query_id;
queries[query_id].playerAddress = msg.sender;
__callback(query_id, randomString(), bytes("test")); //simulate __callback, in reality this occurs after a wait
emit LogBetPlaced(msg.sender, msg.value, query_id);
}
function fake_provable() public returns (bytes32) {
bytes32 query_id = bytes32(keccak256(abi.encodePacked(msg.sender))); //get fake test queryId using keccak256 on msg.sender address
//__callback(query_id, randomString(), bytes("test")); //simulate __callback, in reality this occurs after a wait
return query_id;
}
function __callback(bytes32 _queryId, string memory _result, bytes memory _proof) internal {
//require(msg.sender == provable_cbAddress());
uint256 randomNumber = uint256(keccak256(abi.encodePacked(_result))) % 2;
latestNumber = randomNumber;
checkBet(_queryId, latestNumber);
emit LogGeneratedRandomNumber(randomNumber, "Callback recieved and new random number generated.");
}
function checkBet(bytes32 _queryId, uint latestNumber) internal {
address currentPlayerAddress = queries[_queryId].playerAddress;
if(latestNumber == 1) {
players[currentPlayerAddress].balance += players[currentPlayerAddress].bet * 2;
contractBalance -= players[currentPlayerAddress].bet * 2;
emit LogBetFinished(currentPlayerAddress, players[currentPlayerAddress].bet, _queryId, true);
} else {
contractBalance += players[currentPlayerAddress].bet;
emit LogBetFinished(currentPlayerAddress, players[currentPlayerAddress].bet, _queryId, false);
}
emit LogPlayersBalanceUpdate(currentPlayerAddress, getPlayerBalance(currentPlayerAddress));
emit LogContractBalanceUpdate(getContractBalance());
players[currentPlayerAddress].bet = 0;
players[currentPlayerAddress].isPlaying = false;
delete(queries[_queryId]);
}
function withdraw() public canWithdraw {
uint amount = players[msg.sender].balance;
delete(players[msg.sender]);
msg.sender.transfer(amount);
emit LogPlayersBalanceUpdate(msg.sender, getPlayerBalance(msg.sender));
emit LogContractBalanceUpdate(getContractBalance());
}
function deposit() public payable costs(1 ether){
contractBalance += msg.value;
emit LogContractBalanceUpdate(getContractBalance());
}
function getThisPlayer() public view returns (address playerAddress, uint balance, uint bet, bool isPlaying) {
return (players[msg.sender].playerAddress,
players[msg.sender].balance,
players[msg.sender].bet,
players[msg.sender].isPlaying);
}
function getPlayer(address _address) public view returns (address playerAddress, uint balance, uint bet, bool isPlaying) {
require(_address != address(0x0), "Player with this address does not exist.");
return (players[_address].playerAddress,
players[_address].balance,
players[_address].bet,
players[_address].isPlaying);
}
function getThisPlayerBalance() public view returns (uint) {
return players[msg.sender].balance;
}
function getPlayerBalance(address _address) public view returns (uint) {
return players[_address].balance;
}
function getContractBalance() public view returns (uint){
return contractBalance;
}
function getContractAddress() public view returns (address) {
return address(this);
}
function getSenderAddress() public view returns (address) {
return msg.sender;
}
function randomString() public view returns (string memory) {
if(now % 2 == 0) {
return "0";
} else {
return "1";
}
}
Hi @mervxxgotti
I wrote a guide to use chainlink in order to get a random number: Generate a random number using Chainlink
When you struggle I always suggest you to google your question because you will most likely find your answer. It is extremely important to be able to find an answer by looking at other people questions.
as well as converting this to a 1 or 0 once I receive it?
The operator %
(reminder) operator can be used to “convert” a big number to a 0 or 1.
An example in Javascript that you can run:
const x = 10;
const y = 25;
console.log(x % 2)
console.log(y % 2)
Happy coding,
Dani
Hey @dan-i,
I’ve redone my contract to support multiple players waiting on requests from the chainlink oracle for a random number using the guide you wrote.
Before integrating the new contract with my dapp, I’m still having an issue with events in the contract. Using the code from the guide, I’ve adjusted it for testing purposes and added events.
In remix, I can check the logs from emitted events when the request is sent from the updateRandomNumber() function and I see it in the remix console, but I do receive anything upon the fulfillRandomness() callback function getting called. I know it’s getting called because I receive a new randomResult and the waiting bool flag is changed. But nothing shows up in the console for me to read the logs of the emitted event from the callback function.
How can I see the emitted event from the callback function? I’ve google but haven’t found a solution. I’ve included my test code below.
Thanks Dani!
pragma solidity 0.6.6;
import "https://raw.githubusercontent.com/smartcontractkit/chainlink/master/evm-contracts/src/v0.6/VRFConsumerBase.sol";
contract RandomNumberConsumer is VRFConsumerBase {
bytes32 internal keyHash;
uint256 internal fee;
uint256 public randomResult;
uint256 public randomResult1or0;
bytes32 public requestId;
bool public waiting;
bool public winFlag;
event RandomRequested(bytes32 requestId, bool waiting);
event RandomRequestFulfilled(bytes32 requestId, bool waiting, uint256 randomResult, bool winFlag);
/**
* Constructor inherits VRFConsumerBase
*
* Network: Kovan
* Chainlink VRF Coordinator address: 0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9
* LINK token address: 0xa36085F69e2889c224210F603D836748e7dC0088
* Key Hash: 0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4
*/
constructor()
VRFConsumerBase(
0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9, // VRF Coordinator
0xa36085F69e2889c224210F603D836748e7dC0088 // LINK Token
) public
{
keyHash = 0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4;
fee = 0.1 * 10 ** 18; // 0.1 LINK
waiting = false;
}
/**
* Requests randomness from a user-provided seed
************************************************************************************
* STOP! *
* THIS FUNCTION WILL FAIL IF THIS CONTRACT DOES NOT OWN LINK *
* ---------------------------------------------------------- *
* Learn how to obtain testnet LINK and fund this contract: *
* ------- https://docs.chain.link/docs/acquire-link -------- *
* ---- https://docs.chain.link/docs/fund-your-contract ----- *
* *
************************************************************************************/
function updateRandomNumber() public {
requestId = getRandomNumber(0);
waiting = true;
emit RandomRequested(requestId, waiting);
}
function getRandomNumber(uint256 userProvidedSeed) public returns (bytes32 requestId) {
require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet");
return requestRandomness(keyHash, fee, userProvidedSeed);
}
/**
* Callback function used by VRF Coordinator
*/
function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
randomResult = randomness;
randomResult1or0 = randomResult % 2;
if(randomResult1or0 == 1) {
winFlag = true;
} else {
winFlag = false;
}
waiting = false;
emit RandomRequestFulfilled(requestId, waiting, randomResult, winFlag);
}
/**
* Withdraw LINK from this contract
*
* DO NOT USE THIS IN PRODUCTION AS IT CAN BE CALLED BY ANY ADDRESS.
* THIS IS PURELY FOR EXAMPLE PURPOSES.
*/
function withdrawLink() external {
require(LINK.transfer(msg.sender, LINK.balanceOf(address(this))), "Unable to transfer");
}
}
I’m confused as to why when running on the Javascript VM in remix, whenever I use a function in the contract deployment I will see a green checkmark in the console where I can check the logs but this does not always happen when using injected web3 so even when I see a metamask transaction succeeded notification there will be no green check in the console for me to check the logs for emitted events. Is there a setting for this? An explanation would really help!
I finally finished the coinflipp dapp: https://github.com/rube-de/coinflippDapp
not really pretty, but I learned a lot with events and other solidity specialties
.
You can see the event by checking the blockchain (etherscan kovan).
https://kovan.etherscan.io/address/0x99e22632FAF3AfA94342137823d68A3aC9c6629E#events
I’m confused as to why when running on the Javascript VM in remix, whenever I use a function in the contract deployment I will see a green checkmark in the console where I can check the logs but this does not always happen when using injected web3 so even when I see a metamask transaction succeeded notification there will be no green check in the console for me to check the logs for emitted events. Is there a setting for this? An explanation would really help!
Not sure what you mean here.
Having a difficult time getting my balance to update. I have tried reworking my functions so that I removed an extra step of funding the account but it still won’t add to the balance and then update it based on winning or losing. Could you take a look at my GitHub file link below and give me some help with where I am coding it wrong. Thanks
Hey @cge5009
I would listen for events emitted by your contract, once you get gambleWon
or gambleLost
you know it’s time to update the balance
FAQ - How to listen for events
Cheers,
Dani
I have an event listener in and it works. I updated it with my check balance contract instance call but I still don’t get an update. When I try to withdraw balance, the winnings are always zero balance. I am wondering if there is an error with my _payout function but I can’t quite figure out where it would be happing. I know a payable address is required to transfer value but I can’t figure out how to add that into the _payout function or if its needed. Any guidance?
Can you push your updates on github and let me know?