0
votes

I have created a basic ERC20 token by implementing OpenZeppelin as follow in ERC20.sol file:

pragma solidity ^0.6.4;

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/token/ERC20/ERC20.sol";

contract Token is ERC20 {
    constructor(string memory _name, string memory _symbol)
        public
        ERC20(_name, _symbol)
    {
        _mint(msg.sender, 10000000000000000000000000000);
    }
}

Then implement another contract Contract.sol as follow:

import "./ERC20.sol";

pragma solidity ^0.6.4;

contract SimpleBank{
    Token tokenContract;

    constructor(Token _tokenContract) public {
        tokenContract = _tokenContract;
    }
    
    function deposit(uint amt) public returns (bool)  {
        require(amt != 0 , "deposit amount cannot be zero");
        tokenContract.transfer(address(this),amt);
        return true;
    }
} 

As, I have deployed both contract from the address 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2 so, it holds 10000000000000000000000000000 tokens.

But when I call deposit function from same address I got the following error:

transact to SimpleBank.deposit errored: VM error: revert. revert The transaction has been reverted to the initial state. Reason provided by the contract: "ERC20: transfer amount exceeds balance". Debug the transaction to get more information.



So, what is the proper way to interact with the deployed ERC20 token so that the deploy function works.

1
The answer in the provided link isn't clear to me. Does it mean that another account can't interact with ERC20.sol for security reasons? Can you help me with that @PetrHejda?Abishek Bashyal

1 Answers

1
votes
  1. The user address 0xAb8483... sends a transaction executing SimpleBank's function deposit(), which makes 0xAb8483... the value of msg.sender in SimpleBank.

  2. But then SimpleBank sends an internal transaction executing Token's function transfer(). Which makes SimpleBank address (not the 0xAb8483...) the value of msg.sender in Token.

    So the snippet tokenContract.transfer(address(this),amt); within SimpleBank is trying to send SimpleBank's tokens. Not the user's (0xAb8483...) tokens.

This transfer of tokens (from point 2) reverts, because SimpleBank doesn't own any tokens. Which makes the top-level transaction (from point 1) revert as well.


If you want SimpleBank to be able to transfer 0xAb8483...'s tokens, 0xAb8483... needs to approve() the tokens first to be spent by SimpleBank. Directly from their address, so that they are msg.sender in the Token contract.

Only then SimpleBank can execute transferFrom(0xAb8483..., address(this), amt) (from, to, amount).


TLDR: Your contract can't spend tokens that it doesn't own, unless the owner has manually approved your contract to spend them.

If it could spend someone else's tokens without approval, it would be very easy to steal from people who can't/don't verify your source code (by spending their USDT, WETH and other widely-used tokens).