GSNRecipientERC20Fee.sol 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.0;
  3. import "./GSNRecipient.sol";
  4. import "../access/Ownable.sol";
  5. import "../token/ERC20/SafeERC20.sol";
  6. import "../token/ERC20/ERC20.sol";
  7. /**
  8. * @dev A xref:ROOT:gsn-strategies.adoc#gsn-strategies[GSN strategy] that charges transaction fees in a special purpose ERC20
  9. * token, which we refer to as the gas payment token. The amount charged is exactly the amount of Ether charged to the
  10. * recipient. This means that the token is essentially pegged to the value of Ether.
  11. *
  12. * The distribution strategy of the gas payment token to users is not defined by this contract. It's a mintable token
  13. * whose only minter is the recipient, so the strategy must be implemented in a derived contract, making use of the
  14. * internal {_mint} function.
  15. */
  16. contract GSNRecipientERC20Fee is GSNRecipient {
  17. using SafeERC20 for __unstable__ERC20Owned;
  18. enum GSNRecipientERC20FeeErrorCodes {
  19. INSUFFICIENT_BALANCE
  20. }
  21. __unstable__ERC20Owned private _token;
  22. /**
  23. * @dev The arguments to the constructor are the details that the gas payment token will have: `name` and `symbol`. `decimals` is hard-coded to 18.
  24. */
  25. constructor(string memory name, string memory symbol) {
  26. _token = new __unstable__ERC20Owned(name, symbol);
  27. }
  28. /**
  29. * @dev Returns the gas payment token.
  30. */
  31. function token() public view virtual returns (__unstable__ERC20Owned) {
  32. return _token;
  33. }
  34. /**
  35. * @dev Internal function that mints the gas payment token. Derived contracts should expose this function in their public API, with proper access control mechanisms.
  36. */
  37. function _mint(address account, uint256 amount) internal virtual {
  38. token().mint(account, amount);
  39. }
  40. /**
  41. * @dev Ensures that only users with enough gas payment token balance can have transactions relayed through the GSN.
  42. */
  43. function acceptRelayedCall(
  44. address,
  45. address from,
  46. bytes memory,
  47. uint256 transactionFee,
  48. uint256 gasPrice,
  49. uint256,
  50. uint256,
  51. bytes memory,
  52. uint256 maxPossibleCharge
  53. )
  54. public
  55. view
  56. virtual
  57. override
  58. returns (uint256, bytes memory)
  59. {
  60. if (token().balanceOf(from) < maxPossibleCharge) {
  61. return _rejectRelayedCall(uint256(GSNRecipientERC20FeeErrorCodes.INSUFFICIENT_BALANCE));
  62. }
  63. return _approveRelayedCall(abi.encode(from, maxPossibleCharge, transactionFee, gasPrice));
  64. }
  65. /**
  66. * @dev Implements the precharge to the user. The maximum possible charge (depending on gas limit, gas price, and
  67. * fee) will be deducted from the user balance of gas payment token. Note that this is an overestimation of the
  68. * actual charge, necessary because we cannot predict how much gas the execution will actually need. The remainder
  69. * is returned to the user in {_postRelayedCall}.
  70. */
  71. function _preRelayedCall(bytes memory context) internal virtual override returns (bytes32) {
  72. (address from, uint256 maxPossibleCharge) = abi.decode(context, (address, uint256));
  73. // The maximum token charge is pre-charged from the user
  74. token().safeTransferFrom(from, address(this), maxPossibleCharge);
  75. return 0;
  76. }
  77. /**
  78. * @dev Returns to the user the extra amount that was previously charged, once the actual execution cost is known.
  79. */
  80. function _postRelayedCall(bytes memory context, bool, uint256 actualCharge, bytes32) internal virtual override {
  81. (address from, uint256 maxPossibleCharge, uint256 transactionFee, uint256 gasPrice) =
  82. abi.decode(context, (address, uint256, uint256, uint256));
  83. // actualCharge is an _estimated_ charge, which assumes postRelayedCall will use all available gas.
  84. // This implementation's gas cost can be roughly estimated as 10k gas, for the two SSTORE operations in an
  85. // ERC20 transfer.
  86. uint256 overestimation = _computeCharge(_POST_RELAYED_CALL_MAX_GAS - 10000, gasPrice, transactionFee);
  87. actualCharge = actualCharge - overestimation;
  88. // After the relayed call has been executed and the actual charge estimated, the excess pre-charge is returned
  89. token().safeTransfer(from, maxPossibleCharge - actualCharge);
  90. }
  91. }
  92. /**
  93. * @title __unstable__ERC20Owned
  94. * @dev An ERC20 token owned by another contract, which has minting permissions and can use transferFrom to receive
  95. * anyone's tokens. This contract is an internal helper for GSNRecipientERC20Fee, and should not be used
  96. * outside of this context.
  97. */
  98. // solhint-disable-next-line contract-name-camelcase
  99. contract __unstable__ERC20Owned is ERC20, Ownable {
  100. uint256 private constant _UINT256_MAX = 2**256 - 1;
  101. constructor(string memory name, string memory symbol) ERC20(name, symbol) { }
  102. // The owner (GSNRecipientERC20Fee) can mint tokens
  103. function mint(address account, uint256 amount) public virtual onlyOwner {
  104. _mint(account, amount);
  105. }
  106. // The owner has 'infinite' allowance for all token holders
  107. function allowance(address tokenOwner, address spender) public view virtual override returns (uint256) {
  108. if (spender == owner()) {
  109. return _UINT256_MAX;
  110. } else {
  111. return super.allowance(tokenOwner, spender);
  112. }
  113. }
  114. // Allowance for the owner cannot be changed (it is always 'infinite')
  115. function _approve(address tokenOwner, address spender, uint256 value) internal virtual override {
  116. if (spender == owner()) {
  117. return;
  118. } else {
  119. super._approve(tokenOwner, spender, value);
  120. }
  121. }
  122. function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
  123. if (recipient == owner()) {
  124. _transfer(sender, recipient, amount);
  125. return true;
  126. } else {
  127. return super.transferFrom(sender, recipient, amount);
  128. }
  129. }
  130. }