Prechádzať zdrojové kódy

Create a ERC1363Utils helper similar to existing ERC721Utils and ERC1155Utils (#5133)

Co-authored-by: Ernesto García <ernestognw@gmail.com>
Co-authored-by: cairo <cairoeth@protonmail.com>
Hadrien Croubois 1 rok pred
rodič
commit
aec36ddd6a

+ 5 - 0
.changeset/tricky-bats-pretend.md

@@ -0,0 +1,5 @@
+---
+'openzeppelin-solidity': minor
+---
+
+`ERC1363Utils`: Add helper similar to the existing `ERC721Utils` and `ERC1155Utils`

+ 2 - 0
contracts/token/ERC1155/README.adoc

@@ -39,3 +39,5 @@ NOTE: This core set of contracts is designed to be unopinionated, allowing devel
 == Utilities
 
 {{ERC1155Holder}}
+
+{{ERC1155Utils}}

+ 2 - 0
contracts/token/ERC20/README.adoc

@@ -71,3 +71,5 @@ NOTE: This core set of contracts is designed to be unopinionated, allowing devel
 == Utilities
 
 {{SafeERC20}}
+
+{{ERC1363Utils}}

+ 4 - 78
contracts/token/ERC20/extensions/ERC1363.sol

@@ -4,10 +4,8 @@ pragma solidity ^0.8.20;
 
 import {ERC20} from "../ERC20.sol";
 import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol";
-
 import {IERC1363} from "../../../interfaces/IERC1363.sol";
-import {IERC1363Receiver} from "../../../interfaces/IERC1363Receiver.sol";
-import {IERC1363Spender} from "../../../interfaces/IERC1363Spender.sol";
+import {ERC1363Utils} from "../utils/ERC1363Utils.sol";
 
 /**
  * @title ERC1363
@@ -16,18 +14,6 @@ import {IERC1363Spender} from "../../../interfaces/IERC1363Spender.sol";
  * {ERC1363-transferFromAndCall} methods while calls after approvals can be made with {ERC1363-approveAndCall}
  */
 abstract contract ERC1363 is ERC20, ERC165, IERC1363 {
-    /**
-     * @dev Indicates a failure with the token `receiver`. Used in transfers.
-     * @param receiver Address to which tokens are being transferred.
-     */
-    error ERC1363InvalidReceiver(address receiver);
-
-    /**
-     * @dev Indicates a failure with the token `spender`. Used in approvals.
-     * @param spender Address that may be allowed to operate on tokens without being their owner.
-     */
-    error ERC1363InvalidSpender(address spender);
-
     /**
      * @dev Indicates a failure within the {transfer} part of a transferAndCall operation.
      * @param receiver Address to which tokens are being transferred.
@@ -80,7 +66,7 @@ abstract contract ERC1363 is ERC20, ERC165, IERC1363 {
         if (!transfer(to, value)) {
             revert ERC1363TransferFailed(to, value);
         }
-        _checkOnTransferReceived(_msgSender(), to, value, data);
+        ERC1363Utils.checkOnERC1363TransferReceived(_msgSender(), _msgSender(), to, value, data);
         return true;
     }
 
@@ -112,7 +98,7 @@ abstract contract ERC1363 is ERC20, ERC165, IERC1363 {
         if (!transferFrom(from, to, value)) {
             revert ERC1363TransferFromFailed(from, to, value);
         }
-        _checkOnTransferReceived(from, to, value, data);
+        ERC1363Utils.checkOnERC1363TransferReceived(_msgSender(), from, to, value, data);
         return true;
     }
 
@@ -139,67 +125,7 @@ abstract contract ERC1363 is ERC20, ERC165, IERC1363 {
         if (!approve(spender, value)) {
             revert ERC1363ApproveFailed(spender, value);
         }
-        _checkOnApprovalReceived(spender, value, data);
+        ERC1363Utils.checkOnERC1363ApprovalReceived(_msgSender(), spender, value, data);
         return true;
     }
-
-    /**
-     * @dev Performs a call to {IERC1363Receiver-onTransferReceived} on a target address.
-     *
-     * Requirements:
-     *
-     * - The target has code (i.e. is a contract).
-     * - The target `to` must implement the {IERC1363Receiver} interface.
-     * - The target must return the {IERC1363Receiver-onTransferReceived} selector to accept the transfer.
-     */
-    function _checkOnTransferReceived(address from, address to, uint256 value, bytes memory data) private {
-        if (to.code.length == 0) {
-            revert ERC1363InvalidReceiver(to);
-        }
-
-        try IERC1363Receiver(to).onTransferReceived(_msgSender(), from, value, data) returns (bytes4 retval) {
-            if (retval != IERC1363Receiver.onTransferReceived.selector) {
-                revert ERC1363InvalidReceiver(to);
-            }
-        } catch (bytes memory reason) {
-            if (reason.length == 0) {
-                revert ERC1363InvalidReceiver(to);
-            } else {
-                /// @solidity memory-safe-assembly
-                assembly {
-                    revert(add(32, reason), mload(reason))
-                }
-            }
-        }
-    }
-
-    /**
-     * @dev Performs a call to {IERC1363Spender-onApprovalReceived} on a target address.
-     *
-     * Requirements:
-     *
-     * - The target has code (i.e. is a contract).
-     * - The target `spender` must implement the {IERC1363Spender} interface.
-     * - The target must return the {IERC1363Spender-onApprovalReceived} selector to accept the approval.
-     */
-    function _checkOnApprovalReceived(address spender, uint256 value, bytes memory data) private {
-        if (spender.code.length == 0) {
-            revert ERC1363InvalidSpender(spender);
-        }
-
-        try IERC1363Spender(spender).onApprovalReceived(_msgSender(), value, data) returns (bytes4 retval) {
-            if (retval != IERC1363Spender.onApprovalReceived.selector) {
-                revert ERC1363InvalidSpender(spender);
-            }
-        } catch (bytes memory reason) {
-            if (reason.length == 0) {
-                revert ERC1363InvalidSpender(spender);
-            } else {
-                /// @solidity memory-safe-assembly
-                assembly {
-                    revert(add(32, reason), mload(reason))
-                }
-            }
-        }
-    }
 }

+ 96 - 0
contracts/token/ERC20/utils/ERC1363Utils.sol

@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: MIT
+
+pragma solidity ^0.8.20;
+
+import {IERC1363Receiver} from "../../../interfaces/IERC1363Receiver.sol";
+import {IERC1363Spender} from "../../../interfaces/IERC1363Spender.sol";
+
+/**
+ * @dev Library that provides common ERC-1363 utility functions.
+ *
+ * See https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
+ */
+library ERC1363Utils {
+    /**
+     * @dev Indicates a failure with the token `receiver`. Used in transfers.
+     * @param receiver Address to which tokens are being transferred.
+     */
+    error ERC1363InvalidReceiver(address receiver);
+
+    /**
+     * @dev Indicates a failure with the token `spender`. Used in approvals.
+     * @param spender Address that may be allowed to operate on tokens without being their owner.
+     */
+    error ERC1363InvalidSpender(address spender);
+
+    /**
+     * @dev Performs a call to {IERC1363Receiver-onTransferReceived} on a target address.
+     *
+     * Requirements:
+     *
+     * - The target has code (i.e. is a contract).
+     * - The target `to` must implement the {IERC1363Receiver} interface.
+     * - The target must return the {IERC1363Receiver-onTransferReceived} selector to accept the transfer.
+     */
+    function checkOnERC1363TransferReceived(
+        address operator,
+        address from,
+        address to,
+        uint256 value,
+        bytes memory data
+    ) internal {
+        if (to.code.length == 0) {
+            revert ERC1363InvalidReceiver(to);
+        }
+
+        try IERC1363Receiver(to).onTransferReceived(operator, from, value, data) returns (bytes4 retval) {
+            if (retval != IERC1363Receiver.onTransferReceived.selector) {
+                revert ERC1363InvalidReceiver(to);
+            }
+        } catch (bytes memory reason) {
+            if (reason.length == 0) {
+                revert ERC1363InvalidReceiver(to);
+            } else {
+                /// @solidity memory-safe-assembly
+                assembly {
+                    revert(add(32, reason), mload(reason))
+                }
+            }
+        }
+    }
+
+    /**
+     * @dev Performs a call to {IERC1363Spender-onApprovalReceived} on a target address.
+     *
+     * Requirements:
+     *
+     * - The target has code (i.e. is a contract).
+     * - The target `spender` must implement the {IERC1363Spender} interface.
+     * - The target must return the {IERC1363Spender-onApprovalReceived} selector to accept the approval.
+     */
+    function checkOnERC1363ApprovalReceived(
+        address operator,
+        address spender,
+        uint256 value,
+        bytes memory data
+    ) internal {
+        if (spender.code.length == 0) {
+            revert ERC1363InvalidSpender(spender);
+        }
+
+        try IERC1363Spender(spender).onApprovalReceived(operator, value, data) returns (bytes4 retval) {
+            if (retval != IERC1363Spender.onApprovalReceived.selector) {
+                revert ERC1363InvalidSpender(spender);
+            }
+        } catch (bytes memory reason) {
+            if (reason.length == 0) {
+                revert ERC1363InvalidSpender(spender);
+            } else {
+                /// @solidity memory-safe-assembly
+                assembly {
+                    revert(add(32, reason), mload(reason))
+                }
+            }
+        }
+    }
+}

+ 2 - 0
contracts/token/ERC721/README.adoc

@@ -65,3 +65,5 @@ NOTE: This core set of contracts is designed to be unopinionated, allowing devel
 == Utilities
 
 {{ERC721Holder}}
+
+{{ERC721Utils}}