Here is a draft proposal for monkeypatching EIP-2612 support on ERC-20. This is by no means a complete proposal.
Summary
ApprovalTarget is an immutable contract that accepts token approvals from users across various ERC-20s, then enables anyone with a valid user signature to transfer those tokens. You can think of it like monkeypatching EIP-2612 support on all ERC-20 compliant tokens.
Abstract
To use ERC-20 tokens in dApps, approving is needed, which is expensive.
Design a ApprovalTarget contract to create a single signed approval flow for ERC-20 tokens. This allows users to send approval transaction only once.
Motivation
EIP-2612 allows abstraction in the ERC-20 approve
method. But some of ERC-20 tokens do not have a permit
function. Introducing ApprovalTarget indirectly allows approval by signature for all ERC-20 compliant tokens.
In addition ApprovalTarget replaces approve
transaction with a signed approve and will improves UX.
Specification
ApprovalTarget has three functions.
function nonces(address owner) external view returns (uint)
function PERMIT_AND_TRANSFER_FROM_TYPEHASH() external view returns (bytes32)
function permitAndTransferFrom(address erc20, address owner, address recipient, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external
The semantics of which are as follows:
For all addresses erc20
, owner
, recipient
, uint256s value
, deadline
and nonce
, uint8 v
, bytes32 r
and s
, a call to permitAndTransferFrom(erc20, owner, recipient, value, deadline, v, r, s)
will call transferFrom(owner, recipient, value)
, increment nonces[owner]
by 1. If and only if the following conditions are met:
- The current blocktime is less than or equal to
deadline
. erc20
is not the zero address. this address must be ERC-20 compliant token address.owner
is not the zero address.nonces[owner]
(before the state update) is equal tononce
.r
,s
andv
is a validsecp256k1
signature fromowner
of the message:
NOTE: spender
in the provided signature must be the same as msg.sender
. recipient
isn’t attested by a signature from owner
, and is instead chosen by msg.sender
, attested in the signature as spender
.
If any of these conditions are not met, the permitAndTransferFrom
call must revert.
keccak256(abi.encodePacked(
hex"1901",
DOMAIN_SEPARATOR,
keccak256(abi.encode(
keccak256("PermitAndTransferFrom(address erc20,address owner,address spender,value,uint256 nonce,uint256 deadline)"),
erc20,
owner,
msg.sender, // NOTE: spender
value,
nonce,
deadline))
))
where DOMAIN_SEPARATOR
is defined according to EIP-712.
In summary the caller of the permitAndTransferFrom
function must be spender
. spender
can choose recipient
.
Rationale
The spender
is not provided in permitAndTransferFrom
paramters. If spender
is not msg.sender
, the transaction will revert.
The recipient
is provided by not the owner
but the spender
. So, the recipient
isn’t attested by a signature.
More details here GitHub - massun-onibakuchi/approval-target