I have a crowdsale campaign that i've created but cant seem to find the root cause of this.

Basically, when the campaign is expired, the buyer able to make a refund the token that they've bought during launch but they need to return the token in order to get back the ETH that they're purchased. When buying the token , the eth will transfer to the contract balance and it will revert back once the contract has received the token.

function buyTokens(
        uint256 _amount
    ) public payable onlyWhiteListed onlyWhileOpen {
        uint256 requiredEth = (_amount / 1e18) * price;
        require(msg.value == requiredEth, "Invalid amount of Ether");
        require(_amount <= maxPurchase && _amount >= minPurchase);
        require(dappToken.balanceOf(address(this)) >= _amount);

        purchaseAmount[msg.sender] += _amount;

        require(dappToken.transfer(msg.sender, _amount));

        tokensSold += _amount;

        (bool success, ) = owner.call{value: requiredEth}("");
        require(success, "Failed to send Ether");

        emit Buy(_amount, msg.sender);

 function refundCampaign() public onlyCampaignEnd {
        require(refundStatus == true, "Refund is not enabled");

        uint256 refundAmount = purchaseAmount[msg.sender];

        require(refundAmount > 0, "You have not purchased any tokens");

        purchaseAmount[msg.sender] = 0;
        tokensSold -= refundAmount;

        dappToken.transferFrom(msg.sender, address(this), refundAmount);

        uint256 ethAmount = refundAmount * price;
        require(address(this).balance >= ethAmount, "Insufficient balance");

        (bool ethSuccess, ) = msg.sender.call{value: ethAmount}("");
        require(ethSuccess, "Failed to send Ether");

        emit Refund(msg.sender, refundAmount);

I can see the eth increased in deployer wallet but I'm still getting an error "Insufficient balance" when sending back eth to the buyer

1 Answer 1


(bool ethSuccess, ) = msg.sender.call{value: ethAmount}("");

requires the contract to hold ethAmount of Ether in order to work, here i assume the contracts balance is always 0 since buyTokens() transfers the ETH to the contracts owner.

One solution would be to let the user buy the tokens, but not transfer them right away (both the tokens purchased and the ETH used to buy would be locked in the contract), and then when the presale ends, to have the user have to choice between

  1. claiming the tokens they purchased (which would unlock their tokens and send the corresponding amount of ETH to the contract owner)
  2. get a refund (which would destroy the locked tokens they bought and give them their ETH back)
  • Seems I have missed the calculation from buyTokens lol. since the ETH price are determined by (_amount / 1e18) * price. So I should return the same calculation in refundCampaign and it is working now
    – 0xhaz
    Commented Jun 12, 2023 at 16:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.