Implement EIP712 style permit inheriting ERC20Upgradeable

Hi,

We are developing a token and want to include ‘gasless’ approve functionality using EIP712 signatures.

It will look something like this:

contract Token is Initializable, ERC20Upgradeable {
    mapping(address => mapping(address => uint256)) private _allowances;

   /**
ERC721 stuff in initializer
   */

    function permit(
        address _holder,
        address _spender,
        uint256 _nonce,
        uint256 _expiry,
        bool _allowed,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) public override {
        bytes32 digest =
            keccak256(
                abi.encodePacked(
                    '\x19\x01',
                    DOMAIN_SEPARATOR,
                    keccak256(abi.encode(PERMIT_TYPEHASH, _holder, _spender, _nonce, _expiry, _allowed))
                )
            );
        require(_holder != address(0), 'Token: invalid-address-0');
        require(_holder == ecrecover(digest, _v, _r, _s), 'Token: invalid-permit');
        require(_expiry == 0 || block.timestamp <= _expiry, 'Token: permit-expired');
        require(_nonce == nonces[_holder]++, 'Token: invalid-nonce');
        uint256 wad = _allowed ? 2**53-1 : 0;
        _allowances[_holder][_spender] = wad;
        console.log(_holder);
        console.log(_spender);
        console.log(_allowances[_holder][_spender]);
        emit Approval(_holder, _spender, wad);
    }
}
}

The permit method works (validates signature, emits Approve event with correct values) but when I check with allowance(holder, spender) I get 0.

If I use regular ERC20 approve, allowance is set correctly.

_allowances is private in ERC20Upgradeable so we tried redefining it in the child contract. It compiles but I’m afraid it’s not working properly.

Any tips? Is it possible to do this using ERC20Upgradeable?

Thanks!

2 Likes

Hi @ethicraul,

There is a PR in progress to add Permit to OpenZeppelin Contracts that you could look at for inspiration and calls _approve rather than using _allowances directly: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/2237

1 Like

This does not work. The variable you defined is a new variable, and the allowance function still reads from the other variable.

You can use the internal _approve function to modify the allowances mapping.

2 Likes