I write a simple smart contract to test the function approve() in the USDT, here are my code:
pragma solidity ^0.4.25;
contract EIP20Interface {
uint256 public totalSupply;
function balanceOf(address _owner) public view returns (uint256 balance);
function transfer(address _to, uint256 _value) public returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
function approve(address _spender, uint256 _value) public returns (bool success);
function allowance(address _owner, address _spender) public view returns (uint256 remaining);
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
contract Test {
function tokenAllowAll(address asset, address allowee) public {
EIP20Interface token = EIP20Interface(asset);
if (token.allowance(address(this), allowee) != uint(-1)) {
token.approve(allowee, uint(-1));
}
}
}
After I have deployed it on the mainnet, I just tried to call tokenAllowAll(), but if I input 0xdAC17F958D2ee523a2206206994597C13D831ec7(USDT), 0xAA9E86e4a81625D9016a43AfAe07595D8aD5f4D5(an account), if will fail and throw out an error: Gas estimation failed, but if I input 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48(USDC), 0xAA9E86e4a81625D9016a43AfAe07595D8aD5f4D5(an account) it will pass, so I am not sure what is special for USDT, it has confused me for some days, thanks for any help!
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
// To change the approve amount you first have to reduce the addresses`
// allowance to zero by calling `approve(_spender, 0)` if it is not
// already 0 to mitigate the race condition described here:
// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
require(!((_value != 0) && (allowed[msg.sender][_spender] != 0)));
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
}
Does that mean I can call approve(spender, value) in the USDT contract directly, but I can not call the same function in a contract, cause it is not a standard ERC20 contract, but what is the reason for it?
I assume the issue is that the original Test called using the interface with a return value, whilst SafeERC20 handles both with and without a return value.
I do not think there is any USDT on the testnet from the acutal Tether, so if you wants to have a test on a testnet, you can use the source code on the mainnet to deploy a new one on the testnet to simulate.
@Skyge I’ve deployed the USDT contract to Ropsten testnet at 0xd5ffb36998e2e2df1402e33801a1949852055cb0, and I wrote some code to test how to deposit usdt into the smart contact and withdraw the deposited usdt. I’ve safeapprove the contract address at 0xd5ffb36998e2e2df1402e33801a1949852055cb0, but still I couldn’t depost usdt by calling safeTransferFrom, I am quite new to smart contract, just wondering what’s missing here? Thanks very much.
contract Test {
using SafeERC20 for IERC20;
function tokenAllowAll(address _asset, uint256 _amount ) public {
IERC20 usdt = IERC20(_asset);
if (usdt.allowance(msg.sender, address(this)) < uint256(_amount)) {
usdt.safeApprove(address(this), uint256(_amount));
}
}
function deposit(address _asset,uint256 _amount) public {
IERC20 usdt = IERC20(_asset);
require (usdt.allowance(msg.sender,address(this)) >= _amount,"Allowance must larger than deposit amount!");
usdt.safeTransferFrom(msg.sender, address(this), _amount);
}
function withdraw(address _asset,address _recipient, uint256 _amount) public {
IERC20 usdt = IERC20(_asset);
require (usdt.allowance(msg.sender,address(this)) >= _amount,"Owner must allow the tractions");
usdt.safeTransfer( _recipient, _amount);
}
}
i have same problem , on testnet trc20 token work fine but on mainnet after i sent usdt to contract but withdraw function show error
“REVERT opcode executed. Message: *SafeERC20: ERC20 operation did not succeed”
my contract is
pragma solidity ^0.8.0;
import "../github/OpenZeppelin/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
contract Invest {
using SafeERC20 for IERC20;
uint256 public target = 1000 * (10**6);
address public owner;
constructor(uint256 _target){
target = _target;
owner = msg.sender;
}
function withdraw(IERC20 token, address to) external isOwner {
uint256 balance = token.balanceOf(address(this));
require(balance >= target,"balance is low");
transferToken(token, to, balance);
}
function setTarget(uint256 newTarget) external isOwner {
require(newTarget > target,'new target must be greater current');
target = newTarget;
}
modifier isOwner()
{
require(msg.sender == owner,'only owner can do it');
_;
}
function transferToken(IERC20 token, address to, uint256 amount) private {
token.safeTransfer(to, amount);
}
}
I'm new to smart contract tech totally new I want someone who can teach me how to develop smart contracts and deploy them expectially ones related to this approve(address _spender, uint256 _value) on ERC20 or TRC20 network