ERC1363.sol 7.9 KB

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