Programming Project - Phase 1

Hello, I am trying to test a payable function through the ganche console.

The user needs to send ether to the “start()” function to be able to play.

The line I am running is:

instance.start({value: web3.toWei(1, 'ether')})

Is the problem that I am trying to pass it as a parameter? Thank you!

Hi @JeffE,

Try to use web3.utils.toWei(‘1’, ‘ether’) .
toWei function require big number or string as first parameter if you give him a number it will fail.
See full documentation here if needed.

3 Likes

Thanks for the response! I did that then it said that it expected 0 parameters for the function start(), I guess I should not have it as a parameter.
Should it look something like

instance.start().send({value: web3.utils.toWei('1', 'ether')})

Thanks!

Ended up getting it! Thanks!

The line ended up being

instance.start({value: web3.utils.toWei('1', 'ether')})

hey @gabba
Initially, the smart contract doesn’t have any money. So, if the first user wins the gambling, we need to return him twice the money he had gambled. So, the question is, is there a way to send the winner money from the owner account? or any other way to solve this problem. Because initially few times error is thrown saying balance should be greater than the amount to be sent.

Hello @loksaha1310 ,
I think you need to do this is the 2nd migrations file. This allows it so when the contract is deployed it will automatically add eth to the smart contract from the account. This is also currently what I am working on.

Hope that made sense

1 Like

Thanks man! Let me check that out too! :smiley:

1 Like

Hi @loksaha1310

@JeffE is correct , you can make your contract constructor payable and send eth during your migration:

module.exports = function(deployer) {
  deployer.deploy(Contract, {value: web3.utils.toWei("1", "ether"), gas: 6000000});
};

Otherwise you can create a function to send funds to your contract.

3 Likes

is it necessary to mention the gas? I mean I read somewhere, I can control it somehow. Is there a lower bound?
Thank you by the way :")

@loksaha1310
Thanks for reaching out!
No, it is not necessary to mention the gas and is optional

source: https://web3js.readthedocs.io/en/v1.2.7/web3-eth-contract.html

Further more if you need to control the gas we have gasLimit: the maximum number of gas unit the EVM can use to process the transaction and
gasPrice: represents the price you willing to pay per gas unit.

1 Like

The Dapp gives me the following error
RPC Error: Error: [ethjs-rpc] rpc error with payload
I read that changing network and re-selecting ganache was solved, but it served me twice and then again the error.

same here with me! Trying to solve the issue

Is there a way to get the user’s desired bet as an input or do I have to use a button?

function startGame(){
    var bet = $("#bet_input").val();
    bet = bet.toString();

    var config = {
        value: web3.utils.toWei(bet, "ether")
    }

    contractInstance.methods.start().send(config);
}

I know the first parameter needs to be a string so I tried to convert it. I still receive this error in console though.

Uncaught Error: while converting number to string, invalid number value ‘bet’, should be a number matching (^-?[0-9.]+).

Thanks!

@Thaddeus19 & @loksaha1310
Try giving gas parameter explicitly for your contract deployment.
if it still doesn’t work try reinstalling metamask, don’t forget to backup your private key of previous wallet :slight_smile:

1 Like

@JeffE
I have set the input in the html file as a type=“text” and with this there is no need to conversion into string.

If you would then need to get that as a number you can use below conversion:

var betValue = parseFloat($("#bet_value").val());

Hope that helps!

1 Like

So took me about 5 days to complete the actual smart contract part of it. Then spent about 3 days on the DApp front end part of it. Did not really style it that much but it works! Thanks for everyone’s help!

Video: https://drive.google.com/file/d/1xYv3SamDI9Pki1-Gj6bDdT4meegcyLvt/view?usp=sharing

Code: https://github.com/JExtor/CoinFlipDAPP

2 Likes

@JeffE
Amazing work!
You can try Ivan on tech’s blockchain bootcamp to become a full-stack (both front-end and back-end) dApp developer :slight_smile:

3 Likes

Thank you!
I 100% was thinking about doing his bootcamp. I am looking into a possible payment plan for the bootcamp. I just graduated highschool this year and I know that I want to pursue blockchain development as a career. Doing anything I can to get my foot in the door!

2 Likes

Great course so far and a challenging project for someone who hasn’t had any coding experience before, but I have enjoyed it!

I have tried to do some CSS styling and animations to spin a coin, which weren’t shown in previous courses to learn something new. It was also very valuable to see how people share their issues and resolutions to problems that I had to tackle myself and it helped me resolve my problems. I will now share my project to continue the collaboration :slight_smile:

Any questions or comments please give me a shout!

Video demo: https://drive.google.com/file/d/1V6WSIc2TcqKz6rc9hnJuFf1zxwQnrPVC/view?usp=sharing

Source code: https://github.com/Filipo24/CoinFlip-Dapp

1 Like

Filip,

I got everything to work the way I intended except for the transfer of gains from the contract to the customer’s account. It works perfectly fine during migrations, but when I call the same contract function “sendMoney” from the main.js file, the transmission and reception of the function parameters works as before, but there is never any transfer of funds. So the same contract function supplied with the same input parameters and producing the same output values works when it is called during migration and doesn’t work when it is activated via main.js. As you can imagine, I have tried everything that I could think of to fix this problem, and I absolutely did verify that the input is received properly, but the fact remains that the function works or doesn’t work depending on the calling context. Another, problem was that the transmission of large wei-integer values also works only during migration.The BigNumber function is properly recognized in main.js, but its functionality in transmitting data to the contract is somehow not the same. I more or less solved this problem by breaking up the ether-to-wei conversion into two separate steps (one in main,js and one in solidity), but this “solution” is a bit crummy and not fully satisfactory.

