I wrote this contract to escrow a given type of ERC20 token (address of the token is given when calling the constructor). But every time I call the deposit function to deposit some tokens into the contract, I just get transaction failed and I'm not sure why.
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);
}
}
There's practically only one line that could fail in the deposit()
function:
token.transferFrom(msg.sender, address(this), _amount);
(It could theoretically also revert because of an integer overflow on the following two lines, but this is very improbable.)
This line executes the function tranferFrom()
on the token
contract. As the ERC-20 standard defines, the function should revert if the token sender doesn't have sufficient balance, or if they haven't approved the caller (in your case the MainEscrow
address) to spend that much of their tokens.
So either the token sender doesn't have sufficient balance, or they haven't called the approve(<MainEscrow_address>, <amount>)
function from their address on the token contract.