Ethereum Crowdsale Discussion

  1. You are right. You need to return something in your getLeftTokens function. You also made a mistake in your return clause, it should only contain a return type. So if balanceOf returns an uint, you can write like this.
function getLeftTokens() public view returns(uint) {
     return token.balanceOf(address(this));
}
  1. HD wallet provider has been moved, correct. I’m very happy that you are exploring on your own, you will learn A TON. The documentation for the HDWalletProvider has been moved to truffle and you can find it here. I think you will be able to put the pieces together after reading through the ReadMe.
  1. First thing, which if statement block are we talking running within when you are executing it? I assume it’s the first one, where the funding goal is not reached. I also assume you are not getting any error messages? And how are you checking if no money is being withdrawn?

Looks kinda weird in it’s current state. You first have a transfer call, then you have another send call. They do the same thing, and right now you have quite a nasty bug where the balance will be withdrawn 2 times and the balanceOfShare could be corrupted.

Because first you withdraw all the money to the sender using transfer(). Now the actual balance is 0. Then you do send() with the same amount. This might fail since the contract is out of money, if it fails, then you reset the users balance to what it was before. Your issues might be coming from this.

  1. I have problem that compiler claims

:66:10: TypeError: Different number of arguments in return statement than in returns declaration.
return token.balanceOf(address(this)); //TypeError: Different number of arguments in return statement than in returns declaration.
^-----------------------------------^

I will add how original functions looks like in the token contract

function balanceOf(address tokenOwner) public view returns (uint) {
        return balances[tokenOwner];
    }

I don’t understand why this kind of error appears. I have read that the TypeError object represents an error when a value is not of the expected type, but both functions returns uint as a value of tokens assigned to the address.

  1. Thanks for help. I have a tip for Windows’s users, because the were some trobbles with it. If you have errors while installing @truffle/hdwallet-provider as I did, first go to the https://git-scm.com/download/win (I assumed that you already have account on the github and you rememeber your pass). Install it and the in the powershell input npm install @truffle/hdwallet-provider, I had also problems with installing truffle. Unfortunately I don’t remember how I solved it, but I guess it was after Filip’s video on his YT channel about truffle (https://www.youtube.com/watch?v=2fSPn0-8ORs).

  2. Yeah, it works now. I made mistake that I didn’t pay attention to the account balance, but I was looking for tx in transactions instead internal txns on etherscan, lol.

The following code works for me, using pragma 0.5.1. Did you correct the function as I said?

function getLeftTokens() public view returns(uint) {
     return balanceOf(address(this));
}

function balanceOf(address tokenOwner) public view returns (uint) {
        return balances[tokenOwner];
    }
}

Thanks for sharing the knowledge regarding truffle :+1:

I have solved the problem by changing the interface, I mean by adding the external returns (uint);

interface DubCoin {
    function transfer (address receiver, uint amount) external;

    function balanceOf (address ico) external returns(uint);
}

BTW It interesting to see how the language is changing, in the course we used function with the same name as contract to create a constractor, now we have separate keyword for that. But what is more important and I need to read more about it is not every address variable can use ‘send’ or ‘transfer’ method, now it needs payable attribute and that is makes whole thing more complicated in my opinion, to assign address to ‘address payable variableName’ we need to parse it into address(uint160(_address)).

I have decided to build new ICO Dapp and I found interesting ICO guide, but the problem is when I use buy function the complier throws error, I was debbuing it whole day, but I couldn’t find bug, I started commenting out many things, adding payable etc. but nothing works. If you find some time, can you check it? Rest of the functions works fine.

Github Code

transact to CrowdSaleMedium.buy errored: VM error: revert.
revert The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance. Debug the transaction to get more information.

Edit: Probably I have found the reason why buy functions is not working and the answer is allowance, I have to check it out - potencial solution. This thing came into my mind after I started working on the new ICO Dapp from scratch.

Edit2: Now function buy works, I have modified the code a little bit, because transferFrom also didn’t want to work. After all I had to remove function which was responsible for sending tokens only then, when the ICO reached the funding goal. So now if you buy tokens, you get them immidiately on your account, but I wanted to send them only when the ICO would reach funding goal otherwise the contract would refund your ETH. How to implement sth like that? To send tokens automatically only when fundingGoal = true otherwise also automatically send refund of ETH to your account?

