Skip to content

Commit

Permalink
Add ERC: Signature Validation Extension for Permit
Browse files Browse the repository at this point in the history
Merged by EIP-Bot.
  • Loading branch information
yvonnezhangc authored Jul 3, 2024
1 parent a066efe commit cfcf8e0
Showing 1 changed file with 134 additions and 0 deletions.
134 changes: 134 additions & 0 deletions ERCS/erc-7597.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
---
eip: 7597
title: Signature Validation Extension for Permit
description: An ERC to extend ERC-2612 Permit to support ERC-1271-based signature validation.
author: Yvonne Zhang (@yvonnezhangc), Aloysius Chan (@circle-aloychan)
discussions-to: https://ethereum-magicians.org/t/add-erc-contract-signature-validation-extension-for-eip-2612-permit/18157
status: Draft
type: Standards Track
category: ERC
created: 2024-01-15
requires: 1271, 2612
---

# EIP: Contract signature validation extension for [ERC-2612](./eip-2612.md) Permit

## Abstract

This proposal aims to extend the functionality of the existing [ERC-2612](./eip-2612.md) Permit to support gasless [ERC-20](./eip-20.md) approval operations initiated by smart contract wallets.

## Motivation

The current signature validation scheme in [ERC-2612](./eip-2612.md), based on V, R, S parameters, restricts signature validation to EOA wallets.

With the growing popularity of smart contract wallets and increased adoption of [ERC-1271](./eip-1271.md), it is necessary to allow for flexible signature validation methods and the use of custom logic in each contract's signature verification. By accepting unstructured signature bytes as input, custom algorithms and signature schemes can be utilized, enabling a wider range of wallet types.

## Specification

Compliant contracts must implement the `permit` using the following spec

```
function permit(address owner, address spender, uint value, uint deadline, bytes memory signature) external
```
as well as two other interfaces previously mandated by [ERC-2612](./eip-2612.md):
```
function nonces(address owner) external view returns (uint)
function DOMAIN_SEPARATOR() external view returns (bytes32)
```

A call to `permit(owner, spender, value, deadline, signature)` will set `allowance[owner][spender]` to value, increment `nonces[owner]` by 1, and emit a corresponding `Approval` 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.
- `nonces[owner]` (before the state update) is equal to nonce.
- `signature` validation:
- If `owner` is an EOA, `signature` is a valid secp256k1 signature in the form of `abi.encodePacked(r, s, v)`.
- If `owner` is a contract, `signature` is validated by calling `isValidSignature()` on the `owner` contract.

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

## Rationale

By replacing the existing V, R, S signature validation scheme and introducing support for unstructured bytes input, contract developers can use a unified interface to validate signature from both EOAs and SC wallets. This allows for the utilization of different signature schemes and algorithms fitting the wallet type, paving the way for smart contract wallets and advanced wallet types to enhance their signature validation processes, promoting flexibility and innovation.

## Backwards Compatibility

This proposal is fully backward-compatible with the existing ERC-2612 standard. Contracts that currently rely on the V, R, S signature validation scheme will continue to function without any issues.

If both V, R, S signature validation and the new unstructured bytes signature validation need to be supported for backward compatibility reasons, developers can reduce duplicates by adapting the following code block as an example:

```
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external {
_permit(owner, spender, value, deadline, abi.encodePacked(r, s, v));
}
```

## Reference Implementation

Sample `permit` implemented with OZ's SignatureChecker

```solidity
/**
* @notice Update allowance with a signed permit
* @dev Signature bytes can be used for both EOA wallets and contract wallets.
* @param owner Token owner's address (Authorizer)
* @param spender Spender's address
* @param value Amount of allowance
* @param deadline The time at which the signature expires (unix time)
* @param signature Unstructured bytes signature signed by an EOA wallet or a contract wallet
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
bytes memory signature
) external {
require(deadline >= now, "Permit is expired");
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
bytes32 digest = keccak256(abi.encodePacked(
hex"1901",
DOMAIN_SEPARATOR,
keccak256(abi.encode(
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"),
owner,
spender,
value,
nonce,
deadline
))
));
require(
// Check for both ECDSA signature and and ERC-1271 signature. A sample SignatureChecker is available at
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/7bd2b2a/contracts/utils/cryptography/SignatureChecker.sol
SignatureChecker.isValidSignatureNow(
owner,
typedDataHash,
signature
),
"Invalid signature"
);
allowed[owner][spender] = value;
emit Approval(owner, spender, value);
}
```

## Security Considerations

- For contract wallets, the security of `permit` relies on `isValidSignature()` to ensure the signature bytes represent the desired execution from contract wallet owner(s). Contract wallet developers must exercise caution when implementing custom signature validation logic to ensure the security of their contracts.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).

0 comments on commit cfcf8e0

Please sign in to comment.