pragma solidity ^0.5.0; import "./IRelayRecipient.sol"; import "./IRelayHub.sol"; import "./Context.sol"; import "./bouncers/GSNBouncerBase.sol"; /** * @dev Base GSN recipient contract: includes the {IRelayRecipient} interface and enables GSN support on all contracts * in the inheritance tree. * * Not all interface methods are implemented (e.g. {acceptRelayedCall}, derived contracts must provide one themselves. */ contract GSNRecipient is IRelayRecipient, Context, GSNBouncerBase { // Default RelayHub address, deployed on mainnet and all testnets at the same address address private _relayHub = 0xD216153c06E857cD7f72665E0aF1d7D82172F494; /** * @dev Emitted when a contract changes its {IRelayHub} contract to a new one. */ event RelayHubChanged(address indexed oldRelayHub, address indexed newRelayHub); /** * @dev Returns the address of the {IRelayHub} contract for this recipient. */ function getHubAddr() public view returns (address) { return _relayHub; } /** * @dev Switches to a new {IRelayHub} instance. This method is added for future-proofing: there's no reason to not * use the default instance. * * IMPORTANT: After upgrading, the {GSNRecipient} will no longer be able to receive relayed calls from the old * {IRelayHub} instance. Additionally, all funds should be previously withdrawn via {_withdrawDeposits}. */ function _upgradeRelayHub(address newRelayHub) internal { address currentRelayHub = _relayHub; require(newRelayHub != address(0), "GSNRecipient: new RelayHub is the zero address"); require(newRelayHub != currentRelayHub, "GSNRecipient: new RelayHub is the current one"); emit RelayHubChanged(currentRelayHub, newRelayHub); _relayHub = newRelayHub; } /** * @dev Returns the version string of the {IRelayHub} for which this recipient implementation was built. If * {_upgradeRelayHub} is used, the new {IRelayHub} instance should be compatible with this version. */ // This function is view for future-proofing, it may require reading from // storage in the future. function relayHubVersion() public view returns (string memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return "1.0.0"; } /** * @dev Withdraws the recipient's deposits in `RelayHub`. * * Derived contracts should expose this in an external interface with proper access control. */ function _withdrawDeposits(uint256 amount, address payable payee) internal { IRelayHub(_relayHub).withdraw(amount, payee); } // Overrides for Context's functions: when called from RelayHub, sender and // data require some pre-processing: the actual sender is stored at the end // of the call data, which in turns means it needs to be removed from it // when handling said data. /** * @dev Replacement for msg.sender. Returns the actual sender of a transaction: msg.sender for regular transactions, * and the end-user for GSN relayed calls (where msg.sender is actually `RelayHub`). * * IMPORTANT: Contracts derived from {GSNRecipient} should never use `msg.sender`, and use {_msgSender} instead. */ function _msgSender() internal view returns (address payable) { if (msg.sender != _relayHub) { return msg.sender; } else { return _getRelayedCallSender(); } } /** * @dev Replacement for msg.data. Returns the actual calldata of a transaction: msg.data for regular transactions, * and a reduced version for GSN relayed calls (where msg.data contains additional information). * * IMPORTANT: Contracts derived from {GSNRecipient} should never use `msg.data`, and use {_msgData} instead. */ function _msgData() internal view returns (bytes memory) { if (msg.sender != _relayHub) { return msg.data; } else { return _getRelayedCallData(); } } function _getRelayedCallSender() private pure returns (address payable result) { // We need to read 20 bytes (an address) located at array index msg.data.length - 20. In memory, the array // is prefixed with a 32-byte length value, so we first add 32 to get the memory read index. However, doing // so would leave the address in the upper 20 bytes of the 32-byte word, which is inconvenient and would // require bit shifting. We therefore subtract 12 from the read index so the address lands on the lower 20 // bytes. This can always be done due to the 32-byte prefix. // The final memory read index is msg.data.length - 20 + 32 - 12 = msg.data.length. Using inline assembly is the // easiest/most-efficient way to perform this operation. // These fields are not accessible from assembly bytes memory array = msg.data; uint256 index = msg.data.length; // solhint-disable-next-line no-inline-assembly assembly { // Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those. result := and(mload(add(array, index)), 0xffffffffffffffffffffffffffffffffffffffff) } return result; } function _getRelayedCallData() private pure returns (bytes memory) { // RelayHub appends the sender address at the end of the calldata, so in order to retrieve the actual msg.data, // we must strip the last 20 bytes (length of an address type) from it. uint256 actualDataLength = msg.data.length - 20; bytes memory actualData = new bytes(actualDataLength); for (uint256 i = 0; i < actualDataLength; ++i) { actualData[i] = msg.data[i]; } return actualData; } }