Edit3: It seems that there is no solution to make it automatically, so I decided to implement functions for manual claim for tokens if funding goal is reached otherwise you can refund invested ETH. There is an issue, that you can’t use if(!token.transfer(msg.sender, saveBoughtTokens){} as we could in that case if(!msg.sender.send(etherRefund)){}. Do you have any suggestions?

I’m very happy to see that you managed to debug and solve your problem, great job!

Regarding your last question. I’m not sure what you are trying to accomplish exactly, can you clarify?

But if you want to check if a “transfer” is successful and if not, act on it. Then you shouldn’t use transfer, you should use send. Transfer doesn’t return true/false, it throws on error. Send returns true/false, and then it’s up to you to handle the error part.

It is a function which will send the bought tokens after the ICO will raise all the funds. It uses interface function to transfer tokens which normally works, but I want to implement the revert if the transaction would fail (exactly like in the safeWithdraw function), but it is not correct for Remix.

function getTokens() public  whenIcoCompleted { //withdraw the tokens after ICO reached
        
            uint saveBoughtTokens = boughtTokens[msg.sender];
            boughtTokens[msg.sender] = 0;
            
            if(saveBoughtTokens > 0){
                if(!token.transfer(msg.sender, saveBoughtTokens)){
                    boughtTokens[msg.sender] = saveBoughtTokens;
                }
            }
    }

I have a question about truffle etc.

Do you recommend to do some web development course on udemy or sth similar first, because it is really hard for me to create that ICO DApp, and then come back to the rest of the course about Ethereum and EOS devepolment or omit the ICO project and go straight to EOS and other stuff on your learning platform?

Ok, as I said. You need to use send() instead of transfer(). I described why in my previous response.

Regarding your truffle question. It all depends on what you are interested in. If you want to develop a professional dapp, you propably need to do a general web development course and learn a front-end framework like ReactJS.

We will have a course on truffle in the academy very soon. So that part we will cover, but normal web development is very easy to find both on youtube and on udemy.

Thank you, I now see my mistake. It was something different than that, the transfer function was from token contract which was returning the bool, but I forget to implement that into the interface in the ICO contract, that is why it couldn’t make this condition. That what you wrote is completely true, but it is related to different situation like if(!msg.sender(tokens)), but thanks for your time and effort.

As I heard there are two options, creating dapps or developing the protocol, so web development is inevitable for smart contract developer, do you agree?

1 Like

Great! I don’t think you must learn web development, even though it can be beneficial and open up more opportunities. Larger companies probably have separate developers for smart contract development and front-end development. But it will definitely help you overall to know web as well.

1 Like

Thank you for your help, now my ICO works perfectly in the Remix, it does exactly what I wanted! I can’t wait for your Truffle course, because I have possitively compiled my contracts in the Truffle with openzeppelin framework, which is very helpfull and boost efficienty, but I completely don’t get the migrations, I have seen your YT tutorial, but I am still lost.

For example I can’t migrate this ico contract, there is an error about unexpected token. But like I said I am guessing here, I don’t understand what I am doing in this file :stuck_out_tongue:

const proToken = artifacts.require("ProToken");
const Crowdsale = artifacts.require("ICO");

const settings = {
  rate: 2, // we have 100k tokens, 1 eth can buy 2 tokens
  wallet: 0x7BFea3A336Abbcf2Bf835010299ED059D75FE454,
  token: 0x8E3Cff48e81041De2945F055c5EBD623bE71e36a
};

module.exports = function(deployer) => deployer
  .then(() => deploy(Crowdsale, settings.rate, settings.wallet, settings.token))
  .then(() => setAndTransferAllowance(settings.address, Crowdsale.address, 100));

  async function setAndTransferAllowance(tokensHolder, spender, amount){
    const token = (await proToken.deployed()); // we wait until token contract is deployed;

    const value = amout * (10 ** token.decimals);

    await token.approve(Crowdsale.address, value); // we set allowance for ico contract to receive tokens from token contract;
    await token.transferFrom(token.address, Crowdsale.address, value) // we send from token contract to ico contract defined amount of tokens;
  }

You can post your error message if you want and I can check it out. I can see that you misspelled amount (you wrote amout), which would cause some problems.

I’m recording the new solidity + truffle course right now :slight_smile:

1 Like

My problem is that I don’t feel confident in these deployer, owner etc. variables meaning in the context of these test and migrate files (same with this “=>”). In the end I it has deployed, but like I said I have to educate more in that. Thanks for your engagement!

const ProToken = artifacts.require("ProToken");
const Crowdsale = artifacts.require("ICO");

const settings = {
  rate: 2, // we have 100k tokens, 1 eth can buy 2 tokens
  wallet: '0x7BFea3A336Abbcf2Bf835010299ED059D75FE454'
};

module.exports = (deployer, owner) => deployer
  .then(() => deployer.deploy(Crowdsale, settings.rate, settings.wallet, ProToken.address))
  .then(() => setAndTransferAllowance(ProToken.address, Crowdsale.address, 100));
  
  async function setAndTransferAllowance(tokensHolder, spender, amount){
    const token = (await ProToken.deployed()); // we wait until token contract is deployed;
  
    const value = amout * (10 ** ProToken.decimals);
  
    await token.approve(Crowdsale.address, value); // we set allowance for ico contract to receive tokens from token contract;
    await token.transferFrom(ProToken.address, Crowdsale.address, value) // we send from token contract to ico contract defined amount of tokens;
  }

Did you get it to work after you changed amout to amount?

Quick question: Is there a particular difference when writing the afterDeadline modifier in the CrowdSale contract with a require statement like this:

modifier afterDeadline() {
        require(now >= crowdSaleDeadline);
        _;
    }

Instead of writing it within an if statement like this:

modifier afterDeadline() {
        if(now >= crowdSaleDeadline){
            _;
        }
    }

If so, what’s the difference? They seem to behave the same when I test them, but I want to be sure there isn’t a reason for using the if statement that I’m overlooking.

Also, could we write the modifier without the if or require and still see the same results? It seemed to work the same when I tried it this way.

There won’t be any difference if now >= crowdSaleDeadline. There will be a big difference when the deadline has passed (now < crowdSaleDeadline). The require statement will throw an error and the tx will not go through. WIth the if statement, no error will be thrown and the tx will go trough, but the tx won’t do anything.

Require is more clear for the user. If you don’t have require, the user might think the tx was successful because it went through, even though the outcome was nothing.

1 Like

I had to changed something more than only that, there were some problems with indentify the token.

  1. Is it good practise to create migration file as simple as possible? I mean simple deployment without any interactions as it is in the initial migration file in Truffle. To be more clear, let’s say you need set allowance for the contract, so you can do that probably in the migration file or you can simply deploy the contract and then interact with that contract or it depends on the programmer?

  2. I have the next question related to the first one, how to interact with the contract which is e.g. on the Rinkeby testnet without front end? I mean this case when I need set allowance for ICO contract (I remember that we could interact with contracts by MEW, but are there more possibilities?).

  3. I was configuring the network and I have a question related to the mnemonic phrase when using Infura. How does it work? Let’s assume that I have already an account on Metamask or MyEtherWallet, so I need to attach the mnemonic from one of them into the secret file in order to use these accounts?
    Do I understand correctly, if I input completely new mnemonic phrase from my head in this secret file I will create a new account which will be avaliable to restore in Metmask or MEW?

  4. How to distinguish string and bytes (those dynamic, not fixed) since they seem to be the same thing? I have read the documentation, but I don’t know how to define raw byte data type in opposite to the string type since they both use UTF-8.

As a general rule, use bytes for arbitrary-length raw byte data and string for arbitrary-length string (UTF-8) data. If you can limit the length to a certain number of bytes, always use one of bytes1 to bytes32 because they are much cheaper.

1 Like

Hi ,
I transfered 0.2 Ether from my Metamask Wallet to the MyEtherWallet wallet succesfully. (i also checked again that MyEtherWallet address is similar to the one in my contract (GuyCoin instead of FilipCoin) construction.

1. should I be able to see the GuyCoin balance in the MyEtherWallet?
(I can see only the Rin/Ether balance ).

  1. I am repeating the video step by step… and fail to transfer any tokens to the Crowdsale address.
    I repeatedly receive a message as follows:
    "Invalid argument 0:Jason. can not unmarshal invalid hex string into Go struct field. CallArgs.Gas of type hexutil.uint64" (after pressing the “write” Button).

Any Suggestions?

Thanks

guy

  1. No, not without telling the wallet about your token. Not sure if myetherwallet supports this.

  2. This is probably some some sort of format issues of your inputs. Make sure you have all the types correct, no spaces within the address and no other copy/paste format issue.

If you still don’t get it to work you can send the input arguments here and I’ll check them.

Hi Filip. these are the addresses. its not working for me.
It also says (in previous transfer attempts) that It exceeds the block gas limits.

Contract address (filipCoin Contract): 0x7fe31723349febe0113bb3eac222fba80d33650a

To Address (CrowdSale Contract):
0x0cea7c0ed2912cac62c0447ce187190d0cc86c9b

In the previous Transaction it says that i exceeds the block gas limit…
Time:
4:31:21 PM
11/10/2019
Status:(Failed)
Amount:0 RIN
To Address:
Gas Price:1.5 gwei

Gas Limit: 53292764651854

Max Transaction Fee:79939.146977781 RIN ($14583298.58)
Nonce:
0
Error Message:
exceeds block gas limit

Thanks

The gas limit looks very high. Try lowering it. Also, which address are you using to execute the transfer function?