ERC1363Utils.sol 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  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. /// @solidity memory-safe-assembly
  49. assembly {
  50. revert(add(32, reason), 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. /// @solidity memory-safe-assembly
  82. assembly {
  83. revert(add(32, reason), mload(reason))
  84. }
  85. }
  86. }
  87. }
  88. }