GSNRecipient.sol 9.6 KB

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