ERC1363Utils.sol 3.1 KB

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