假设有个合约ERC20充值方法,方法接收msg.sender发送的ERC20代币,并增加合约中的余额统计

import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
...
function rechargeMain(address mainChainErc20Addr, uint256 amount) payable external notContract returns (bool){
    ...
    require(amount > 0, "The recharge amount is too small");
    require(IERC20(mainChainErc20Addr).balanceOf(msg.sender) >= amount, "Insufficient contract account balance");

    IERC20(mainChainErc20Addr).transfer(address(this), amount);
    ...
    return true;
}

执行后提示

execution reverted: ERC20: transfer amount exceeds balance

经测试(Github Code

function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
    _transfer(_msgSender(), recipient, amount);
    return true;
}

_msgSender()的地址为合约地址,测试交易(跳转地址

所以我们需要使用transferFrom,代码修改为

import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
...
function rechargeMain(address mainChainErc20Addr, uint256 amount) payable external notContract returns (bool){
    ...
    require(amount > 0, "The recharge amount is too small");
    require(IERC20(mainChainErc20Addr).balanceOf(msg.sender) >= amount, "Insufficient contract account balance");

    IERC20(mainChainErc20Addr).transferFrom(msg.sender, address(this), amount);
    ...
    return true;
}

执行完,提示

execution reverted: ERC20: transfer amount exceeds allowance

查看代码(Github code

function transferFrom(
address sender,
 address recipient,
 uint256 amount
) public virtual override returns (bool) {
    _transfer(sender, recipient, amount);

    uint256 currentAllowance = _allowances[sender][_msgSender()];
    require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
    unchecked {
        _approve(sender, _msgSender(), currentAllowance - amount);
    }

    return true;
}

需要先批准交易金额(津贴)(Github Code

 function approve(address spender, uint256 amount) public virtual override returns (bool) {
     _approve(_msgSender(), spender, amount);
     return true;
 }

查看当前剩余允许值,(Github Code

function allowance(address owner, address spender) public view virtual override returns (uint256) {
    return _allowances[owner][spender];
}

也可以执行increaseAllowancedecreaseAllowance增量增减调整

对于此次需求,执行rechargeMain前,需要先执行津贴充值

increaseAllowance(address spender, uint256 addedValue)

执行increaseAllowance的地址为当前充值转出地址
spender为当前转入合约地址
addedValue为当前充值金额
测试交易:https://ropsten.etherscan.io/tx/0x0f65cb2a7ca2bf0d6b1fdd65e943afb5c6305573dc3c3a960c2f86f71757c897