简体   繁体   中英

Solidity Transfer Issue

i have created an ERC20 token and a second contract called Vendor that is only supposed to receive ETH and then call the transfer function of the ERC20 contract to send the tokens to the buyer.

Through ether.js i call the Buy function on the vendor contract, sending the amount of eth as follows

async function buy() {
const request = await vendorContract.buyTokens(
    {
         from: accounts[0],
         value: ethers.utils.parseUnits("0.1") 
    }
);
}

As soon as the Vendor contract receives the transaction, it checks that the amount is higher than 0, and checks the Vendor contract balance to make sure it is going to be able to pay, as follows

function buyTokens() public payable returns (uint256 tokenAmount) {
require(msg.value > 0, "Send ETH to buy some tokens");

uint256 amountToBuy = msg.value * tokensPerEth;

// check if the Vendor Contract has enough amount of tokens for the transaction
uint256 contractBalance = ercToken.balanceOf(address(this));
require(contractBalance >= amountToBuy, "Vendor contract has not enough tokens in its 
balance");

// Transfer token to the msg.sender
(bool sent) = ercToken.transfer(msg.sender, amountToBuy);
require(sent, "Failed to transfer token to user");

// emit the event
 emit BuyTokens(msg.sender, msg.value, amountToBuy);

return amountToBuy;
}

And untill now, everything works, then, the ERC20 Smart Contract should transfer the amount of tokens the user bought to the user's address as follows

function transfer(address to, uint256 amount) public virtual override returns (bool) {
    _transfer(msg.sender, to, amount * 1e18);
    return true;

The ERC20 smart contract transfer function sets the caller equal to the msg.sender, in this case, our Vendor smart contract, passes the "to" address and multiplies the amount * decilams (18) and then invokes the _transfer function

    function _transfer(
    address from,
    address to,
    uint256 amount
    ) internal virtual {
    require(from != address(0), "ERC20: transfer from the zero address");
    require(to != address(0), "ERC20: transfer to the zero address");

    _beforeTokenTransfer(from, to, amount);

    uint256 fromBalance = _balances[from];
    require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
    unchecked {
        _balances[from] = fromBalance - amount;
       
        _balances[to] += amount;
    }

    emit Transfer(from, to, amount);

    _afterTokenTransfer(from, to, amount);
}

And this is where my issue starts, even if both ERC20 contract and Vendor contract got 1.000.000.000 tokens in their balance, the _transfer function fails saying the amount exceeds the balance. Any idea why?

From the transfer function, you are passing the msg.sender as from to the _transfer function. Which means you are trying to send tokens to a msg.sender from a msg.sender.

So thats why contract is giving you the "ERC20: transfer amount exceeds balance" error from this line require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); fromBalance is zero because it didnt recieved any tokens yet.

What you want to do here is this;

on the transfer function, you should pass the vendorContract like this;

`function transfer(address to, uint256 amount) public virtual override returns (bool) {
_transfer(vendorContract, to, amount * 1e18);
return true;`

That way the from argument on the _transfer function will be the vendor contract and everything should work as intended.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM