Solidity 0.8.x – How to Increase Allowance of a Smart Contract to Transfer a User’s ERC20 Tokens

soliditysolidity-0.8.x

First, let me apologize because I've seen this question asked multiple times but I can't figure it out still.

  function setAllowance(address tokenAddr, uint256 amount) external payable {
    IERC20(tokenAddr).safeIncreaseAllowance(address(this), amount * 10**18);
  }

  function getAllowance(address tokenAddr) external view returns (uint256) {
    return IERC20(tokenAddr).allowance(msg.sender, address(this)) / 10**18;
  }

This is my function in solidity. I'm calling it from React so within this function the caller/msg.sender is my external metamask wallet address. I want my contract to be able to send tokens on behalf of the external metamask wallet. However, the allowance does not increase. I believe my setAllowance is wrong, but it doesn't have a "owner" & "spender" parameter, only "spender" which is my contract (ie. address(this)).

So how do I know who the spender is getting the allowance from, because I want it to be the external metamask wallet, but clearly that is not happening and it's getting an allowance from something else.

I want to add in that I swapped address(this) and msg.sender, but I don't want my external wallet to have an allowance from the contract, I need it the other way around. (though in this case, the allowance did increase).

Edit 1:
Im using import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"
and the function:

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

Edit 2: Testing it on Mumbai network (Polygon testnet)

Faucet: https://faucet.polygon.technology/

Using: Test ERC20 Plasma from this faucet on Mumbai

Testing Token: https://polygonscan.com/token/0xfe4F5145f6e09952a5ba9e956ED0C25e3Fa4c7F1

Best Answer

Are you talking about this contract?

https://rinkeby.etherscan.io/address/0x3b00ef435fa4fcff5c209a37d1f3dcff37c705ad#code

If so, I would personally just create my own interface, because the USDT implementation is kinda wild:

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

interface IERC20 {
    function balanceOf(address owner) external view returns (uint256);

    function approve(address spender, uint256 value) external returns (bool);

    function allowance(address owner, address spender)
        external
        view
        returns (uint256);

    function increaseAllowance(address spender, uint256 addedValue)
        external
        returns (bool);

    function decreaseAllowance(address spender, uint256 subtractedValue)
        external
        returns (bool);
}

You can even delete the approve() function if you won't be using it.

Note that this will NOT work the same way on mainnet, because there's a completely different implementation of an older ERC20 version.

Related Topic