hey @dan-i,
Thanks for all your help. So I’ve redone my contract to use provable to generate the random number and it’s working great on remix using the ropsten testnet.
Then I followed along with with Filip’s video to try migrating the project with truffle. I remember running into this issue before as you said,
You have to use const HDWalletProvider = require('@truffle/hdwallet-provider');
as truffle-hdwallet-provider
is deprecated.
but when I use @truffle/hdwallet-provider, I get this error:
When when I use truffle-hdwallet-provider, it begins compiling. Why is this?
Next, I continue to follow the videos to import the provableAPI.sol file, and it seems like everything is compiling fine, I get this error:
It says I have insufficient funds but the balance stated there is ~4.7 ETH, which is the amount in the account in my Metamask on the ropsten network. This ran fine in remix and there was no insufficient funds when running on there. Does this have something to do with the hdwallet-provider?
Here’s my contract and config file:
pragma solidity >= 0.5.0 < 0.6.0;
//import "github.com/provable-things/ethereum-api/provableAPI_0.5.sol";
import "./provableAPI_0.5.sol";
contract Betting is usingProvable {
uint public contractBalance;
//for generating random number using provable
uint256 constant NUM_RANDOM_BYTES_REQUESTED = 1;
uint256 public latestNumber;
struct player {
address playerAddress;
uint balance;
uint bet;
bool waiting; //true if player waiting for oracle request
bool win; //true if last bet won
bytes32 queryId;
}
struct query {
bytes32 id;
address playerAddress;
uint256 random;
}
mapping(address => player) private players;
mapping(bytes32 => query) private queries;
event LogGeneratedRandomNumber(bytes32 requestId, uint256 randomNumber);
event LogGameState(address playerAddress, uint playerBalance, bytes32 requestId, uint256 random, uint contractBalance);
event LogPlay(address playerAddress, uint bet, bytes32 requestId);
event LogLinkBalance(uint256 linkBalance);
/*
* MODIFIERS
************************************************************************************************
*/
modifier initCosts(uint initCost){
require(msg.value >= initCost, "Contract needs minimum ether to initialize contract balance.");
_;
}
modifier costs(uint cost){
require(msg.value >= cost, "Minimum bet or deposit is 0.01 ether!");
_;
}
modifier ready() {
require(contractBalance > 0, "Cannot play. Contract balance is empty.");
require(players[msg.sender].waiting == false, "Cannot play. This player address is already playing and waiting on request.");
_;
}
modifier withdrawable() {
require(msg.sender != address(0));
require(players[msg.sender].balance > 0, "This address has no funds to withdraw.");
require(!players[msg.sender].waiting, "Cannot withdraw while waiting for oracle request.");
_;
}
/***********************************************************************************************/
//constructor takes initial 0.05 ether (50 finney) from default player
constructor() public payable initCosts(0.05 ether) {
contractBalance += msg.value;
players[msg.sender].playerAddress = msg.sender;
players[msg.sender].balance = 0;
players[msg.sender].bet = 0;
players[msg.sender].waiting = false;
players[msg.sender].win = false;
players[msg.sender].queryId = 0;
emit LogGameState(players[msg.sender].playerAddress, players[msg.sender].balance, 0, 0, contractBalance);
}
function play() public payable costs(0.01 ether) ready {
players[msg.sender].playerAddress = msg.sender;
players[msg.sender].bet = msg.value;
players[msg.sender].waiting = true;
bytes32 newQueryId = getRandomNumber();
players[msg.sender].queryId = newQueryId;
queries[newQueryId].id = newQueryId;
queries[newQueryId].playerAddress = msg.sender;
emit LogPlay(players[msg.sender].playerAddress, players[msg.sender].bet, newQueryId);
}
function getRandomNumber() payable public returns (bytes32 queryId) {
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);
return query_id;
}
function __callback(bytes32 _queryId, string memory _result, bytes memory _proof) public {
uint256 randomNumber = uint256(keccak256(abi.encodePacked(_result)));
latestNumber = randomNumber;
updateGame(_queryId);
}
function updateGame(bytes32 _queryId) internal {
address playerAddress = queries[_queryId].playerAddress;
queries[_queryId].random = latestNumber;
if(latestNumber % 2 == 1) {
players[playerAddress].win = true;
} else {
players[playerAddress].win = false;
}
updateBalances(playerAddress, _queryId);
players[playerAddress].bet = 0;
players[playerAddress].waiting = false;
//delete(requests[requestId]);
}
function updateBalances(address playerAddress, bytes32 _queryId) internal {
if(players[playerAddress].win) {
players[playerAddress].balance += players[playerAddress].bet * 2;
contractBalance -= players[playerAddress].bet * 2;
} else {
contractBalance += players[playerAddress].bet;
}
emit LogGameState(
playerAddress,
players[playerAddress].balance,
_queryId,
queries[_queryId].random,
contractBalance
);
}
function withdrawPlayerBalance() public withdrawable {
uint amount = players[msg.sender].balance;
delete(players[msg.sender]);
msg.sender.transfer(amount);
emit LogGameState(
msg.sender,
players[msg.sender].balance,
players[msg.sender].queryId,
queries[players[msg.sender].queryId].random,
contractBalance
);
}
function withdrawContractBalance() public {
uint256 amount = contractBalance;
contractBalance = 0;
msg.sender.transfer(amount);
emit LogGameState(
msg.sender,
players[msg.sender].balance,
players[msg.sender].queryId,
queries[players[msg.sender].queryId].random,
contractBalance
);
}
function deposit() public payable costs(0.01 ether){
contractBalance += msg.value;
emit LogGameState(
msg.sender,
players[msg.sender].balance,
players[msg.sender].queryId,
queries[players[msg.sender].queryId].random,
contractBalance
);
}
function getPlayer() public view returns (address playerAddress, uint balance, uint bet, bool waiting, bool win, bytes32 queryId, uint256 random) {
return (players[msg.sender].playerAddress,
players[msg.sender].balance,
players[msg.sender].bet,
players[msg.sender].waiting,
players[msg.sender].win,
players[msg.sender].queryId,
queries[players[msg.sender].queryId].random
);
}
function getPlayerBalance() public view returns (uint) {
return players[msg.sender].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;
}
}
/**
* Use this file to configure your truffle project. It's seeded with some
* common settings for different networks and features like migrations,
* compilation and testing. Uncomment the ones you need or modify
* them to suit your project as necessary.
*
* More information about configuration can be found at:
*
* truffleframework.com/docs/advanced/configuration
*
* To deploy via Infura you'll need a wallet provider (like @truffle/hdwallet-provider)
* to sign your transactions before they're sent to a remote public node. Infura accounts
* are available for free at: infura.io/register.
*
* You'll also need a mnemonic - the twelve word phrase the wallet uses to generate
* public/private key pairs. If you're publishing your code to GitHub make sure you load this
* phrase from a file you've .gitignored so it doesn't accidentally become public.
*
*/
const HDWalletProvider = require('truffle-hdwallet-provider');
const infuraKey = "f442bc908a5e4689a34d94ce3ba716b9";
//
const fs = require('fs');
const mnemonic = fs.readFileSync(".secret").toString().trim();
module.exports = {
/**
* Networks define how you connect to your ethereum client and let you set the
* defaults web3 uses to send transactions. If you don't specify one truffle
* will spin up a development blockchain for you on port 9545 when you
* run `develop` or `test`. You can ask a truffle command to use a specific
* network from the command line, e.g
*
* $ truffle test --network <network-name>
*/
networks: {
// Useful for testing. The `development` name is special - truffle uses it by default
// if it's defined here and no other network is specified at the command line.
// You should run a client (like ganache-cli, geth or parity) in a separate terminal
// tab if you use this network and you must also set the `host`, `port` and `network_id`
// options below to some value.
//
ganache: {
host: "127.0.0.1", // Localhost (default: none)
port: 7545, // Standard Ethereum port (default: none)
network_id: "5777", // Any network (default: none)
},
// Another network with more advanced options...
// advanced: {
// port: 8777, // Custom port
// network_id: 1342, // Custom network
// gas: 8500000, // Gas sent with each transaction (default: ~6700000)
// gasPrice: 20000000000, // 20 gwei (in wei) (default: 100 gwei)
// from: <address>, // Account to send txs from (default: accounts[0])
// websockets: true // Enable EventEmitter interface for web3 (default: false)
// },
// Useful for deploying to a public network.
// NB: It's important to wrap the provider as a function.
ropsten: {
provider: () => new HDWalletProvider(mnemonic, `https://ropsten.infura.io/v3/83d1095ef3f9413dbe7bf4be8d6c003c`),
network_id: 3, // Ropsten's id
gas: 5500000, // Ropsten has a lower block limit than mainnet
confirmations: 2, // # of confs to wait between deployments. (default: 0)
timeoutBlocks: 200, // # of blocks before a deployment times out (minimum/default: 50)
skipDryRun: true // Skip dry run before migrations? (default: false for public nets )
}
// Useful for private networks
// private: {
// provider: () => new HDWalletProvider(mnemonic, `https://network.io`),
// network_id: 2111, // This network is yours, in the cloud.
// production: true // Treats this network as if it was a public net. (default: false)
// }
},
// Set default mocha options here, use special reporters etc.
mocha: {
// timeout: 100000
},
// Configure your compilers
compilers: {
solc: {
version: "0.5.12", // Fetch exact version from solc-bin (default: truffle's version)
// docker: true, // Use "0.5.1" you've installed locally with docker (default: false)
// settings: { // See the solidity docs for advice about optimization and evmVersion
// optimizer: {
// enabled: false,
// runs: 200
// },
// evmVersion: "byzantium"
// }
}
}
}
Can you help me with this? Thank you!