0
votes

How to add transfer function on a contract to a user using openZeppelin?

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract TokenSample is ERC20 {
    constructor() ERC20("TokenSample", "SMPL") {
        _mint(msg.sender, 21000000 * 10 ** decimals());
    }
}

When I deploy the above contract, I get a transfer form with 2 parameter (recipient, amount). It's okay.

But because of one reason, I need to implement my own transfer function inside the contract.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract TokenSample is ERC20 {
    constructor() ERC20("TokenSample", "SMPL") {
        _mint(msg.sender, 21000000 * 10 ** decimals());
    }

 function getToken(uint256 _amount) external returns(bool)  {
   // my internal logic here
   transfer(msg.sender, _amount);
    return true;
 }
}

From the code I got error : ERC20: transfer amount exceeds balance

I am not really sure but I guest it's because the token is belong to the owner not belong to the contract. What is the right way to implement that getToken method?

1

1 Answers

1
votes

The transfer amount exceeds balance error message comes from a failed check if the sender has enough balance. Source: ERC20.sol on OpenZeppelin GitHub.

In case of the transfer() function being called from within a contract function (and not directly by the user), the sender is the contract.

So this line in your contract

transfer(msg.sender, _amount);

is trying to send _amount of tokens from the contract address to the user (executing the getToken() function). And when it's trying to transfer more tokens than the sender (the contract) owns, it fails with this error message.


This way you can mint new tokens (increasing the total supply) to the user.

function getToken(uint256 _amount) external {
    // TODO your own logic here
    _mint(msg.sender, _amount);
}

And if you want to mint some of the tokens to the contract address during deployment, you can use the address(this) as the receiver, which stands for the current contract address.

constructor() {
    // mint 10M tokens to the contract
    _mint(address(this), 10000000 * 10 ** decimals());
    
    // mint 21M tokens to the owner
    _mint(msg.sender, 21000000 * 10 ** decimals());

    // total supply is now 31M, where the contract owns 10M and the owner owns 21M
}