在 ERC20 托管合约上调用存款功能时出错

Error calling deposit function on ERC20 escrow contract

我写这个合约是为了托管给定类型的 ERC20 代币(代币的地址在调用构造函数时给出)。但是每次我调用存款功能将一些代币存入合约时,我只是交易失败,我不确定为什么。


pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MainEscrow is Ownable {

    IERC20 public token;

    event Deposited(
        address indexed payee,
        address tokenAddress,
        uint256 amount
    );
    event Withdrawn(
        address indexed payee,
        address tokenAddress,
        uint256 amount
    );

    // payee address => token address => amount
    mapping(address => mapping(address => uint256)) public deposits;

    // payee address => token address => expiration time
    mapping(address => mapping(address => uint256)) public expirations;

    constructor(address _tokenAddress) {
        token = IERC20(_tokenAddress);
    }

    function deposit(
        address _payee,
        uint256 _amount,
        uint256 _expiration
    ) public {
        token.transferFrom(msg.sender, address(this), _amount);
        deposits[_payee][address(token)] += _amount;
        expirations[_payee][address(token)] = block.timestamp + _expiration;
        emit Deposited(_payee, address(token), _amount);
    }

    function withdraw(address payable _payee, uint256 _amount) public {
        uint256 totalPayment = deposits[_payee][address(token)];
        require(totalPayment >= _amount, "Not enough value");
        token.approve(_payee, _amount);
        require(token.transfer(_payee, _amount));
        deposits[_payee][address(token)] = totalPayment - _amount;
        emit Withdrawn(_payee, address(token), _amount);
    }

    function refund(address payable _payee) public {
        require(
            block.timestamp > expirations[_payee][address(token)],
            "The payment is still in escrow."
        );
        uint256 payment = deposits[_payee][address(token)];
        token.approve(msg.sender, payment);
        require(token.transfer(msg.sender, payment), "Transfer failed");
        deposits[_payee][address(token)] = 0;
        emit Withdrawn(msg.sender, address(token), payment);
    }
}

deposit() 函数中实际上只有一行可能失败:

token.transferFrom(msg.sender, address(this), _amount);

(理论上也可以恢复,因为以下两行的整数溢出,但这是非常不可能的。)

此行在 token 合约上执行函数 tranferFrom()。正如 ERC-20 标准定义的那样,如果令牌发送者没有足够的余额,或者他们没有批准调用者(在您的情况下是 MainEscrow 地址)花费那么多,该函数应该恢复他们的代币。

所以代币发送者没有足够的余额,或者他们没有从代币合约上的地址调用 approve(<MainEscrow_address>, <amount>) 函数。