Skip to content

Commit

Permalink
EIP-3009: Reformat, add Rationale section
Browse files Browse the repository at this point in the history
  • Loading branch information
petejkim committed Sep 30, 2020
1 parent a620568 commit e69300f
Showing 1 changed file with 160 additions and 42 deletions.
202 changes: 160 additions & 42 deletions EIPS/eip-3009.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
---
eip: 3009
title: `transferWithAuthorization` - Gas-Abstracted ERC20 transactions with EIP-712
author: Peter Jihoon Kim (@petejkim), Kevin Britz (@kbrizzle), David Knott (@DavidLKnott)
title:
`transferWithAuthorization` - Gas-Abstracted ERC20 transactions with EIP-712
author:
Peter Jihoon Kim (@petejkim), Kevin Britz (@kbrizzle), David Knott
(@DavidLKnott)
discussions-to: https://github.com/ethereum/EIPs/issues/3010
status: Draft
type: Standards Track
Expand All @@ -12,39 +15,74 @@ requires: 20, 712

## Simple Summary

A function called `transferWithAuthorization` to enable gas-abstracted and atomic interactions with [ERC-20](https://eips.ethereum.org/EIPS/eip-20) token contracts via signatures conforming to the [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md) typed message signing specification.
A function called `transferWithAuthorization` to enable gas-abstracted and
atomic interactions with [ERC-20](https://eips.ethereum.org/EIPS/eip-20) token
contracts via signatures conforming to the
[EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md) typed
message signing specification.

This enables the user to:
* delegate the gas payment to someone else,
* pay for gas in the token itself rather than in ETH,
* perform one or more token transfers and other operations in a single atomic transaction,
* transfer ERC-20 tokens to another address, and have the recipient submit the transaction,
* batch multiple transactions with minimal overhead, and
* create and perform multiple transactions without having to worry about them failing due to accidental nonce-reuse or improper ordering by the miner.

The popular USD-backed stablecoin [USDC v2](https://etherscan.io/token/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48) implements an expanded form of this spec. This can also be adopted alongside the [EIP-2612](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2612.md) spec for maximum compatibility with existing applications.
- delegate the gas payment to someone else,
- pay for gas in the token itself rather than in ETH,
- perform one or more token transfers and other operations in a single atomic
transaction,
- transfer ERC-20 tokens to another address, and have the recipient submit the
transaction,
- batch multiple transactions with minimal overhead, and
- create and perform multiple transactions without having to worry about them
failing due to accidental nonce-reuse or improper ordering by the miner.

The popular USD-backed stablecoin
[USDC v2](https://etherscan.io/token/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48)
implements an expanded form of this spec. This can also be adopted alongside the
[EIP-2612](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2612.md) spec
for maximum compatibility with existing applications.

## Abstract

This is a standard that extends the ERC-20 spec by introducing a new function, `transferWithAuthorization`. This function enables users to transfer tokens without also having to submit a transaction and pay for gas themselves. This function also can also be used to transfer tokens and perform another action in a single atomic transaction.
This is a standard that extends the ERC-20 spec by introducing a new function,
`transferWithAuthorization`. This function enables users to transfer tokens
without also having to submit a transaction and pay for gas themselves. This
function also can also be used to transfer tokens and perform another action in
a single atomic transaction.

## Motivation

There is an existing spec, [EIP-2612](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2612.md), that also allows gas-abstracted transactions. The two primary differences between this spec and EIP-2612 are that:

* EIP-2612 uses sequential nonces, but this uses random 32-byte nonces, and that
* EIP-2612 relies on the ERC-20 `approve`/`transferFrom` ("ERC-20 allowance") pattern.

The biggest issue with the use of sequential nonces is that it does not allow users to perform more than one transaction at time without risking their transactions failing, because:

* DApps may unintentionally reuse nonces that have not yet been processed in the blockchain.
* Miners may process the transactions in the incorrect order.

This is especially problematic now that gas prices have become very high and transactions often get queued up and remain unconfirmed for a long time. Non-sequential nonces allow users to create as many transactions as they want at the same time.

The ERC-20 allowance mechanism is susceptible to the [multiple withdrawal attack](https://blockchain-projects.readthedocs.io/multiple_withdrawal.html)/[SWC-114](https://swcregistry.io/docs/SWC-114), and encourages antipatterns such as the use of the "infinite" allowance. The wide-prevalence of upgradeable contracts have made the conditions favorable for these attacks to happen in the wild.

The deficiencies of the ERC-20 allowance pattern brought about the development of alternative token standards such as the [ERC-777](https://eips.ethereum.org/EIPS/eip-777) and [ERC-677](https://github.com/ethereum/EIPs/issues/677). However, they haven't been able to gain much adoption due to compatibility and potential security issues.
There is an existing spec,
[EIP-2612](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2612.md), that
also allows gas-abstracted transactions. The two primary differences between
this spec and EIP-2612 are that:

- EIP-2612 uses sequential nonces, but this uses random 32-byte nonces, and that
- EIP-2612 relies on the ERC-20 `approve`/`transferFrom` ("ERC-20 allowance")
pattern.

The biggest issue with the use of sequential nonces is that it does not allow
users to perform more than one transaction at time without risking their
transactions failing, because:

- DApps may unintentionally reuse nonces that have not yet been processed in the
blockchain.
- Miners may process the transactions in the incorrect order.

This is especially problematic now that gas prices have become very high and
transactions often get queued up and remain unconfirmed for a long time.
Non-sequential nonces allow users to create as many transactions as they want at
the same time.

The ERC-20 allowance mechanism is susceptible to the
[multiple withdrawal attack](https://blockchain-projects.readthedocs.io/multiple_withdrawal.html)/[SWC-114](https://swcregistry.io/docs/SWC-114),
and encourages antipatterns such as the use of the "infinite" allowance. The
wide-prevalence of upgradeable contracts have made the conditions favorable for
these attacks to happen in the wild.

The deficiencies of the ERC-20 allowance pattern brought about the development
of alternative token standards such as the
[ERC-777](https://eips.ethereum.org/EIPS/eip-777) and
[ERC-677](https://github.com/ethereum/EIPs/issues/677). However, they haven't
been able to gain much adoption due to compatibility and potential security
issues.

## Specification

Expand All @@ -59,7 +97,9 @@ function authorizationState(
) external view returns (bool);
```

This mapping keeps track of the nonces of the authorizations that have been used. (`false` = Unused, `true` = Used) Nonces are randomly generated `bytes32` unique to the token holder's address.
This mapping keeps track of the nonces of the authorizations that have been
used. (`false` = Unused, `true` = Used) Nonces are randomly generated `bytes32`
unique to the token holder's address.

### Event

Expand Down Expand Up @@ -105,9 +145,11 @@ function transferWithAuthorization(
) external;
```

The arguments `v`, `r`, and `s` can be obtained using the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) typed message signing spec. EIP-712 ensures that the signatures generated are valid only for this specific instance of the token contract and cannot be replayed on networks with different chain IDs by incorporating the contract address and the chain ID in a Keccak-256 hash digest called the domain separator. The actual set of parameters used to derive the domain separator is up to the implementing contract.
The arguments `v`, `r`, and `s` can be obtained using the
[EIP-712](https://eips.ethereum.org/EIPS/eip-712) typed message signing spec.

**Example:**

```
DomainSeparator := Keccak256(ABIEncode(
Keccak256(
Expand All @@ -120,7 +162,10 @@ DomainSeparator := Keccak256(ABIEncode(
))
```

With the domain separator, the typehash, which is used to identify the type of the EIP712 message being used, and the values of the parameters, you are able to derive a Keccak-256 hash digest which can then be signed using the token holder's private key.
With the domain separator, the typehash, which is used to identify the type of
the EIP712 message being used, and the values of the parameters, you are able to
derive a Keccak-256 hash digest which can then be signed using the token
holder's private key.

**Example:**

Expand All @@ -139,9 +184,13 @@ Digest := Keecak256(
{ v, r, s } := Sign(Digest, PrivateKey)
```

Smart contract functions that wrap the `transferWithAuthorization` call may choose to reduce the number of arguments by accepting the full ABI-encoded set of arguments for the `transferWithAuthorization` call as a single argument of the type `bytes`.
Smart contract functions that wrap the `transferWithAuthorization` call may
choose to reduce the number of arguments by accepting the full ABI-encoded set
of arguments for the `transferWithAuthorization` call as a single argument of
the type `bytes`.

**Example:**

```solidity
// keccak256("transferWithAuthorization(address,address,uint256,uint256,uint256,bytes32,uint8,bytes32,bytes32)")[0:4]
bytes4 private constant _TRANSFER_WITH_AUTHORIZATION_SELECTOR = 0xe3ee160e;
Expand Down Expand Up @@ -170,9 +219,11 @@ function deposit(address token, bytes calldata transferAuthorization)

### Use with web3 providers

The signature for an authorization can be obtained using a web3 provider with the `eth_signTypedData{_v4}` method.
The signature for an authorization can be obtained using a web3 provider with
the `eth_signTypedData{_v4}` method.

**Example (TransferWithAuthorization):**

```javascript
const data = {
types: {
Expand Down Expand Up @@ -213,28 +264,85 @@ const signature = await ethereum.request({
params: [userAddress, JSON.stringify(data)],
});

const v = "0x" + signature.slice(130,132);
const v = "0x" + signature.slice(130, 132);
const r = signature.slice(0, 66);
const s = "0x" + signature.slice(66, 130);
```

## Rationale

_WIP_
### Unique Random Nonce, Instead of Sequential Nonce

- One might say transaction ordering is one reason why sequential nonces are
preferred. However, it is very difficult to achieve in practice for meta
transactions.
- For native Ethereum transactions, when a transaction with a nonce value that
is too-high is submitted to the network, it will stay pending until the
transactions consuming the lower unused nonces are confirmed.
- However, for meta-transactions, when a transaction containing a sequential
nonce value that is either too high or too low is submitted to the smart
contract, it will revert and result in wasted gas.
- The fact that miners can also reorder transactions and include them in the
block in the order they want (assuming each transaction was submitted to the
network by different meta-transaction relayers) also makes it possible for the
transactions to fail even if the nonces used were correct.
- Lastly, when using different applications simultaneously, in absence of some
sort of an off-chain nonce-tracker, it is not possible to determine what the
correct next nonce value is if there exists nonces that are used but haven't
been submitted and confirmed by the network.
- This is especially problematic now that high gas price fluctuations often
cause transactions to "get stuck" in the pool for a long time. Today, if you
make a meta-transaction that uses a sequential nonce from one app, and switch
to another app to make another meta-transaction before the previous one
confirms, the same nonce will be used twice, resulting in one of the
transactions failing.
- In conclusion, the only way to guarantee transaction ordering is for relayers
to submit transactions one at a time, waiting for confirmation between each
submission (and the order in which they should be submitted can be part of
some off-chain metadata), rendering sequential nonce irrelevant.

### Valid After and Valid Before

- Relying on relayers to submit transactions for you means you may not have
exact control over the timing of transaction submission.
- These parameters allow the user to schedule a transaction to be only valid in
the future or before a specific deadline, protecting the user from potential
undesirable effects that may be caused by the submission being made either too
late or too early.

### EIP-712

- EIP-712 ensures that the signatures generated are valid only for this specific
instance of the token contract and cannot be replayed on a different network
with a different chain ID.
- This is achieved by incorporating the contract address and the chain ID in a
Keccak-256 hash digest called the domain separator. The actual set of
parameters used to derive the domain separator is up to the implementing
contract, but it is highly recommended that the fields `verifyingContract` and
`chainId` are included.

## Backwards Compatibility

New contracts benefit from being able to directly utilize `transferWithAuthorization` in order to create atomic transactions, but existing contracts may still rely on the conventional ERC-20 allowance pattern (`approve`/`transferFrom`).
New contracts benefit from being able to directly utilize
`transferWithAuthorization` in order to create atomic transactions, but existing
contracts may still rely on the conventional ERC-20 allowance pattern
(`approve`/`transferFrom`).

In order to add support for `transferWithAuthorization` to existing contracts ("parent contract") that use the ERC-20 allowance pattern, a forwarding contract ("forwarder") can be constructed that takes an authorization and does the following:
In order to add support for `transferWithAuthorization` to existing contracts
("parent contract") that use the ERC-20 allowance pattern, a forwarding contract
("forwarder") can be constructed that takes an authorization and does the
following:

1. Extract the user and deposit amount from the authorization
2. Call `transferWithAuthorization` to transfer specified funds from the user to the forwarder
2. Call `transferWithAuthorization` to transfer specified funds from the user to
the forwarder
3. Approve the parent contract to spend funds from the forwarder
4. Call the method on the parent contract that spends the allowance set from the forwarder
4. Call the method on the parent contract that spends the allowance set from the
forwarder
5. Transfer the ownership of any resulting tokens back to the user

**Example:**

```solidity
interface IDeFiToken {
function deposit(uint256 amount) external returns (uint256);
Expand Down Expand Up @@ -304,14 +412,24 @@ _WIP_

## Implementation

An example implementation can be found in [this repostiory](https://github.com/CoinbaseStablecoin/eip-3009/blob/master/contracts/lib/EIP3009.sol).
In addition to that, [this file](https://github.com/CoinbaseStablecoin/eip-3009/blob/master/contracts/lib/EIP3009Expanded.sol) shows an expanded form this spec, as implemented by the USDC smart contract.
An example implementation can be found in
[this repostiory](https://github.com/CoinbaseStablecoin/eip-3009/blob/master/contracts/lib/EIP3009.sol).
In addition to that,
[this file](https://github.com/CoinbaseStablecoin/eip-3009/blob/master/contracts/lib/EIP3009Expanded.sol)
shows an expanded form this spec, as implemented by the USDC smart contract.

## Security Considerations

Transactions with the same nonce may be submitted to the network but only the first transaction that’s confirmed by the network will be successful. Applications and services utilizing this should always wait for an adequate number of confirmations before treating the transaction as completed.
Transactions with the same nonce may be submitted to the network but only the
first transaction that’s confirmed by the network will be successful.
Applications and services utilizing this should always wait for an adequate
number of confirmations before treating the transaction as completed.

The zero address must be rejected when using `ecrecover` to prevent unauthorized transfers and approvals of funds from the zero address. The built-in `ecrecover` returns the zero address when a malformed signature is provided.
The zero address must be rejected when using `ecrecover` to prevent unauthorized
transfers and approvals of funds from the zero address. The built-in `ecrecover`
returns the zero address when a malformed signature is provided.

## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).

Copyright and related rights waived via
[CC0](https://creativecommons.org/publicdomain/zero/1.0/).

0 comments on commit e69300f

Please sign in to comment.