0

I am creating a Smart contract that produces X Coins. If they send 1 USDT to the contract, I want to give 1 X Coin, which they can withdraw whenever they want. The reason why I want to use TransferFrom is that people can leave the X Coin for interest instead of withdrawing it immediately. So I want to use the Transfer function.

When I create a smart contract in another ERC20 Standard myself, I can interact with it and run the transfer function successfully.

PROBLEM: I got the Tether contract source code from https://etherscan.io/address/0xdac17f958d2ee523a2206206994597c13d831ec7#code.

I deployed it via Remix IDE to JavaScript VM(London) with Account 1 (0x5B38Da6a701c568545dCfcB03FcB875f56beddC4). Then, my own contract, X Token, Account 2 (0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2) I deployed with.

I have completed the approval process With USDT token account in account1, I confirm the address of X COIN smart contract to unlimited USDT smart contract. However, whenever I try to perform the transfer, I get the following error.

revert
    The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance.
Debug the transaction to get more information.

I'm sure the balance is enough There are 500,000,000 coins on account1 and I just want to withdraw 1,000,000 coins. I get this error only on USDT', not at any other contract address. What do you think is the problem?

X TOKEN SOURCE CODE:

// SPDX-License-Identifier: MIT
pragma solidity ^0.4.18;

contract BEP20 {
    string public name;
    string public symbol;
    uint8 public decimals = 6;
    uint256 public totalSupply;
    uint256 public totalMintSupply;
    mapping (address => uint256) public balanceOf;
    mapping (address => mapping (address => uint256)) public allowance;
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);
    event Burn(address indexed from, uint256 value);
    event Mint(address indexed from, uint256 _value);
    address owner;
    address feeCollector;
    uint256 initialSupply = 500000000;
    uint256 fee;
    uint256 burnAmount;
    string tokenName = 'XTOKEN';
    string tokenSymbol = 'XXX'; 
    address acceptedToken;
    uint256 priceA;
    uint256 priceBicot;
    uint8 phasenum;
    bool flag;

    uint256 public depositAmount;
    uint256 public amountOut;
    address public usdtToken;

    
    constructor() public {
        // Update total supply with the decimal amount
        totalSupply = initialSupply * 10 ** uint256(decimals);
        // Give the creator all initial tokens
        balanceOf[msg.sender] = totalSupply;
        // Set the name for display purposes
        name = tokenName;
        // Set the symbol for display purposes
        symbol = tokenSymbol;
        //Set owner of the token
        owner = msg.sender;
    }

    function approve(address _spender, uint256 _value) public returns (bool success) {
        allowance[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }


    function balanceOf(address _sender) public view returns(uint256 _balance){
        return balanceOf[_sender];
    }

    //I didn't care about the security measures I just tried to run the transfer
    function setDepositParams(address _usdtToken, uint256 _depositAmount, uint256 _amountOut) public {
        usdtToken = _usdtToken;
        depositAmount = _depositAmount;
        amountOut = _amountOut;
    }

    //I didn't care about the security measures I just tried to run the transfer
    function getDeposit() public {
        Callee c = Callee(usdtToken);
        bool trans;
        trans = c.transfer(owner, depositAmount);
        require(trans == true, 'Invalid payment');
        balanceOf[msg.sender] += amountOut;
        balanceOf[owner] -= amountOut;
    }

    function _transfer(address _from, address _to, uint _value) internal {
        require(_to != address(0), 'To cannot be empty.');
        require(balanceOf[_from] >= _value, 'Insufficient balance.');
        require(balanceOf[_to] + _value >= balanceOf[_to]);
        uint previousBalances = balanceOf[_from] + balanceOf[_to];
        balanceOf[_from] -= _value;
        balanceOf[_to] += _value;
        emit Transfer(_from, _to, _value);
        
        assert(balanceOf[_from] + balanceOf[_to] == previousBalances);
    }
    


}

contract Callee{
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
    function transfer(address _to, uint256 _value) public returns (bool success);
}
2
  • Please include the code calling it, seems like you are including a value on the call therefore it thinks it must be payable, but it'll be impossible to know unless you add more detail
    – Julissa DC
    Commented Jun 10, 2022 at 21:07
  • I think I found a solution to the problem. The problem may be in the Tether source code, or it has a setting that I don't understand and I'm overlooking it. I tried to make a payment by triggering the transferFrom function with another stable coin and it was successful.
    – AhmetE
    Commented Jun 11, 2022 at 17:54

1 Answer 1

1

The USDT code uses a onlyPayLoadSize() modifier on it's transferFrom() function

function transferFrom(address _from, address _to, uint _value) public onlyPayloadSize(3 * 32)

The EVM pads calls adding bytes to the msg.data.length by adding zeros, failing the transaction.

The solution is to use OpenZeppelin's SafeERC20 library's safeTransferFrom() function which makes a low level call to the transferFrom() function.

Import the library by adding "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

And

using SafeERC20 for ERC20;

make the call like this:

ERC20(tokenAddress).safeTransferFrom(msg.sender, address(this), amount);

Here is the reference to the original post I saw when encountering the same error how-to-transfer-and-transferfrom-on-the-tether-smart-contract-from-another-smart

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.