Skip to content

Commit aec36dd

Browse files
Amxxernestognwcairoeth
authored
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>
1 parent e3786e6 commit aec36dd

File tree

6 files changed

+111
-78
lines changed

6 files changed

+111
-78
lines changed

.changeset/tricky-bats-pretend.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'openzeppelin-solidity': minor
3+
---
4+
5+
`ERC1363Utils`: Add helper similar to the existing `ERC721Utils` and `ERC1155Utils`

contracts/token/ERC1155/README.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,5 @@ NOTE: This core set of contracts is designed to be unopinionated, allowing devel
3939
== Utilities
4040

4141
{{ERC1155Holder}}
42+
43+
{{ERC1155Utils}}

contracts/token/ERC20/README.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,5 @@ NOTE: This core set of contracts is designed to be unopinionated, allowing devel
7171
== Utilities
7272

7373
{{SafeERC20}}
74+
75+
{{ERC1363Utils}}

contracts/token/ERC20/extensions/ERC1363.sol

Lines changed: 4 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ pragma solidity ^0.8.20;
44

55
import {ERC20} from "../ERC20.sol";
66
import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol";
7-
87
import {IERC1363} from "../../../interfaces/IERC1363.sol";
9-
import {IERC1363Receiver} from "../../../interfaces/IERC1363Receiver.sol";
10-
import {IERC1363Spender} from "../../../interfaces/IERC1363Spender.sol";
8+
import {ERC1363Utils} from "../utils/ERC1363Utils.sol";
119

