Skip to content

Commit 93b1afb

Browse files
author
Leonid Tyurin
authored
Update GSN interface (#628)
1 parent 7579b52 commit 93b1afb

File tree

9 files changed

+1242
-489
lines changed

9 files changed

+1242
-489
lines changed

contracts/gsn/BasePaymaster.sol

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ pragma experimental ABIEncoderV2;
44

55
import "../upgradeable_contracts/Ownable.sol";
66

7-
import "./interfaces/GsnTypes.sol";
87
import "./interfaces/IPaymaster.sol";
98
import "./interfaces/IRelayHub.sol";
109
import "./utils/GsnEip712Library.sol";
@@ -18,7 +17,7 @@ import "./forwarder/IForwarder.sol";
1817
*/
1918
contract BasePaymaster is IPaymaster, Ownable {
2019
IRelayHub internal relayHub;
21-
IForwarder public trustedForwarder;
20+
address private _trustedForwarder;
2221

2322
function getHubAddr() public view returns (address) {
2423
return address(relayHub);
@@ -27,45 +26,63 @@ contract BasePaymaster is IPaymaster, Ownable {
2726
//overhead of forwarder verify+signature, plus hub overhead.
2827
uint256 public constant FORWARDER_HUB_OVERHEAD = 50000;
2928

30-
//These parameters are documented in IPaymaster.GasLimits
29+
//These parameters are documented in IPaymaster.GasAndDataLimits
3130
uint256 public constant PRE_RELAYED_CALL_GAS_LIMIT = 100000;
3231
uint256 public constant POST_RELAYED_CALL_GAS_LIMIT = 110000;
3332
uint256 public constant PAYMASTER_ACCEPTANCE_BUDGET = PRE_RELAYED_CALL_GAS_LIMIT + FORWARDER_HUB_OVERHEAD;
33+
uint256 public constant CALLDATA_SIZE_LIMIT = 10500;
3434

35-
function getGasLimits() external view returns (IPaymaster.GasLimits) {
35+
function getGasAndDataLimits() external view returns (IPaymaster.GasAndDataLimits limits) {
3636
return
37-
IPaymaster.GasLimits(PAYMASTER_ACCEPTANCE_BUDGET, PRE_RELAYED_CALL_GAS_LIMIT, POST_RELAYED_CALL_GAS_LIMIT);
37+
IPaymaster.GasAndDataLimits(
38+
PAYMASTER_ACCEPTANCE_BUDGET,
39+
PRE_RELAYED_CALL_GAS_LIMIT,
40+
POST_RELAYED_CALL_GAS_LIMIT,
41+
CALLDATA_SIZE_LIMIT
42+
);
3843
}
3944

4045
// this method must be called from preRelayedCall to validate that the forwarder
4146
// is approved by the paymaster as well as by the recipient contract.
4247
function _verifyForwarder(GsnTypes.RelayRequest relayRequest) public view {
43-
require(address(trustedForwarder) == relayRequest.relayData.forwarder, "Forwarder is not trusted");
48+
require(address(_trustedForwarder) == relayRequest.relayData.forwarder, "Forwarder is not trusted");
4449
GsnEip712Library.verifyForwarderTrusted(relayRequest);
4550
}
4651

4752
/*
4853
* modifier to be used by recipients as access control protection for preRelayedCall & postRelayedCall
4954
*/
5055
modifier relayHubOnly() {
51-
require(msg.sender == getHubAddr(), "Function can only be called by RelayHub");
56+
require(msg.sender == getHubAddr(), "can only be called by RelayHub");
5257
_;
5358
}
5459

5560
function setRelayHub(IRelayHub hub) public onlyOwner {
5661
relayHub = hub;
5762
}
5863

59-
function setTrustedForwarder(IForwarder forwarder) public onlyOwner {
60-
trustedForwarder = forwarder;
64+
function setTrustedForwarder(address forwarder) public onlyOwner {
65+
_trustedForwarder = forwarder;
6166
}
6267

63-
// check current deposit on relay hub.
64-
function getRelayHubDeposit() public view returns (uint256) {
68+
function trustedForwarder() external view returns (address) {
69+
return _trustedForwarder;
70+
}
71+
72+
/// check current deposit on relay hub.
73+
function getRelayHubDeposit() external view returns (uint256) {
6574
return relayHub.balanceOf(address(this));
6675
}
6776

68-
// withdraw deposit from relayHub
77+
// any eth moved into the paymaster is transferred as a deposit.
78+
// This way, we don't need to understand the RelayHub API in order to replenish
79+
// the paymaster.
80+
function() external payable {
81+
require(address(relayHub) != address(0), "relay hub address not set");
82+
relayHub.depositFor.value(msg.value)(address(this));
83+
}
84+
85+
/// withdraw deposit from relayHub
6986
function withdrawRelayHubDepositTo(uint256 amount, address target) public onlyOwner {
7087
relayHub.withdraw(amount, target);
7188
}

contracts/gsn/forwarder/IForwarder.sol

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,20 @@ contract IForwarder {
1010
uint256 gas;
1111
uint256 nonce;
1212
bytes data;
13+
uint256 validUntil;
1314
}
1415

16+
event DomainRegistered(bytes32 indexed domainSeparator, bytes domainValue);
17+
18+
event RequestTypeRegistered(bytes32 indexed typeHash, string typeStr);
19+
1520
function getNonce(address from) external view returns (uint256);
1621

1722
/**
1823
* verify the transaction would execute.
1924
* validate the signature and the nonce of the request.
2025
* revert if either signature or nonce are incorrect.
26+
* also revert if domainSeparator or requestTypeHash are not registered.
2127
*/
2228
function verify(
2329
ForwardRequest forwardRequest,
@@ -51,8 +57,8 @@ contract IForwarder {
5157
/**
5258
* Register a new Request typehash.
5359
* @param typeName - the name of the request type.
54-
* @param typeSuffix - anything after the generic params can be empty string (if no extra fields are needed)
55-
* if it does contain a value, then a comma is added first.
60+
* @param typeSuffix - any extra data after the generic params.
61+
* (must add at least one param. The generic ForwardRequest type is always registered by the constructor)
5662
*/
5763
function registerRequestType(string typeName, string typeSuffix) external;
5864

contracts/gsn/interfaces/GsnTypes.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@ pragma solidity 0.4.24;
44
import "../forwarder/IForwarder.sol";
55

66
contract GsnTypes {
7+
/// @notice gasPrice, pctRelayFee and baseRelayFee must be validated inside of the paymaster's preRelayedCall in order not to overpay
78
struct RelayData {
89
uint256 gasPrice;
910
uint256 pctRelayFee;
1011
uint256 baseRelayFee;
1112
address relayWorker;
1213
address paymaster;
14+
address forwarder;
1315
bytes paymasterData;
1416
uint256 clientId;
15-
address forwarder;
1617
}
1718

1819
//note: must start with the ForwardRequest to be an extension of the generic forwarder

contracts/gsn/interfaces/IPaymaster.sol

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,19 @@ contract IPaymaster {
2929
* note that an OOG will revert the transaction, but the paymaster already committed to pay,
3030
* so the relay will get compensated, at the expense of the paymaster
3131
*/
32-
struct GasLimits {
32+
struct GasAndDataLimits {
3333
uint256 acceptanceBudget;
3434
uint256 preRelayedCallGasLimit;
3535
uint256 postRelayedCallGasLimit;
36+
uint256 calldataSizeLimit;
3637
}
3738

3839
/**
39-
* Return the GasLimits constants used by the Paymaster.
40+
* Return the Gas Limits and msg.data max size constants used by the Paymaster.
4041
*/
41-
function getGasLimits() external view returns (GasLimits memory limits);
42+
function getGasAndDataLimits() external view returns (GasAndDataLimits memory limits);
43+
44+
function trustedForwarder() external view returns (address);
4245

4346
/**
4447
* return the relayHub of this contract.
@@ -49,7 +52,7 @@ contract IPaymaster {
4952
* Can be used to determine if the contract can pay for incoming calls before making any.
5053
* @return the paymaster's deposit in the RelayHub.
5154
*/
52-
function getRelayHubDeposit() public view returns (uint256);
55+
function getRelayHubDeposit() external view returns (uint256);
5356

5457
/**
5558
* Called by Relay (and RelayHub), to validate if the paymaster agrees to pay for this call.
@@ -74,7 +77,7 @@ contract IPaymaster {
7477
* Note that in most cases the paymaster shouldn't try use it at all. It is always checked
7578
* by the forwarder immediately after preRelayedCall returns.
7679
* @param approvalData - extra dapp-specific data (e.g. signature from trusted party)
77-
* @param maxPossibleGas - based on values returned from {@link getGasLimits},
80+
* @param maxPossibleGas - based on values returned from {@link getGasAndDataLimits},
7881
* the RelayHub will calculate the maximum possible amount of gas the user may be charged for.
7982
* In order to convert this value to wei, the Paymaster has to call "relayHub.calculateCharge()"
8083
* return:

contracts/gsn/token_paymaster/TokenPaymaster.sol

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,25 @@ import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
66
import "../BasePaymaster.sol";
77
import "./IUniswapV2Router02.sol";
88
import "../../upgradeable_contracts/GSNForeignERC20Bridge.sol";
9+
import "../../upgradeable_contracts/Claimable.sol";
910

10-
contract TokenPaymaster is BasePaymaster {
11-
address private token;
11+
contract TokenPaymaster is BasePaymaster, Claimable {
12+
ERC20 private token;
1213
IUniswapV2Router02 private router;
1314
address private bridge;
1415

1516
address[] private tokenWethPair = new address[](2);
1617
uint256 public postGasUsage = 300000;
18+
// Default value from BasePaymaster, may be changed later
19+
// if we need to increase number of signatures for bridge contract
20+
uint256 public calldataSizeLimit = 10500;
1721

1822
constructor(address _relayHub, address _forwarder, address _token, address _router, address _bridge) public {
1923
_setOwner(msg.sender);
20-
relayHub = IRelayHub(_relayHub);
21-
trustedForwarder = IForwarder(_forwarder);
24+
setRelayHub(IRelayHub(_relayHub));
25+
setTrustedForwarder(_forwarder);
2226

23-
token = _token;
27+
token = ERC20(_token);
2428
router = IUniswapV2Router02(_router);
2529
bridge = _bridge;
2630

@@ -29,7 +33,7 @@ contract TokenPaymaster is BasePaymaster {
2933
}
3034

3135
function setToken(address t) external onlyOwner {
32-
token = t;
36+
token = ERC20(t);
3337
}
3438

3539
function setRouter(IUniswapV2Router02 r) external onlyOwner {
@@ -40,33 +44,33 @@ contract TokenPaymaster is BasePaymaster {
4044
bridge = b;
4145
}
4246

43-
function versionPaymaster() external view returns (string memory) {
44-
return "2.0.0+opengsn.tokengsn.ipaymaster";
47+
function setPostGasUsage(uint256 gasUsage) external onlyOwner {
48+
postGasUsage = gasUsage;
4549
}
4650

47-
function() external payable {
48-
require(address(relayHub) != address(0), "relay hub address not set");
49-
relayHub.depositFor.value(msg.value)(address(this));
51+
function setCalldataSizeLimit(uint256 sizeLimit) external onlyOwner {
52+
calldataSizeLimit = sizeLimit;
53+
}
54+
55+
function versionPaymaster() external view returns (string memory) {
56+
return "2.2.0+opengsn.bridgetokengsn.ipaymaster";
5057
}
5158

5259
function deposit() external payable {
5360
require(address(relayHub) != address(0), "relay hub address not set");
5461
relayHub.depositFor.value(msg.value)(address(this));
5562
}
5663

57-
function getGasLimits() external view returns (IPaymaster.GasLimits memory limits) {
64+
function getGasAndDataLimits() external view returns (IPaymaster.GasAndDataLimits memory limits) {
5865
return
59-
IPaymaster.GasLimits(
66+
IPaymaster.GasAndDataLimits(
6067
PAYMASTER_ACCEPTANCE_BUDGET,
6168
PRE_RELAYED_CALL_GAS_LIMIT,
62-
postGasUsage // maximum postRelayedCall gasLimit
69+
postGasUsage, // maximum postRelayedCall gasLimit
70+
calldataSizeLimit
6371
);
6472
}
6573

66-
function erc20() internal view returns (ERC20) {
67-
return ERC20(token);
68-
}
69-
7074
function readBytes32(bytes memory b, uint256 index) internal pure returns (bytes32 res) {
7175
require(b.length >= index + 32, "data too short");
7276
assembly {
@@ -79,7 +83,7 @@ contract TokenPaymaster is BasePaymaster {
7983
bytes signature,
8084
bytes approvalData,
8185
uint256 maxPossibleGas
82-
) public returns (bytes memory context, bool revertOnRecipientRevert) {
86+
) public relayHubOnly returns (bytes memory context, bool revertOnRecipientRevert) {
8387
(signature, approvalData);
8488
_verifyForwarder(relayRequest);
8589
bytes memory reqData = relayRequest.request.data;
@@ -108,12 +112,9 @@ contract TokenPaymaster is BasePaymaster {
108112
return a < b ? a : b;
109113
}
110114

111-
function setPostGasUsage(uint256 gasUsage) external onlyOwner {
112-
postGasUsage = gasUsage;
113-
}
114-
115115
function postRelayedCall(bytes context, bool success, uint256 gasUseWithoutPost, GsnTypes.RelayData relayData)
116116
public
117+
relayHubOnly
117118
{
118119
(success);
119120
// Extract data from context
@@ -137,7 +138,7 @@ contract TokenPaymaster is BasePaymaster {
137138
uint256 chargeWei = relayHub.calculateCharge(min(gasUseWithoutPost + postGasUsage, maxPossibleGas), relayData);
138139

139140
// Uniswap
140-
require(erc20().approve(address(router), maxTokensFee), "approve failed");
141+
require(token.approve(address(router), maxTokensFee), "approve failed");
141142
// NOTE: Received eth automatically converts to relayhub deposit
142143
uint256 spentTokens = router.swapTokensForExactETH(
143144
chargeWei,
@@ -149,7 +150,11 @@ contract TokenPaymaster is BasePaymaster {
149150

150151
// Send rest of tokens to user
151152
if (spentTokens < maxTokensFee) {
152-
require(erc20().transfer(to, maxTokensFee - spentTokens));
153+
require(token.transfer(to, maxTokensFee - spentTokens));
153154
}
154155
}
156+
157+
function claimTokens(address _token, address _to) external onlyOwner {
158+
claimValues(_token, _to);
159+
}
155160
}

contracts/upgradeable_contracts/GSNForeignERC20Bridge.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ contract GSNForeignERC20Bridge is BasicForeignBridge, ERC20Bridge, BaseRelayReci
3636
* as a commission
3737
*/
3838
function executeSignaturesGSN(bytes message, bytes signatures, uint256 maxTokensFee) external {
39-
require(msg.sender == addressStorage[TRUSTED_FORWARDER], "invalid forwarder");
39+
// Allow only forwarder calls
40+
require(isTrustedForwarder(msg.sender), "invalid forwarder");
4041
Message.hasEnoughValidSignatures(message, signatures, validatorContract(), false);
4142

4243
address recipient;

0 commit comments

Comments
 (0)