ERC1363.sol 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. // SPDX-License-Identifier: MIT
  2. // OpenZeppelin Contracts (last updated v5.1.0-rc.0) (token/ERC20/extensions/ERC1363.sol)
  3. pragma solidity ^0.8.20;
  4. import {ERC20} from "../ERC20.sol";
  5. import {IERC165, ERC165} from "../../../utils/introspection/ERC165.sol";
  6. import {IERC1363} from "../../../interfaces/IERC1363.sol";
  7. import {IERC1363Receiver} from "../../../interfaces/IERC1363Receiver.sol";
  8. import {IERC1363Spender} from "../../../interfaces/IERC1363Spender.sol";
  9. /**
  10. * @title ERC1363
  11. * @dev Extension of {ERC20} tokens that adds support for code execution after transfers and approvals
  12. * on recipient contracts. Calls after transfers are enabled through the {ERC1363-transferAndCall} and
  13. * {ERC1363-transferFromAndCall} methods while calls after approvals can be made with {ERC1363-approveAndCall}
  14. */
  15. abstract contract ERC1363 is ERC20, ERC165, IERC1363 {
  16. /**
  17. * @dev Indicates a failure with the token `receiver`. Used in transfers.
  18. * @param receiver Address to which tokens are being transferred.
  19. */
  20. error ERC1363InvalidReceiver(address receiver);
  21. /**
  22. * @dev Indicates a failure with the token `spender`. Used in approvals.
  23. * @param spender Address that may be allowed to operate on tokens without being their owner.
  24. */
  25. error ERC1363InvalidSpender(address spender);
  26. /**
  27. * @dev Indicates a failure within the {transfer} part of a transferAndCall operation.
  28. * @param receiver Address to which tokens are being transferred.
  29. * @param value Amount of tokens to be transferred.
  30. */
  31. error ERC1363TransferFailed(address receiver, uint256 value);
  32. /**
  33. * @dev Indicates a failure within the {transferFrom} part of a transferFromAndCall operation.
  34. * @param sender Address from which to send tokens.
  35. * @param receiver Address to which tokens are being transferred.
  36. * @param value Amount of tokens to be transferred.
  37. */
  38. error ERC1363TransferFromFailed(address sender, address receiver, uint256 value);
  39. /**
  40. * @dev Indicates a failure within the {approve} part of a approveAndCall operation.
  41. * @param spender Address which will spend the funds.
  42. * @param value Amount of tokens to be spent.
  43. */
  44. error ERC1363ApproveFailed(address spender, uint256 value);
  45. /**
  46. * @inheritdoc IERC165
  47. */
  48. function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
  49. return interfaceId == type(IERC1363).interfaceId || super.supportsInterface(interfaceId);
  50. }
  51. /**
  52. * @dev Moves a `value` amount of tokens from the caller's account to `to`
  53. * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
  54. *
  55. * Requirements:
  56. *
  57. * - The target has code (i.e. is a contract).
  58. * - The target `to` must implement the {IERC1363Receiver} interface.
  59. * - The target must return the {IERC1363Receiver-onTransferReceived} selector to accept the transfer.
  60. * - The internal {transfer} must succeed (returned `true`).
  61. */
  62. function transferAndCall(address to, uint256 value) public returns (bool) {
  63. return transferAndCall(to, value, "");
  64. }
  65. /**
  66. * @dev Variant of {transferAndCall} that accepts an additional `data` parameter with
  67. * no specified format.
  68. */
  69. function transferAndCall(address to, uint256 value, bytes memory data) public virtual returns (bool) {
  70. if (!transfer(to, value)) {
  71. revert ERC1363TransferFailed(to, value);
  72. }
  73. _checkOnTransferReceived(_msgSender(), to, value, data);
  74. return true;
  75. }
  76. /**
  77. * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
  78. * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
  79. *
  80. * Requirements:
  81. *
  82. * - The target has code (i.e. is a contract).
  83. * - The target `to` must implement the {IERC1363Receiver} interface.
  84. * - The target must return the {IERC1363Receiver-onTransferReceived} selector to accept the transfer.
  85. * - The internal {transferFrom} must succeed (returned `true`).
  86. */
  87. function transferFromAndCall(address from, address to, uint256 value) public returns (bool) {
  88. return transferFromAndCall(from, to, value, "");
  89. }
  90. /**
  91. * @dev Variant of {transferFromAndCall} that accepts an additional `data` parameter with
  92. * no specified format.
  93. */
  94. function transferFromAndCall(
  95. address from,
  96. address to,
  97. uint256 value,
  98. bytes memory data
  99. ) public virtual returns (bool) {
  100. if (!transferFrom(from, to, value)) {
  101. revert ERC1363TransferFromFailed(from, to, value);
  102. }
  103. _checkOnTransferReceived(from, to, value, data);
  104. return true;
  105. }
  106. /**
  107. * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
  108. * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
  109. *
  110. * Requirements:
  111. *
  112. * - The target has code (i.e. is a contract).
  113. * - The target `spender` must implement the {IERC1363Spender} interface.
  114. * - The target must return the {IERC1363Spender-onApprovalReceived} selector to accept the approval.
  115. * - The internal {approve} must succeed (returned `true`).
  116. */
  117. function approveAndCall(address spender, uint256 value) public returns (bool) {
  118. return approveAndCall(spender, value, "");
  119. }
  120. /**
  121. * @dev Variant of {approveAndCall} that accepts an additional `data` parameter with
  122. * no specified format.
  123. */
  124. function approveAndCall(address spender, uint256 value, bytes memory data) public virtual returns (bool) {
  125. if (!approve(spender, value)) {
  126. revert ERC1363ApproveFailed(spender, value);
  127. }
  128. _checkOnApprovalReceived(spender, value, data);
  129. return true;
  130. }
  131. /**
  132. * @dev Performs a call to {IERC1363Receiver-onTransferReceived} on a target address.
  133. *
  134. * Requirements:
  135. *
  136. * - The target has code (i.e. is a contract).
  137. * - The target `to` must implement the {IERC1363Receiver} interface.
  138. * - The target must return the {IERC1363Receiver-onTransferReceived} selector to accept the transfer.
  139. */
  140. function _checkOnTransferReceived(address from, address to, uint256 value, bytes memory data) private {
  141. if (to.code.length == 0) {
  142. revert ERC1363InvalidReceiver(to);
  143. }
  144. try IERC1363Receiver(to).onTransferReceived(_msgSender(), from, value, data) returns (bytes4 retval) {
  145. if (retval != IERC1363Receiver.onTransferReceived.selector) {
  146. revert ERC1363InvalidReceiver(to);
  147. }
  148. } catch (bytes memory reason) {
  149. if (reason.length == 0) {
  150. revert ERC1363InvalidReceiver(to);
  151. } else {
  152. /// @solidity memory-safe-assembly
  153. assembly {
  154. revert(add(32, reason), mload(reason))
  155. }
  156. }
  157. }
  158. }
  159. /**
  160. * @dev Performs a call to {IERC1363Spender-onApprovalReceived} on a target address.
  161. *
  162. * Requirements:
  163. *
  164. * - The target has code (i.e. is a contract).
  165. * - The target `spender` must implement the {IERC1363Spender} interface.
  166. * - The target must return the {IERC1363Spender-onApprovalReceived} selector to accept the approval.
  167. */
  168. function _checkOnApprovalReceived(address spender, uint256 value, bytes memory data) private {
  169. if (spender.code.length == 0) {
  170. revert ERC1363InvalidSpender(spender);
  171. }
  172. try IERC1363Spender(spender).onApprovalReceived(_msgSender(), value, data) returns (bytes4 retval) {
  173. if (retval != IERC1363Spender.onApprovalReceived.selector) {
  174. revert ERC1363InvalidSpender(spender);
  175. }
  176. } catch (bytes memory reason) {
  177. if (reason.length == 0) {
  178. revert ERC1363InvalidSpender(spender);
  179. } else {
  180. /// @solidity memory-safe-assembly
  181. assembly {
  182. revert(add(32, reason), mload(reason))
  183. }
  184. }
  185. }
  186. }
  187. }