Skip to content
Prev Previous commit
Next Next commit
expand example
  • Loading branch information
frangio committed Sep 8, 2023
commit c7c46ea645991335ca38c568eec29b333d5db1d4
19 changes: 12 additions & 7 deletions contracts/token/ERC20/extensions/IERC20Permit.sol
Copy link
Contributor

@frangio frangio Sep 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like IERC20Permit is not listed in the docs site. (https://docs.openzeppelin.com/contracts/4.x/api/token/erc20)

I added it in this PR, let's see if it looks nice.

When we have this interface/implementation separation I don't like having duplicate docs in the site. The same applies to I/AccessManager, for example. But if the interface is in the library it should be somewhere in the documentation... so I may have to accept adding it.

Using @inheritdoc leads to more duplication but it might make it nicer to navigate than a link like "See IERC20Permit.permit".

Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,24 @@ pragma solidity ^0.8.20;
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the approval in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a good pattern that can
* be generally recommended is:
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a good pattern that may
* be generally recommended is shown below:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) {
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value); // will use token.transferFrom
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. In general, `address(this)` would
* be used as the `spender` parameter.
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
Expand Down