1210
/**
1311
* @title ERC1363
@@ -16,18 +14,6 @@ import {IERC1363Spender} from "../../../interfaces/IERC1363Spender.sol";
1614
* {ERC1363-transferFromAndCall} methods while calls after approvals can be made with {ERC1363-approveAndCall}
1715
*/
1816
abstract contract ERC1363 is ERC20, ERC165, IERC1363 {
19-
/**
20-
* @dev Indicates a failure with the token `receiver`. Used in transfers.
21-
* @param receiver Address to which tokens are being transferred.
22-
*/
23-
error ERC1363InvalidReceiver(address receiver);
24-
25-
/**
26-
* @dev Indicates a failure with the token `spender`. Used in approvals.
27-
* @param spender Address that may be allowed to operate on tokens without being their owner.
28-
*/
29-
error ERC1363InvalidSpender(address spender);
30-
3117
/**
3218
* @dev Indicates a failure within the {transfer} part of a transferAndCall operation.
3319
* @param receiver Address to which tokens are being transferred.
@@ -80,7 +66,7 @@ abstract contract ERC1363 is ERC20, ERC165, IERC1363 {
8066
if (!transfer(to, value)) {
8167
revert ERC1363TransferFailed(to, value);
8268
}
83-
_checkOnTransferReceived(_msgSender(), to, value, data);
69+
ERC1363Utils.checkOnERC1363TransferReceived(_msgSender(), _msgSender(), to, value, data);
8470
return true;
8571
}
8672

@@ -112,7 +98,7 @@ abstract contract ERC1363 is ERC20, ERC165, IERC1363 {
11298
if (!transferFrom(from, to, value)) {
11399
revert ERC1363TransferFromFailed(from, to, value);
114100
}
115-
_checkOnTransferReceived(from, to, value, data);
101+
ERC1363Utils.checkOnERC1363TransferReceived(_msgSender(), from, to, value, data);
116102
return true;
117103
}
118104

@@ -139,67 +125,7 @@ abstract contract ERC1363 is ERC20, ERC165, IERC1363 {
139125
if (!approve(spender, value)) {
140126
revert ERC1363ApproveFailed(spender, value);
141127
}
142-
_checkOnApprovalReceived(spender, value, data);
128+
ERC1363Utils.checkOnERC1363ApprovalReceived(_msgSender(), spender, value, data);
143129
return true;
144130
}
145-
146-
/**
147-
* @dev Performs a call to {IERC1363Receiver-onTransferReceived} on a target address.
148-
*
149-
* Requirements:
150-
*
151-
* - The target has code (i.e. is a contract).
152-
* - The target `to` must implement the {IERC1363Receiver} interface.
153-
* - The target must return the {IERC1363Receiver-onTransferReceived} selector to accept the transfer.
154-
*/
155-
function _checkOnTransferReceived(address from, address to, uint256 value, bytes memory data) private {
156-
if (to.code.length == 0) {
157-
revert ERC1363InvalidReceiver(to);
158-
}
159-
160-
try IERC1363Receiver(to).onTransferReceived(_msgSender(), from, value, data) returns (bytes4 retval) {
161-
if (retval != IERC1363Receiver.onTransferReceived.selector) {
162-
revert ERC1363InvalidReceiver(to);
163-
}
164-
} catch (bytes memory reason) {
165-
if (reason.length == 0) {
166-
revert ERC1363InvalidReceiver(to);
167-
} else {
168-
/// @solidity memory-safe-assembly
169-
assembly {
170-
revert(add(32, reason), mload(reason))
171-
}
172-
}
173-
}
174-
}
175-
176-
/**
177-
* @dev Performs a call to {IERC1363Spender-onApprovalReceived} on a target address.
178-
*
179-
* Requirements:
180-
*
181-
* - The target has code (i.e. is a contract).
182-
* - The target `spender` must implement the {IERC1363Spender} interface.
183-
* - The target must return the {IERC1363Spender-onApprovalReceived} selector to accept the approval.
184-
*/
185-
function _checkOnApprovalReceived(address spender, uint256 value, bytes memory data) private {
186-
if (spender.code.length == 0) {
187-
revert ERC1363InvalidSpender(spender);
188-
}
189-
190-
try IERC1363Spender(spender).onApprovalReceived(_msgSender(), value, data) returns (bytes4 retval) {
191-
if (retval != IERC1363Spender.onApprovalReceived.selector) {
192-
revert ERC1363InvalidSpender(spender);
193-
}
194-
} catch (bytes memory reason) {
195-
if (reason.length == 0) {
196-
revert ERC1363InvalidSpender(spender);
197-
} else {
198-
/// @solidity memory-safe-assembly
199-
assembly {
200-
revert(add(32, reason), mload(reason))
201-
}
202-
}
203-
}
204-
}
205131
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.20;
4+
5+
import {IERC1363Receiver} from "../../../interfaces/IERC1363Receiver.sol";
6+
import {IERC1363Spender} from "../../../interfaces/IERC1363Spender.sol";
7+
8+
/**
9+
* @dev Library that provides common ERC-1363 utility functions.
10+
*
11+
* See https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
12+
*/
13+
library ERC1363Utils {
14+
/**
15+
* @dev Indicates a failure with the token `receiver`. Used in transfers.
16+
* @param receiver Address to which tokens are being transferred.
17+
*/
18+
error ERC1363InvalidReceiver(address receiver);
19+
20+
/**
21+
* @dev Indicates a failure with the token `spender`. Used in approvals.
22+
* @param spender Address that may be allowed to operate on tokens without being their owner.
23+
*/
24+
error ERC1363InvalidSpender(address spender);
25+
26+
/**
27+
* @dev Performs a call to {IERC1363Receiver-onTransferReceived} on a target address.
28+
*
29+
* Requirements:
30+
*
31+
* - The target has code (i.e. is a contract).
32+
* - The target `to` must implement the {IERC1363Receiver} interface.
33+
* - The target must return the {IERC1363Receiver-onTransferReceived} selector to accept the transfer.
34+
*/
35+
function checkOnERC1363TransferReceived(
36+
address operator,
37+
address from,
38+
address to,
39+
uint256 value,
40+
bytes memory data
41+
) internal {
42+
if (to.code.length == 0) {
43+
revert ERC1363InvalidReceiver(to);
44+
}
45+
46+
try IERC1363Receiver(to).onTransferReceived(operator, from, value, data) returns (bytes4 retval) {
47+
if (retval != IERC1363Receiver.onTransferReceived.selector) {
48+
revert ERC1363InvalidReceiver(to);
49+
}
50+
} catch (bytes memory reason) {
51+
if (reason.length == 0) {
52+
revert ERC1363InvalidReceiver(to);
53+
} else {
54+
/// @solidity memory-safe-assembly
55+
assembly {
56+
revert(add(32, reason), mload(reason))
57+
}
58+
}
59+
}
60+
}
61+
62+
/**
63+
* @dev Performs a call to {IERC1363Spender-onApprovalReceived} on a target address.
64+
*
65+
* Requirements:
66+
*
67+
* - The target has code (i.e. is a contract).
68+
* - The target `spender` must implement the {IERC1363Spender} interface.
69+
* - The target must return the {IERC1363Spender-onApprovalReceived} selector to accept the approval.
70+
*/
71+
function checkOnERC1363ApprovalReceived(
72+
address operator,
73+
address spender,
74+
uint256 value,
75+
bytes memory data
76+
) internal {
77+
if (spender.code.length == 0) {
78+
revert ERC1363InvalidSpender(spender);
79+
}
80+
81+
try IERC1363Spender(spender).onApprovalReceived(operator, value, data) returns (bytes4 retval) {
82+
if (retval != IERC1363Spender.onApprovalReceived.selector) {
83+
revert ERC1363InvalidSpender(spender);
84+
}
85+
} catch (bytes memory reason) {
86+
if (reason.length == 0) {
87+
revert ERC1363InvalidSpender(spender);
88+
} else {
89+
/// @solidity memory-safe-assembly
90+
assembly {
91+
revert(add(32, reason), mload(reason))
92+
}
93+
}
94+
}
95+
}
96+
}

contracts/token/ERC721/README.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,5 @@ NOTE: This core set of contracts is designed to be unopinionated, allowing devel
6565
== Utilities
6666

6767
{{ERC721Holder}}
68+
69+
{{ERC721Utils}}

0 commit comments

Comments
 (0)