To make this more precise, here is the command that I used in main.js to activate the sendMoney function in the contract:

      gain = Math.round(2000000*gain);   
      contractInstance.methods.sendMoney(customerAddress,gain).call({from:owner})then(function(transferAmount){console.log(transferAmount);});

All the parameters are correctly received and the transferAmount output is correct, but there is, as I said no transfer of funds. By contrast, there is a transfer of funds when I use the following call during migration:

 await instance.sendMoney(accounts[3], 1000000, {from: accounts[0]});

Finally, the sendMoney function in solidity looks as follows:

function sendMoney(address payable customerAddress, uint transferAmount) public onlyOwner returns(uint){
  transferAmount = transferAmount*1000000000000;
  balance -= transferAmount;
  customerAddress.transfer(transferAmount);
  return(transferAmount);}

The only other fairly major problem that I ran into was the fact that the now%2 function that you advertised in your video, always produced the same value. It produced different values for different migrations, but for a given contractinstance (or instance) it always produced the same output. To get around that problem, I cooked up a different pseudo-random function using hashes. Here is what it looks like:

 function random(bytes memory n) public view onlyOwner returns(uint){
    return uint256(keccak256(n)) % 10;}

It produces a pseudo-random digit between zero and nine that determines where my number animation comes to a halt. The pseudo-random encryption and the corresponding call in main.js look as follows:

var encoding = "RETEEssdf34fgdcccvv565(some random string)";
var date = new Date();
contractInstance.methods.random(web3.utils.fromAscii(date + encoding)).call({from: owner} then(function(randomValue){
   totalCount = 18  + 1*randomValue;

So the idea is to produce a new date string every one second and then to generate the hash of the concatenation of that date string with the random string shown above. Taking the modulo to the base ten of this hash, you end up with a pseudo-random digit between 0 and 9. So far as I can tell, this simple encryption method is nearly unbreakable because the encoding string can be arbitrarily long and complicated.

I took a screen video of my machine in action, but your end of the system didn’t allow me to attach it. So here is a screen capture instead:

For the main.js program (shown below), I used a nested sequence of promise calls, and I was wondering whether you had any comments to make about that choice.

  var web3 = new Web3(Web3.givenProvider);
  var contractInstance;
  var lastN = 0;
  var potentialGainLoss = 0;
  var encoding = "RETEEssdf34fgdcccvv565(some random string)";
  var owner = "0x30c2beE07179b5ef41fcd1017eDc734b2983E26B";
  $(document).ready(function(){
window.ethereum.enable().then(function(accounts){
  contractInstance = new web3.eth.Contract(abi, "0x872be5C771228602b787515e04D3AF1ADDBD1C2e", {from: accounts[0]});
    console.log(contractInstance);
    ctx.font = "45px Arial";
    $("#submit_and_play_button").click(submitAndPlay);
    function submitAndPlay(){
      var onZero = 0;
      var onOne = 0;
      var totalCount = 0;
      var customerAddress = $("#account_input").val();
      function setColor(m){
        if(m % 2 == 0){
          ctx.fillStyle = "black";
        }else{
          ctx.fillStyle = "white";
        }
      }

      if(customerAddress.length == 42){
        setColor(lastN);
        ctx.fillText(lastN % 2,62+lastN*50,91);
        onZero = $("#on_zero_input").val();
        onOne = $("#on_one_input").val();
        potentialGainLoss = web3.utils.toWei(Math.abs(onZero - onOne).toString(), "ether");
        contractInstance.methods.getBalance().call().then(function(contractBalance){
          if(1*contractBalance > 1*potentialGainLoss){
            var config = {from: customerAddress, value: potentialGainLoss};
            contractInstance.methods.receiveMoney().send(config).then(function(){
              var date = new Date();
              var count = 0;
              var n = 0;
              contractInstance.methods.random(web3.utils.fromAscii(date + encoding)).call({from: owner})
              .then(function(randomValue){
                totalCount = 18  + 1*randomValue;
                ctx.fillStyle = "red";
                ctx.fillText(0,62,91);
                var id = setInterval(runNumbers,200);
                function runNumbers() {
                  if(Math.floor(count/9) % 2 == 0){
                    n++;
                  }else{
                    n--;
                  }
                  if(count == totalCount){
                    clearInterval(id);
                  }else{
                    setColor(n-1);
                    if(Math.floor(count/9) % 2 == 0){
                      ctx.fillText((n-1) % 2,62+(n-1)*50,91);
                    }else{
                      ctx.fillText((n+1) % 2,62+(n+1)*50,91);
                    }
                    ctx.fillStyle = "red";
                    ctx.fillText(n % 2,62+n*50,91);
                    lastN = n;
                    count++;
                  }
                }
              }).then(function(){
                var gain = (onOne - onZero)*(2*(totalCount % 2) - 1);
                if(gain<0){
                  $("#gain_output").text("0 ether");
                  $("#loss_output").text(Math.abs(gain) + " ether");
                }else{
                  $("#loss_output").text("0 ether");
                  $("#gain_output").text(gain + " ether");
                  gain = Math.round(2000000*gain);
                contractInstance.methods.sendMoney(customerAddress, gain).call({from: owner}).then(function(transferAmount){
                  console.log(transferAmount);
                });
                }
              });
            });
          }else{
            alert("Your bet is too large!");
          }
        });
      }else{
        alert("Invalid Address!");
      }
    }
  });
});