ERC1363Utils.sol 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/utils/ERC1363Utils.sol)
  3. pragma solidity ^0.8.20;
  4. import {IERC1363Receiver} from "../../../interfaces/IERC1363Receiver.sol";
  5. import {IERC1363Spender} from "../../../interfaces/IERC1363Spender.sol";
  6. /**
  7. * @dev Library that provides common ERC-1363 utility functions.
  8. *
  9. * See https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
  10. */
  11. library ERC1363Utils {
  12. /**
  13. * @dev Indicates a failure with the token `receiver`. Used in transfers.
  14. * @param receiver Address to which tokens are being transferred.
  15. */
  16. error ERC1363InvalidReceiver(address receiver);
  17. /**
  18. * @dev Indicates a failure with the token `spender`. Used in approvals.
  19. * @param spender Address that may be allowed to operate on tokens without being their owner.
  20. */
  21. error ERC1363InvalidSpender(address spender);
  22. /**
  23. * @dev Performs a call to {IERC1363Receiver-onTransferReceived} on a target address.
  24. *
  25. * Requirements:
  26. *
  27. * - The target has code (i.e. is a contract).
  28. * - The target `to` must implement the {IERC1363Receiver} interface.
  29. * - The target must return the {IERC1363Receiver-onTransferReceived} selector to accept the transfer.
  30. */
  31. function checkOnERC1363TransferReceived(
  32. address operator,
  33. address from,
  34. address to,
  35. uint256 value,
  36. bytes memory data
  37. ) internal {
  38. if (to.code.length == 0) {
  39. revert ERC1363InvalidReceiver(to);
  40. }
  41. try IERC1363Receiver(to).onTransferReceived(operator, from, value, data) returns (bytes4 retval) {
  42. if (retval != IERC1363Receiver.onTransferReceived.selector) {
  43. revert ERC1363InvalidReceiver(to);
  44. }
  45. } catch (bytes memory reason) {
  46. if (reason.length == 0) {
  47. revert ERC1363InvalidReceiver(to);
  48. } else {
  49. assembly ("memory-safe") {
  50. revert(add(reason, 0x20), mload(reason))
  51. }
  52. }
  53. }
  54. }
  55. /**
  56. * @dev Performs a call to {IERC1363Spender-onApprovalReceived} on a target address.
  57. *
  58. * Requirements:
  59. *
  60. * - The target has code (i.e. is a contract).
  61. * - The target `spender` must implement the {IERC1363Spender} interface.
  62. * - The target must return the {IERC1363Spender-onApprovalReceived} selector to accept the approval.
  63. */
  64. function checkOnERC1363ApprovalReceived(
  65. address operator,
  66. address spender,
  67. uint256 value,
  68. bytes memory data
  69. ) internal {
  70. if (spender.code.length == 0) {
  71. revert ERC1363InvalidSpender(spender);
  72. }
  73. try IERC1363Spender(spender).onApprovalReceived(operator, value, data) returns (bytes4 retval) {
  74. if (retval != IERC1363Spender.onApprovalReceived.selector) {
  75. revert ERC1363InvalidSpender(spender);
  76. }
  77. } catch (bytes memory reason) {
  78. if (reason.length == 0) {
  79. revert ERC1363InvalidSpender(spender);
  80. } else {
  81. assembly ("memory-safe") {
  82. revert(add(reason, 0x20), mload(reason))
  83. }
  84. }
  85. }
  86. }
  87. }