GSNRecipient.sol 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity >=0.6.0 <0.8.0;
  3. import "../utils/Context.sol";
  4. import "./IRelayRecipient.sol";
  5. import "./IRelayHub.sol";
  6. /**
  7. * @dev Base GSN recipient contract: includes the {IRelayRecipient} interface
  8. * and enables GSN support on all contracts in the inheritance tree.
  9. *
  10. * TIP: This contract is abstract. The functions {IRelayRecipient-acceptRelayedCall},
  11. * {_preRelayedCall}, and {_postRelayedCall} are not implemented and must be
  12. * provided by derived contracts. See the
  13. * xref:ROOT:gsn-strategies.adoc#gsn-strategies[GSN strategies] for more
  14. * information on how to use the pre-built {GSNRecipientSignature} and
  15. * {GSNRecipientERC20Fee}, or how to write your own.
  16. */
  17. abstract contract GSNRecipient is IRelayRecipient, Context {
  18. // Default RelayHub address, deployed on mainnet and all testnets at the same address
  19. address private _relayHub = 0xD216153c06E857cD7f72665E0aF1d7D82172F494;
  20. uint256 constant private _RELAYED_CALL_ACCEPTED = 0;
  21. uint256 constant private _RELAYED_CALL_REJECTED = 11;
  22. // How much gas is forwarded to postRelayedCall
  23. uint256 constant internal _POST_RELAYED_CALL_MAX_GAS = 100000;
  24. /**
  25. * @dev Emitted when a contract changes its {IRelayHub} contract to a new one.
  26. */
  27. event RelayHubChanged(address indexed oldRelayHub, address indexed newRelayHub);
  28. /**
  29. * @dev Returns the address of the {IRelayHub} contract for this recipient.
  30. */
  31. function getHubAddr() public view virtual override returns (address) {
  32. return _relayHub;
  33. }
  34. /**
  35. * @dev Switches to a new {IRelayHub} instance. This method is added for future-proofing: there's no reason to not
  36. * use the default instance.
  37. *
  38. * IMPORTANT: After upgrading, the {GSNRecipient} will no longer be able to receive relayed calls from the old
  39. * {IRelayHub} instance. Additionally, all funds should be previously withdrawn via {_withdrawDeposits}.
  40. */
  41. function _upgradeRelayHub(address newRelayHub) internal virtual {
  42. address currentRelayHub = _relayHub;
  43. require(newRelayHub != address(0), "GSNRecipient: new RelayHub is the zero address");
  44. require(newRelayHub != currentRelayHub, "GSNRecipient: new RelayHub is the current one");
  45. emit RelayHubChanged(currentRelayHub, newRelayHub);
  46. _relayHub = newRelayHub;
  47. }
  48. /**
  49. * @dev Returns the version string of the {IRelayHub} for which this recipient implementation was built. If
  50. * {_upgradeRelayHub} is used, the new {IRelayHub} instance should be compatible with this version.
  51. */
  52. // This function is view for future-proofing, it may require reading from
  53. // storage in the future.
  54. function relayHubVersion() public view virtual returns (string memory) {
  55. this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
  56. return "1.0.0";
  57. }
  58. /**
  59. * @dev Withdraws the recipient's deposits in `RelayHub`.
  60. *
  61. * Derived contracts should expose this in an external interface with proper access control.
  62. */
  63. function _withdrawDeposits(uint256 amount, address payable payee) internal virtual {
  64. IRelayHub(getHubAddr()).withdraw(amount, payee);
  65. }
  66. // Overrides for Context's functions: when called from RelayHub, sender and
  67. // data require some pre-processing: the actual sender is stored at the end
  68. // of the call data, which in turns means it needs to be removed from it
  69. // when handling said data.
  70. /**
  71. * @dev Replacement for msg.sender. Returns the actual sender of a transaction: msg.sender for regular transactions,
  72. * and the end-user for GSN relayed calls (where msg.sender is actually `RelayHub`).
  73. *
  74. * IMPORTANT: Contracts derived from {GSNRecipient} should never use `msg.sender`, and use {_msgSender} instead.
  75. */
  76. function _msgSender() internal view virtual override returns (address payable) {
  77. if (msg.sender != getHubAddr()) {
  78. return msg.sender;
  79. } else {
  80. return _getRelayedCallSender();
  81. }
  82. }
  83. /**
  84. * @dev Replacement for msg.data. Returns the actual calldata of a transaction: msg.data for regular transactions,
  85. * and a reduced version for GSN relayed calls (where msg.data contains additional information).
  86. *
  87. * IMPORTANT: Contracts derived from {GSNRecipient} should never use `msg.data`, and use {_msgData} instead.
  88. */
  89. function _msgData() internal view virtual override returns (bytes memory) {
  90. if (msg.sender != getHubAddr()) {
  91. return msg.data;
  92. } else {
  93. return _getRelayedCallData();
  94. }
  95. }
  96. // Base implementations for pre and post relayedCall: only RelayHub can invoke them, and data is forwarded to the
  97. // internal hook.
  98. /**
  99. * @dev See `IRelayRecipient.preRelayedCall`.
  100. *
  101. * This function should not be overridden directly, use `_preRelayedCall` instead.
  102. *
  103. * * Requirements:
  104. *
  105. * - the caller must be the `RelayHub` contract.
  106. */
  107. function preRelayedCall(bytes memory context) public virtual override returns (bytes32) {
  108. require(msg.sender == getHubAddr(), "GSNRecipient: caller is not RelayHub");
  109. return _preRelayedCall(context);
  110. }
  111. /**
  112. * @dev See `IRelayRecipient.preRelayedCall`.
  113. *
  114. * Called by `GSNRecipient.preRelayedCall`, which asserts the caller is the `RelayHub` contract. Derived contracts
  115. * must implement this function with any relayed-call preprocessing they may wish to do.
  116. *
  117. */
  118. function _preRelayedCall(bytes memory context) internal virtual returns (bytes32);
  119. /**
  120. * @dev See `IRelayRecipient.postRelayedCall`.
  121. *
  122. * This function should not be overridden directly, use `_postRelayedCall` instead.
  123. *
  124. * * Requirements:
  125. *
  126. * - the caller must be the `RelayHub` contract.
  127. */
  128. function postRelayedCall(bytes memory context, bool success, uint256 actualCharge, bytes32 preRetVal) public virtual override {
  129. require(msg.sender == getHubAddr(), "GSNRecipient: caller is not RelayHub");
  130. _postRelayedCall(context, success, actualCharge, preRetVal);
  131. }
  132. /**
  133. * @dev See `IRelayRecipient.postRelayedCall`.
  134. *
  135. * Called by `GSNRecipient.postRelayedCall`, which asserts the caller is the `RelayHub` contract. Derived contracts
  136. * must implement this function with any relayed-call postprocessing they may wish to do.
  137. *
  138. */
  139. function _postRelayedCall(bytes memory context, bool success, uint256 actualCharge, bytes32 preRetVal) internal virtual;
  140. /**
  141. * @dev Return this in acceptRelayedCall to proceed with the execution of a relayed call. Note that this contract
  142. * will be charged a fee by RelayHub
  143. */
  144. function _approveRelayedCall() internal pure virtual returns (uint256, bytes memory) {
  145. return _approveRelayedCall("");
  146. }
  147. /**
  148. * @dev See `GSNRecipient._approveRelayedCall`.
  149. *
  150. * This overload forwards `context` to _preRelayedCall and _postRelayedCall.
  151. */
  152. function _approveRelayedCall(bytes memory context) internal pure virtual returns (uint256, bytes memory) {
  153. return (_RELAYED_CALL_ACCEPTED, context);
  154. }
  155. /**
  156. * @dev Return this in acceptRelayedCall to impede execution of a relayed call. No fees will be charged.
  157. */
  158. function _rejectRelayedCall(uint256 errorCode) internal pure virtual returns (uint256, bytes memory) {
  159. return (_RELAYED_CALL_REJECTED + errorCode, "");
  160. }
  161. /*
  162. * @dev Calculates how much RelayHub will charge a recipient for using `gas` at a `gasPrice`, given a relayer's
  163. * `serviceFee`.
  164. */
  165. function _computeCharge(uint256 gas, uint256 gasPrice, uint256 serviceFee) internal pure virtual returns (uint256) {
  166. // The fee is expressed as a percentage. E.g. a value of 40 stands for a 40% fee, so the recipient will be
  167. // charged for 1.4 times the spent amount.
  168. return (gas * gasPrice * (100 + serviceFee)) / 100;
  169. }
  170. function _getRelayedCallSender() private pure returns (address payable result) {
  171. // We need to read 20 bytes (an address) located at array index msg.data.length - 20. In memory, the array
  172. // is prefixed with a 32-byte length value, so we first add 32 to get the memory read index. However, doing
  173. // so would leave the address in the upper 20 bytes of the 32-byte word, which is inconvenient and would
  174. // require bit shifting. We therefore subtract 12 from the read index so the address lands on the lower 20
  175. // bytes. This can always be done due to the 32-byte prefix.
  176. // The final memory read index is msg.data.length - 20 + 32 - 12 = msg.data.length. Using inline assembly is the
  177. // easiest/most-efficient way to perform this operation.
  178. // These fields are not accessible from assembly
  179. bytes memory array = msg.data;
  180. uint256 index = msg.data.length;
  181. // solhint-disable-next-line no-inline-assembly
  182. assembly {
  183. // Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
  184. result := and(mload(add(array, index)), 0xffffffffffffffffffffffffffffffffffffffff)
  185. }
  186. return result;
  187. }
  188. function _getRelayedCallData() private pure returns (bytes memory) {
  189. // RelayHub appends the sender address at the end of the calldata, so in order to retrieve the actual msg.data,
  190. // we must strip the last 20 bytes (length of an address type) from it.
  191. uint256 actualDataLength = msg.data.length - 20;
  192. bytes memory actualData = new bytes(actualDataLength);
  193. for (uint256 i = 0; i < actualDataLength; ++i) {
  194. actualData[i] = msg.data[i];
  195. }
  196. return actualData;
  197. }
  198. }