浏览代码

Update docs

github-actions 2 年之前
父节点
当前提交
390ad640cb

+ 5 - 3
contracts/token/ERC20/README.adoc

@@ -15,11 +15,11 @@ There are a few core contracts that implement the behavior specified in the EIP:
 
 Additionally there are multiple custom extensions, including:
 
+* {ERC20Permit}: gasless approval of tokens (standardized as ERC2612).
 * {ERC20Burnable}: destruction of own tokens.
 * {ERC20Capped}: enforcement of a cap to the total supply when minting tokens.
 * {ERC20Pausable}: ability to pause token transfers.
 * {ERC20Snapshot}: efficient storage of past token balances to be later queried at any point in time.
-* {ERC20Permit}: gasless approval of tokens (standardized as ERC2612).
 * {ERC20FlashMint}: token level support for flash loans through the minting and burning of ephemeral tokens (standardized as ERC3156).
 * {ERC20Votes}: support for voting and vote delegation.
 * {ERC20VotesComp}: support for voting and vote delegation (compatible with Compound's token, with uint96 restrictions).
@@ -43,14 +43,16 @@ NOTE: This core set of contracts is designed to be unopinionated, allowing devel
 
 == Extensions
 
+{{IERC20Permit}}
+
+{{ERC20Permit}}
+
 {{ERC20Burnable}}
 
 {{ERC20Capped}}
 
 {{ERC20Pausable}}
 
-{{ERC20Permit}}
-
 {{ERC20Snapshot}}
 
 {{ERC20Votes}}

+ 3 - 3
contracts/token/ERC20/extensions/ERC20Permit.sol

@@ -44,7 +44,7 @@ abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
     constructor(string memory name) EIP712(name, "1") {}
 
     /**
-     * @dev See {IERC20Permit-permit}.
+     * @inheritdoc IERC20Permit
      */
     function permit(
         address owner,
@@ -68,14 +68,14 @@ abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {
     }
 
     /**
-     * @dev See {IERC20Permit-nonces}.
+     * @inheritdoc IERC20Permit
      */
     function nonces(address owner) public view virtual override returns (uint256) {
         return _nonces[owner].current();
     }
 
     /**
-     * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
+     * @inheritdoc IERC20Permit
      */
     // solhint-disable-next-line func-name-mixedcase
     function DOMAIN_SEPARATOR() external view override returns (bytes32) {

+ 30 - 0
contracts/token/ERC20/extensions/IERC20Permit.sol

@@ -10,6 +10,34 @@ pragma solidity ^0.8.0;
  * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
  * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
  * need to send a transaction, and thus is not required to hold Ether at all.
+ *
+ * ==== Security Considerations
+ *
+ * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
+ * 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 allowance 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 pattern that may be
+ * generally recommended is:
+ *
+ * ```solidity
+ * 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);
+ * }
+ *
+ * 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. (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.
  */
 interface IERC20Permit {
     /**
@@ -32,6 +60,8 @@ interface IERC20Permit {
      * For more information on the signature format, see the
      * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
      * section].
+     *
+     * CAUTION: See Security Considerations above.
      */
     function permit(
         address owner,

+ 302 - 172
docs/modules/api/pages/token/ERC20.adoc

@@ -2,11 +2,11 @@
 :IERC20: pass:normal[xref:token/ERC20.adoc#IERC20[`IERC20`]]
 :IERC20Metadata: pass:normal[xref:token/ERC20.adoc#IERC20Metadata[`IERC20Metadata`]]
 :ERC20: pass:normal[xref:token/ERC20.adoc#ERC20[`ERC20`]]
+:ERC20Permit: pass:normal[xref:token/ERC20.adoc#ERC20Permit[`ERC20Permit`]]
 :ERC20Burnable: pass:normal[xref:token/ERC20.adoc#ERC20Burnable[`ERC20Burnable`]]
 :ERC20Capped: pass:normal[xref:token/ERC20.adoc#ERC20Capped[`ERC20Capped`]]
 :ERC20Pausable: pass:normal[xref:token/ERC20.adoc#ERC20Pausable[`ERC20Pausable`]]
 :ERC20Snapshot: pass:normal[xref:token/ERC20.adoc#ERC20Snapshot[`ERC20Snapshot`]]
-:ERC20Permit: pass:normal[xref:token/ERC20.adoc#ERC20Permit[`ERC20Permit`]]
 :ERC20FlashMint: pass:normal[xref:token/ERC20.adoc#ERC20FlashMint[`ERC20FlashMint`]]
 :ERC20Votes: pass:normal[xref:token/ERC20.adoc#ERC20Votes[`ERC20Votes`]]
 :ERC20VotesComp: pass:normal[xref:token/ERC20.adoc#ERC20VotesComp[`ERC20VotesComp`]]
@@ -70,6 +70,48 @@
 :ERC20: pass:normal[xref:token/ERC20.adoc#ERC20[`ERC20`]]
 :IERC20-approve: pass:normal[xref:token/ERC20.adoc#IERC20-approve-address-uint256-[`IERC20.approve`]]
 :IERC20-approve: pass:normal[xref:token/ERC20.adoc#IERC20-approve-address-uint256-[`IERC20.approve`]]
+:IERC20-allowance: pass:normal[xref:token/ERC20.adoc#IERC20-allowance-address-address-[`IERC20.allowance`]]
+:IERC20-approve: pass:normal[xref:token/ERC20.adoc#IERC20-approve-address-uint256-[`IERC20.approve`]]
+:SafeERC20-safeTransferFrom: pass:normal[xref:token/ERC20.adoc#SafeERC20-safeTransferFrom-contract-IERC20-address-address-uint256-[`SafeERC20.safeTransferFrom`]]
+:xref-IERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-: xref:token/ERC20.adoc#IERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-
+:xref-IERC20Permit-nonces-address-: xref:token/ERC20.adoc#IERC20Permit-nonces-address-
+:xref-IERC20Permit-DOMAIN_SEPARATOR--: xref:token/ERC20.adoc#IERC20Permit-DOMAIN_SEPARATOR--
+:IERC20-approve: pass:normal[xref:token/ERC20.adoc#IERC20-approve-address-uint256-[`IERC20.approve`]]
+:EIP712: pass:normal[xref:utils.adoc#EIP712[`EIP712`]]
+:IERC20-allowance: pass:normal[xref:token/ERC20.adoc#IERC20-allowance-address-address-[`IERC20.allowance`]]
+:IERC20-approve: pass:normal[xref:token/ERC20.adoc#IERC20-approve-address-uint256-[`IERC20.approve`]]
+:xref-ERC20Permit-constructor-string-: xref:token/ERC20.adoc#ERC20Permit-constructor-string-
+:xref-ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-: xref:token/ERC20.adoc#ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-
+:xref-ERC20Permit-nonces-address-: xref:token/ERC20.adoc#ERC20Permit-nonces-address-
+:xref-ERC20Permit-DOMAIN_SEPARATOR--: xref:token/ERC20.adoc#ERC20Permit-DOMAIN_SEPARATOR--
+:xref-ERC20Permit-_useNonce-address-: xref:token/ERC20.adoc#ERC20Permit-_useNonce-address-
+:xref-EIP712-_domainSeparatorV4--: xref:utils.adoc#EIP712-_domainSeparatorV4--
+:xref-EIP712-_hashTypedDataV4-bytes32-: xref:utils.adoc#EIP712-_hashTypedDataV4-bytes32-
+:xref-EIP712-eip712Domain--: xref:utils.adoc#EIP712-eip712Domain--
+:xref-ERC20-name--: xref:token/ERC20.adoc#ERC20-name--
+:xref-ERC20-symbol--: xref:token/ERC20.adoc#ERC20-symbol--
+:xref-ERC20-decimals--: xref:token/ERC20.adoc#ERC20-decimals--
+:xref-ERC20-totalSupply--: xref:token/ERC20.adoc#ERC20-totalSupply--
+:xref-ERC20-balanceOf-address-: xref:token/ERC20.adoc#ERC20-balanceOf-address-
+:xref-ERC20-transfer-address-uint256-: xref:token/ERC20.adoc#ERC20-transfer-address-uint256-
+:xref-ERC20-allowance-address-address-: xref:token/ERC20.adoc#ERC20-allowance-address-address-
+:xref-ERC20-approve-address-uint256-: xref:token/ERC20.adoc#ERC20-approve-address-uint256-
+:xref-ERC20-transferFrom-address-address-uint256-: xref:token/ERC20.adoc#ERC20-transferFrom-address-address-uint256-
+:xref-ERC20-increaseAllowance-address-uint256-: xref:token/ERC20.adoc#ERC20-increaseAllowance-address-uint256-
+:xref-ERC20-decreaseAllowance-address-uint256-: xref:token/ERC20.adoc#ERC20-decreaseAllowance-address-uint256-
+:xref-ERC20-_transfer-address-address-uint256-: xref:token/ERC20.adoc#ERC20-_transfer-address-address-uint256-
+:xref-ERC20-_mint-address-uint256-: xref:token/ERC20.adoc#ERC20-_mint-address-uint256-
+:xref-ERC20-_burn-address-uint256-: xref:token/ERC20.adoc#ERC20-_burn-address-uint256-
+:xref-ERC20-_approve-address-address-uint256-: xref:token/ERC20.adoc#ERC20-_approve-address-address-uint256-
+:xref-ERC20-_spendAllowance-address-address-uint256-: xref:token/ERC20.adoc#ERC20-_spendAllowance-address-address-uint256-
+:xref-ERC20-_beforeTokenTransfer-address-address-uint256-: xref:token/ERC20.adoc#ERC20-_beforeTokenTransfer-address-address-uint256-
+:xref-ERC20-_afterTokenTransfer-address-address-uint256-: xref:token/ERC20.adoc#ERC20-_afterTokenTransfer-address-address-uint256-
+:xref-IERC5267-EIP712DomainChanged--: xref:interfaces.adoc#IERC5267-EIP712DomainChanged--
+:xref-IERC20-Transfer-address-address-uint256-: xref:token/ERC20.adoc#IERC20-Transfer-address-address-uint256-
+:xref-IERC20-Approval-address-address-uint256-: xref:token/ERC20.adoc#IERC20-Approval-address-address-uint256-
+:EIP712: pass:normal[xref:utils.adoc#EIP712[`EIP712`]]
+:IERC20-approve: pass:normal[xref:token/ERC20.adoc#IERC20-approve-address-uint256-[`IERC20.approve`]]
+:EIP712: pass:normal[xref:utils.adoc#EIP712[`EIP712`]]
 :ERC20: pass:normal[xref:token/ERC20.adoc#ERC20[`ERC20`]]
 :xref-ERC20Burnable-burn-uint256-: xref:token/ERC20.adoc#ERC20Burnable-burn-uint256-
 :xref-ERC20Burnable-burnFrom-address-uint256-: xref:token/ERC20.adoc#ERC20Burnable-burnFrom-address-uint256-
@@ -152,41 +194,6 @@
 :xref-IERC20-Transfer-address-address-uint256-: xref:token/ERC20.adoc#IERC20-Transfer-address-address-uint256-
 :xref-IERC20-Approval-address-address-uint256-: xref:token/ERC20.adoc#IERC20-Approval-address-address-uint256-
 :ERC20-_beforeTokenTransfer: pass:normal[xref:token/ERC20.adoc#ERC20-_beforeTokenTransfer-address-address-uint256-[`ERC20._beforeTokenTransfer`]]
-:IERC20-allowance: pass:normal[xref:token/ERC20.adoc#IERC20-allowance-address-address-[`IERC20.allowance`]]
-:IERC20-approve: pass:normal[xref:token/ERC20.adoc#IERC20-approve-address-uint256-[`IERC20.approve`]]
-:xref-ERC20Permit-constructor-string-: xref:token/ERC20.adoc#ERC20Permit-constructor-string-
-:xref-ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-: xref:token/ERC20.adoc#ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-
-:xref-ERC20Permit-nonces-address-: xref:token/ERC20.adoc#ERC20Permit-nonces-address-
-:xref-ERC20Permit-DOMAIN_SEPARATOR--: xref:token/ERC20.adoc#ERC20Permit-DOMAIN_SEPARATOR--
-:xref-ERC20Permit-_useNonce-address-: xref:token/ERC20.adoc#ERC20Permit-_useNonce-address-
-:xref-EIP712-_domainSeparatorV4--: xref:utils.adoc#EIP712-_domainSeparatorV4--
-:xref-EIP712-_hashTypedDataV4-bytes32-: xref:utils.adoc#EIP712-_hashTypedDataV4-bytes32-
-:xref-EIP712-eip712Domain--: xref:utils.adoc#EIP712-eip712Domain--
-:xref-ERC20-name--: xref:token/ERC20.adoc#ERC20-name--
-:xref-ERC20-symbol--: xref:token/ERC20.adoc#ERC20-symbol--
-:xref-ERC20-decimals--: xref:token/ERC20.adoc#ERC20-decimals--
-:xref-ERC20-totalSupply--: xref:token/ERC20.adoc#ERC20-totalSupply--
-:xref-ERC20-balanceOf-address-: xref:token/ERC20.adoc#ERC20-balanceOf-address-
-:xref-ERC20-transfer-address-uint256-: xref:token/ERC20.adoc#ERC20-transfer-address-uint256-
-:xref-ERC20-allowance-address-address-: xref:token/ERC20.adoc#ERC20-allowance-address-address-
-:xref-ERC20-approve-address-uint256-: xref:token/ERC20.adoc#ERC20-approve-address-uint256-
-:xref-ERC20-transferFrom-address-address-uint256-: xref:token/ERC20.adoc#ERC20-transferFrom-address-address-uint256-
-:xref-ERC20-increaseAllowance-address-uint256-: xref:token/ERC20.adoc#ERC20-increaseAllowance-address-uint256-
-:xref-ERC20-decreaseAllowance-address-uint256-: xref:token/ERC20.adoc#ERC20-decreaseAllowance-address-uint256-
-:xref-ERC20-_transfer-address-address-uint256-: xref:token/ERC20.adoc#ERC20-_transfer-address-address-uint256-
-:xref-ERC20-_mint-address-uint256-: xref:token/ERC20.adoc#ERC20-_mint-address-uint256-
-:xref-ERC20-_burn-address-uint256-: xref:token/ERC20.adoc#ERC20-_burn-address-uint256-
-:xref-ERC20-_approve-address-address-uint256-: xref:token/ERC20.adoc#ERC20-_approve-address-address-uint256-
-:xref-ERC20-_spendAllowance-address-address-uint256-: xref:token/ERC20.adoc#ERC20-_spendAllowance-address-address-uint256-
-:xref-ERC20-_beforeTokenTransfer-address-address-uint256-: xref:token/ERC20.adoc#ERC20-_beforeTokenTransfer-address-address-uint256-
-:xref-ERC20-_afterTokenTransfer-address-address-uint256-: xref:token/ERC20.adoc#ERC20-_afterTokenTransfer-address-address-uint256-
-:xref-IERC5267-EIP712DomainChanged--: xref:interfaces.adoc#IERC5267-EIP712DomainChanged--
-:xref-IERC20-Transfer-address-address-uint256-: xref:token/ERC20.adoc#IERC20-Transfer-address-address-uint256-
-:xref-IERC20-Approval-address-address-uint256-: xref:token/ERC20.adoc#IERC20-Approval-address-address-uint256-
-:EIP712: pass:normal[xref:utils.adoc#EIP712[`EIP712`]]
-:IERC20Permit-permit: pass:normal[xref:token/ERC20.adoc#IERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-[`IERC20Permit.permit`]]
-:IERC20Permit-nonces: pass:normal[xref:token/ERC20.adoc#IERC20Permit-nonces-address-[`IERC20Permit.nonces`]]
-:IERC20Permit-DOMAIN_SEPARATOR: pass:normal[xref:token/ERC20.adoc#IERC20Permit-DOMAIN_SEPARATOR--[`IERC20Permit.DOMAIN_SEPARATOR`]]
 :ERC20Votes: pass:normal[xref:token/ERC20.adoc#ERC20Votes[`ERC20Votes`]]
 :xref-ERC20Snapshot-_snapshot--: xref:token/ERC20.adoc#ERC20Snapshot-_snapshot--
 :xref-ERC20Snapshot-_getCurrentSnapshotId--: xref:token/ERC20.adoc#ERC20Snapshot-_getCurrentSnapshotId--
@@ -533,11 +540,11 @@ There are a few core contracts that implement the behavior specified in the EIP:
 
 Additionally there are multiple custom extensions, including:
 
+* {ERC20Permit}: gasless approval of tokens (standardized as ERC2612).
 * {ERC20Burnable}: destruction of own tokens.
 * {ERC20Capped}: enforcement of a cap to the total supply when minting tokens.
 * {ERC20Pausable}: ability to pause token transfers.
 * {ERC20Snapshot}: efficient storage of past token balances to be later queried at any point in time.
-* {ERC20Permit}: gasless approval of tokens (standardized as ERC2612).
 * {ERC20FlashMint}: token level support for flash loans through the minting and burning of ephemeral tokens (standardized as ERC3156).
 * {ERC20Votes}: support for voting and vote delegation.
 * {ERC20VotesComp}: support for voting and vote delegation (compatible with Compound's token, with uint96 restrictions).
@@ -1073,6 +1080,264 @@ To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hook
 
 == Extensions
 
+:permit: pass:normal[xref:#IERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-[`++permit++`]]
+:nonces: pass:normal[xref:#IERC20Permit-nonces-address-[`++nonces++`]]
+:DOMAIN_SEPARATOR: pass:normal[xref:#IERC20Permit-DOMAIN_SEPARATOR--[`++DOMAIN_SEPARATOR++`]]
+
+[.contract]
+[[IERC20Permit]]
+=== `++IERC20Permit++` link:https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.3/contracts/token/ERC20/extensions/IERC20Permit.sol[{github-icon},role=heading-link]
+
+[.hljs-theme-light.nopadding]
+```solidity
+import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
+```
+
+Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
+https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
+
+Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
+presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
+need to send a transaction, and thus is not required to hold Ether at all.
+
+==== Security Considerations
+
+There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
+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 allowance 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 pattern that may be
+generally recommended is:
+
+```solidity
+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);
+}
+
+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. (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.
+
+[.contract-index]
+.Functions
+--
+* {xref-IERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-}[`++permit(owner, spender, value, deadline, v, r, s)++`]
+* {xref-IERC20Permit-nonces-address-}[`++nonces(owner)++`]
+* {xref-IERC20Permit-DOMAIN_SEPARATOR--}[`++DOMAIN_SEPARATOR()++`]
+
+--
+
+[.contract-item]
+[[IERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-]]
+==== `[.contract-item-name]#++permit++#++(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)++` [.item-kind]#external#
+
+Sets `value` as the allowance of `spender` over ``owner``'s tokens,
+given ``owner``'s signed approval.
+
+IMPORTANT: The same issues {IERC20-approve} has related to transaction
+ordering also apply here.
+
+Emits an {Approval} event.
+
+Requirements:
+
+- `spender` cannot be the zero address.
+- `deadline` must be a timestamp in the future.
+- `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
+over the EIP712-formatted function arguments.
+- the signature must use ``owner``'s current nonce (see {nonces}).
+
+For more information on the signature format, see the
+https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
+section].
+
+CAUTION: See Security Considerations above.
+
+[.contract-item]
+[[IERC20Permit-nonces-address-]]
+==== `[.contract-item-name]#++nonces++#++(address owner) → uint256++` [.item-kind]#external#
+
+Returns the current nonce for `owner`. This value must be
+included whenever a signature is generated for {permit}.
+
+Every successful call to {permit} increases ``owner``'s nonce by one. This
+prevents a signature from being used multiple times.
+
+[.contract-item]
+[[IERC20Permit-DOMAIN_SEPARATOR--]]
+==== `[.contract-item-name]#++DOMAIN_SEPARATOR++#++() → bytes32++` [.item-kind]#external#
+
+Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
+
+:constructor: pass:normal[xref:#ERC20Permit-constructor-string-[`++constructor++`]]
+:permit: pass:normal[xref:#ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-[`++permit++`]]
+:nonces: pass:normal[xref:#ERC20Permit-nonces-address-[`++nonces++`]]
+:DOMAIN_SEPARATOR: pass:normal[xref:#ERC20Permit-DOMAIN_SEPARATOR--[`++DOMAIN_SEPARATOR++`]]
+:_useNonce: pass:normal[xref:#ERC20Permit-_useNonce-address-[`++_useNonce++`]]
+
+[.contract]
+[[ERC20Permit]]
+=== `++ERC20Permit++` link:https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.3/contracts/token/ERC20/extensions/ERC20Permit.sol[{github-icon},role=heading-link]
+
+[.hljs-theme-light.nopadding]
+```solidity
+import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
+```
+
+Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
+https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
+
+Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
+presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
+need to send a transaction, and thus is not required to hold Ether at all.
+
+_Available since v3.4._
+
+[.contract-index]
+.Functions
+--
+* {xref-ERC20Permit-constructor-string-}[`++constructor(name)++`]
+* {xref-ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-}[`++permit(owner, spender, value, deadline, v, r, s)++`]
+* {xref-ERC20Permit-nonces-address-}[`++nonces(owner)++`]
+* {xref-ERC20Permit-DOMAIN_SEPARATOR--}[`++DOMAIN_SEPARATOR()++`]
+* {xref-ERC20Permit-_useNonce-address-}[`++_useNonce(owner)++`]
+
+[.contract-subindex-inherited]
+.EIP712
+* {xref-EIP712-_domainSeparatorV4--}[`++_domainSeparatorV4()++`]
+* {xref-EIP712-_hashTypedDataV4-bytes32-}[`++_hashTypedDataV4(structHash)++`]
+* {xref-EIP712-eip712Domain--}[`++eip712Domain()++`]
+
+[.contract-subindex-inherited]
+.IERC5267
+
+[.contract-subindex-inherited]
+.IERC20Permit
+
+[.contract-subindex-inherited]
+.ERC20
+* {xref-ERC20-name--}[`++name()++`]
+* {xref-ERC20-symbol--}[`++symbol()++`]
+* {xref-ERC20-decimals--}[`++decimals()++`]
+* {xref-ERC20-totalSupply--}[`++totalSupply()++`]
+* {xref-ERC20-balanceOf-address-}[`++balanceOf(account)++`]
+* {xref-ERC20-transfer-address-uint256-}[`++transfer(to, amount)++`]
+* {xref-ERC20-allowance-address-address-}[`++allowance(owner, spender)++`]
+* {xref-ERC20-approve-address-uint256-}[`++approve(spender, amount)++`]
+* {xref-ERC20-transferFrom-address-address-uint256-}[`++transferFrom(from, to, amount)++`]
+* {xref-ERC20-increaseAllowance-address-uint256-}[`++increaseAllowance(spender, addedValue)++`]
+* {xref-ERC20-decreaseAllowance-address-uint256-}[`++decreaseAllowance(spender, subtractedValue)++`]
+* {xref-ERC20-_transfer-address-address-uint256-}[`++_transfer(from, to, amount)++`]
+* {xref-ERC20-_mint-address-uint256-}[`++_mint(account, amount)++`]
+* {xref-ERC20-_burn-address-uint256-}[`++_burn(account, amount)++`]
+* {xref-ERC20-_approve-address-address-uint256-}[`++_approve(owner, spender, amount)++`]
+* {xref-ERC20-_spendAllowance-address-address-uint256-}[`++_spendAllowance(owner, spender, amount)++`]
+* {xref-ERC20-_beforeTokenTransfer-address-address-uint256-}[`++_beforeTokenTransfer(from, to, amount)++`]
+* {xref-ERC20-_afterTokenTransfer-address-address-uint256-}[`++_afterTokenTransfer(from, to, amount)++`]
+
+[.contract-subindex-inherited]
+.IERC20Metadata
+
+[.contract-subindex-inherited]
+.IERC20
+
+--
+
+[.contract-index]
+.Events
+--
+
+[.contract-subindex-inherited]
+.EIP712
+
+[.contract-subindex-inherited]
+.IERC5267
+* {xref-IERC5267-EIP712DomainChanged--}[`++EIP712DomainChanged()++`]
+
+[.contract-subindex-inherited]
+.IERC20Permit
+
+[.contract-subindex-inherited]
+.ERC20
+
+[.contract-subindex-inherited]
+.IERC20Metadata
+
+[.contract-subindex-inherited]
+.IERC20
+* {xref-IERC20-Transfer-address-address-uint256-}[`++Transfer(from, to, value)++`]
+* {xref-IERC20-Approval-address-address-uint256-}[`++Approval(owner, spender, value)++`]
+
+--
+
+[.contract-item]
+[[ERC20Permit-constructor-string-]]
+==== `[.contract-item-name]#++constructor++#++(string name)++` [.item-kind]#internal#
+
+Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
+
+It's a good idea to use the same `name` that is defined as the ERC20 token name.
+
+[.contract-item]
+[[ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-]]
+==== `[.contract-item-name]#++permit++#++(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)++` [.item-kind]#public#
+
+Sets `value` as the allowance of `spender` over ``owner``'s tokens,
+given ``owner``'s signed approval.
+
+IMPORTANT: The same issues {IERC20-approve} has related to transaction
+ordering also apply here.
+
+Emits an {Approval} event.
+
+Requirements:
+
+- `spender` cannot be the zero address.
+- `deadline` must be a timestamp in the future.
+- `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
+over the EIP712-formatted function arguments.
+- the signature must use ``owner``'s current nonce (see {nonces}).
+
+For more information on the signature format, see the
+https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
+section].
+
+CAUTION: See Security Considerations above.
+
+[.contract-item]
+[[ERC20Permit-nonces-address-]]
+==== `[.contract-item-name]#++nonces++#++(address owner) → uint256++` [.item-kind]#public#
+
+Returns the current nonce for `owner`. This value must be
+included whenever a signature is generated for {permit}.
+
+Every successful call to {permit} increases ``owner``'s nonce by one. This
+prevents a signature from being used multiple times.
+
+[.contract-item]
+[[ERC20Permit-DOMAIN_SEPARATOR--]]
+==== `[.contract-item-name]#++DOMAIN_SEPARATOR++#++() → bytes32++` [.item-kind]#external#
+
+Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
+
+[.contract-item]
+[[ERC20Permit-_useNonce-address-]]
+==== `[.contract-item-name]#++_useNonce++#++(address owner) → uint256 current++` [.item-kind]#internal#
+
+"Consume a nonce": return the current value and increment.
+
+_Available since v4.1._
+
 :burn: pass:normal[xref:#ERC20Burnable-burn-uint256-[`++burn++`]]
 :burnFrom: pass:normal[xref:#ERC20Burnable-burnFrom-address-uint256-[`++burnFrom++`]]
 
@@ -1345,141 +1610,6 @@ Requirements:
 
 - the contract must not be paused.
 
-:constructor: pass:normal[xref:#ERC20Permit-constructor-string-[`++constructor++`]]
-:permit: pass:normal[xref:#ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-[`++permit++`]]
-:nonces: pass:normal[xref:#ERC20Permit-nonces-address-[`++nonces++`]]
-:DOMAIN_SEPARATOR: pass:normal[xref:#ERC20Permit-DOMAIN_SEPARATOR--[`++DOMAIN_SEPARATOR++`]]
-:_useNonce: pass:normal[xref:#ERC20Permit-_useNonce-address-[`++_useNonce++`]]
-
-[.contract]
-[[ERC20Permit]]
-=== `++ERC20Permit++` link:https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.9.3/contracts/token/ERC20/extensions/ERC20Permit.sol[{github-icon},role=heading-link]
-
-[.hljs-theme-light.nopadding]
-```solidity
-import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";
-```
-
-Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
-https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
-
-Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
-presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
-need to send a transaction, and thus is not required to hold Ether at all.
-
-_Available since v3.4._
-
-[.contract-index]
-.Functions
---
-* {xref-ERC20Permit-constructor-string-}[`++constructor(name)++`]
-* {xref-ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-}[`++permit(owner, spender, value, deadline, v, r, s)++`]
-* {xref-ERC20Permit-nonces-address-}[`++nonces(owner)++`]
-* {xref-ERC20Permit-DOMAIN_SEPARATOR--}[`++DOMAIN_SEPARATOR()++`]
-* {xref-ERC20Permit-_useNonce-address-}[`++_useNonce(owner)++`]
-
-[.contract-subindex-inherited]
-.EIP712
-* {xref-EIP712-_domainSeparatorV4--}[`++_domainSeparatorV4()++`]
-* {xref-EIP712-_hashTypedDataV4-bytes32-}[`++_hashTypedDataV4(structHash)++`]
-* {xref-EIP712-eip712Domain--}[`++eip712Domain()++`]
-
-[.contract-subindex-inherited]
-.IERC5267
-
-[.contract-subindex-inherited]
-.IERC20Permit
-
-[.contract-subindex-inherited]
-.ERC20
-* {xref-ERC20-name--}[`++name()++`]
-* {xref-ERC20-symbol--}[`++symbol()++`]
-* {xref-ERC20-decimals--}[`++decimals()++`]
-* {xref-ERC20-totalSupply--}[`++totalSupply()++`]
-* {xref-ERC20-balanceOf-address-}[`++balanceOf(account)++`]
-* {xref-ERC20-transfer-address-uint256-}[`++transfer(to, amount)++`]
-* {xref-ERC20-allowance-address-address-}[`++allowance(owner, spender)++`]
-* {xref-ERC20-approve-address-uint256-}[`++approve(spender, amount)++`]
-* {xref-ERC20-transferFrom-address-address-uint256-}[`++transferFrom(from, to, amount)++`]
-* {xref-ERC20-increaseAllowance-address-uint256-}[`++increaseAllowance(spender, addedValue)++`]
-* {xref-ERC20-decreaseAllowance-address-uint256-}[`++decreaseAllowance(spender, subtractedValue)++`]
-* {xref-ERC20-_transfer-address-address-uint256-}[`++_transfer(from, to, amount)++`]
-* {xref-ERC20-_mint-address-uint256-}[`++_mint(account, amount)++`]
-* {xref-ERC20-_burn-address-uint256-}[`++_burn(account, amount)++`]
-* {xref-ERC20-_approve-address-address-uint256-}[`++_approve(owner, spender, amount)++`]
-* {xref-ERC20-_spendAllowance-address-address-uint256-}[`++_spendAllowance(owner, spender, amount)++`]
-* {xref-ERC20-_beforeTokenTransfer-address-address-uint256-}[`++_beforeTokenTransfer(from, to, amount)++`]
-* {xref-ERC20-_afterTokenTransfer-address-address-uint256-}[`++_afterTokenTransfer(from, to, amount)++`]
-
-[.contract-subindex-inherited]
-.IERC20Metadata
-
-[.contract-subindex-inherited]
-.IERC20
-
---
-
-[.contract-index]
-.Events
---
-
-[.contract-subindex-inherited]
-.EIP712
-
-[.contract-subindex-inherited]
-.IERC5267
-* {xref-IERC5267-EIP712DomainChanged--}[`++EIP712DomainChanged()++`]
-
-[.contract-subindex-inherited]
-.IERC20Permit
-
-[.contract-subindex-inherited]
-.ERC20
-
-[.contract-subindex-inherited]
-.IERC20Metadata
-
-[.contract-subindex-inherited]
-.IERC20
-* {xref-IERC20-Transfer-address-address-uint256-}[`++Transfer(from, to, value)++`]
-* {xref-IERC20-Approval-address-address-uint256-}[`++Approval(owner, spender, value)++`]
-
---
-
-[.contract-item]
-[[ERC20Permit-constructor-string-]]
-==== `[.contract-item-name]#++constructor++#++(string name)++` [.item-kind]#internal#
-
-Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
-
-It's a good idea to use the same `name` that is defined as the ERC20 token name.
-
-[.contract-item]
-[[ERC20Permit-permit-address-address-uint256-uint256-uint8-bytes32-bytes32-]]
-==== `[.contract-item-name]#++permit++#++(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)++` [.item-kind]#public#
-
-See {IERC20Permit-permit}.
-
-[.contract-item]
-[[ERC20Permit-nonces-address-]]
-==== `[.contract-item-name]#++nonces++#++(address owner) → uint256++` [.item-kind]#public#
-
-See {IERC20Permit-nonces}.
-
-[.contract-item]
-[[ERC20Permit-DOMAIN_SEPARATOR--]]
-==== `[.contract-item-name]#++DOMAIN_SEPARATOR++#++() → bytes32++` [.item-kind]#external#
-
-See {IERC20Permit-DOMAIN_SEPARATOR}.
-
-[.contract-item]
-[[ERC20Permit-_useNonce-address-]]
-==== `[.contract-item-name]#++_useNonce++#++(address owner) → uint256 current++` [.item-kind]#internal#
-
-"Consume a nonce": return the current value and increment.
-
-_Available since v4.1._
-
 :Snapshots: pass:normal[xref:#ERC20Snapshot-Snapshots[`++Snapshots++`]]
 :Snapshot: pass:normal[xref:#ERC20Snapshot-Snapshot-uint256-[`++Snapshot++`]]
 :_snapshot: pass:normal[xref:#ERC20Snapshot-_snapshot--[`++_snapshot++`]]