在 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>)
函数。
我写这个合约是为了托管给定类型的 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>)
函数。