ERC-7550: Transient ERC-20 Approvals

For most up to date discussions please follow the PR: Add ERC: Transient ERC-20 Approvals by Joeysantoro · Pull Request #81 · ethereum/ERCs · GitHub


eip: 7550
title: Transient ERC-20 Approvals
description: Transient ERC-20 approvals via function calls and EIP-712 secp256k1 signatures
author: Joey Santoro (@joeysantoro), Moody Salem (@moodysalem)
discussions-to: TODO
status: Draft
type: Standards Track
category: ERC
created: 2023-10-26
requires: 20, 712, 1153, 2612

Abstract

This standard specifies a time-bound transient ERC-20 token approval mechanism as a cheap augmentation of standard token approval functionality.

It includes a separate transient (single transaction) mapping of transientAllowance which can be set via a transientApprove call or a transientPermit signature.

transientPermit signatures allow the approved contract to spend an unlimited amount of tokens until the specified deadline. The approval is intentionally replayable in order to save an additional SSTORE and remove the need for nonces.

Motivation

ERC-20 approvals empower complex smart contract operation of token balances. These are typically achieved either natively or via ERC-2612 permit.

The allowance of a token is persistent until revoked or used. This has two drawbacks:

  • gas expensive: requires an SSTORE to set and allowance and a second to use it
  • security risk: if an approved contract is later found to be insecure then approved funds are at risk

EIP-1153 Transient Storage allows a parallel cheap approval mechanism which is bound to a single transaction. This simultaneously addresses both issues of persistent allowances.

Specification

Compliant contracts must implement 3 new functions + 1 event in addition to ERC-20 and ERC-2612:

function transientAllowance(address owner, address spender) external view returns (uint)
function transientPermit(address owner, address spender, uint deadline, uint8 v, bytes32 r, bytes32 s) external
function transientApprove(address spender, uint amount) external

event TransientApproval(address indexed _owner, address indexed _spender, uint256 _value)

transientAllowance, transientApprove, and TransientApproval function identically to allowance, approve, Approval respectively, with the caveats that:

  • transientAllowance is uses EIP-1153 transient storage to track transient approvals
  • tokens SHOULD exclusively exhaust the transient allowance before checking or using the persistent allowance for transferFrom.

transientPermit functions as follows:

For all addresses owner, spender, uint256 deadline, uint8 v, bytes32 r and s,
a call to transientPermit(owner, spender, deadline, v, r, s) will set
transientAllowance[owner][spender] to type(uint256).max,
and emit a corresponding TransientApproval event,
if and only if the following conditions are met:

  • The current blocktime is less than or equal to deadline.
  • owner is not the zero address.
  • r, s and v is a valid secp256k1 signature from owner of the message:

If any of these conditions are not met, the transientPermit call must revert.

keccak256(abi.encodePacked(
   hex"1901",
   DOMAIN_SEPARATOR,
   keccak256(abi.encode(
            keccak256("TransientPermit(address owner,address spender,uint256 deadline)"),
            owner,
            spender,
            deadline))
))

where DOMAIN_SEPARATOR is defined according to EIP-712. The DOMAIN_SEPARATOR should be unique to the contract and chain to prevent replay attacks from other domains,
and satisfy the requirements of EIP-712, but is otherwise unconstrained.
A common choice for DOMAIN_SEPARATOR is:

DOMAIN_SEPARATOR = keccak256(
    abi.encode(
        keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
        keccak256(bytes(name)),
        keccak256(bytes(version)),
        chainid,
        address(this)
));

In other words, the message is the EIP-712 typed structure:

{
  "types": {
    "EIP712Domain": [
      {
        "name": "name",
        "type": "string"
      },
      {
        "name": "version",
        "type": "string"
      },
      {
        "name": "chainId",
        "type": "uint256"
      },
      {
        "name": "verifyingContract",
        "type": "address"
      }
    ],
    "TransientPermit": [
      {
        "name": "owner",
        "type": "address"
      },
      {
        "name": "spender",
        "type": "address"
      },
      {
        "name": "deadline",
        "type": "uint256"
      }
    ],
  },
  "primaryType": "TransientPermit",
  "domain": {
    "name": erc20name,
    "version": version,
    "chainId": chainid,
    "verifyingContract": tokenAddress
  },
  "message": {
    "owner": owner,
    "spender": spender,
    "deadline": deadline
  }
}

Note that nowhere in this definition we refer to msg.sender. The caller of the transientPermit function can be any address.

Rationale

The main design changes from ERC-20 and ERC-2612 revolve around the decision to not include nonce or value in transientPermit.

The entire point of the transient approval mechnism is to provide an ultra cheap alternative to persistent approvals. Therefore, removing the usage of nonce (which require an additional SSTORE) is in line with the goal of making transient approvals as cheap as possible. The security tradeoffs of removing replay protection are worth it because users can simply use persistent approvals where security is of higher concern.

Because transient permit can be replayed, the value argument becomes useless and even misleading as it provides a false sense of security. Therefore only unlimited transientPermit is allowed.

Backwards Compatibility

Transient Approval is fully backwards compatible with ERC-20, ERC-2612 and all other known EIPs and contracts.

Security Considerations

All security considerations of EIP-2612 apply to TransientPermit.

Additionally, due to the lack of replay protection from the non-inclusion of nonces it is strongly recommended to use tight time bounds on any TransientPermit signatures.

If an unlimited transient approval is signed intentionally or unintentionally, it can be witheld indefinitely by any Relayer effectively acting as a secret approval not visible to the signer in any way.

Copyright

Copyright and related rights waived via CC0.

1 Like

@joeysantoro has there been any more discussion on this?

In my opinion it would be really great in general if there would be a public good similar to weth that would wrap erc20 tokens to make them erc-7550 compliant. Same for ERC-4626 tokens.

Some benefits of this from an end user perspective:

  • 10-50x cheaper lending borrowing platforms on Ethereum mainnet
  • 10-50x cheaper flashloans
  • 10-50x cheaper swaps.
1 Like